Есть ли способ декодировать числовые коды ошибок COM в pywin32

Вот часть трассировки стека из недавнего запуска ненадежного приложения, написанного на Python, которое управляет другим приложением, написанным в Excel:

pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None) 

Очевидно, что-то пошло не так … но что? [1] Эти коды ошибок COM кажутся чрезмерно загадочными.

Как я могу декодировать это сообщение об ошибке? Есть ли где-нибудь таблица, которая позволяет мне преобразовать этот цифровой код ошибки в нечто более значимое?

[1] Я действительно знаю, что пошло не так в этом случае, оно пыталось получить доступ к имени prperty в объекте Range, у которого не было свойства Name … не все ошибки легко найти!

5 Solutions collect form web for “Есть ли способ декодировать числовые коды ошибок COM в pywin32”

Вы ничего не делаете неправильно. Первый элемент в вашей трассировке стека (номер) – это код ошибки, возвращаемый COM-объектом. Второй элемент – это описание, связанное с кодом ошибки, который в данном случае является «Исключением». pywintypes.com_error уже назвал эквивалент win32api.FormatMessage (errCode) для вас. Мы посмотрим на второй номер за минуту.

Кстати, вы можете использовать утилиту «Поиск ошибок», которая поставляется в Visual Studio (C: \ Program Files \ Microsoft Visual Studio 9.0 \ Common7 \ Tools \ ErrLook.exe) в качестве быстрой стартовой панели для проверки кодов ошибок COM. Эта утилита также вызывает FormatMessage для вас и отображает результат. Не все коды ошибок будут работать с этим механизмом, но многие будут. Обычно это моя первая остановка.

Обработка ошибок и отчетность в COM немного беспорядочны. Я постараюсь дать вам немного фона.

Все вызовы COM-метода возвращают числовой код под названием HRESULT, который может указывать на успех или неудачу. Все формы отчетов об ошибках в COM строятся поверх этого.

Коды обычно выражаются в шестнадцатеричном формате, хотя иногда вы увидите их как большие 32-битные числа, как в вашей трассе стека. Существуют все типы предопределенных кодов возврата для общих результатов и проблем, или объект может возвращать пользовательские числовые коды для особых ситуаций. Например, значение 0 (называемое S_OK) универсально означает «Нет ошибки», а 0x80000002 – E_OUTOFMEMORY. Иногда коды HRESULT возвращаются объектом, иногда с помощью инфраструктуры COM.

COM-объект также может предоставить гораздо более богатую информацию об ошибках, реализуя интерфейс IErrorInfo. Когда объект реализует IErrorInfo, он может предоставить все виды подробностей о том, что произошло, например подробное пользовательское сообщение об ошибке и даже имя файла справки, описывающего проблему. В VB6 и VBA. объект Err позволяет вам получить доступ ко всей этой информации ( Err.Description и т. д.).

Чтобы усложнить дело, поздние связанные COM-объекты (которые используют механизм, называемый COM Automation или IDispatch), добавляют некоторые слои, которые необходимо очистить, чтобы получить информацию. Обычно Excel обрабатывается посредством позднего связывания.

Теперь давайте посмотрим на вашу ситуацию снова. То, что вы получаете как первое число, является довольно общим кодом ошибки: DISP_E_EXCEPTION. Примечание. Обычно вы можете узнать официальное имя HRESULT, указав номер, хотя иногда вам нужно использовать шестнадцатеричную версию, чтобы найти что-нибудь полезное.

Ошибки, начинающиеся с DISP_, являются кодами ошибок IDISPATCH. Ошибка означает, что «было создано исключение COM, созданное объектом», с дополнительной информацией, упакованной в другое место (хотя я не совсем знаю, где я должен искать ее).

Из того, что я понимаю в pywintypes.com_error, последнее число в вашем сообщении – это фактический код ошибки, который был возвращен объектом во время исключения. Это фактический цифровой код, который вы выберете из Err.Number VBA.

К сожалению, этот второй код -2146788248 (0x800A9C68) находится в диапазоне, зарезервированном для пользовательских сообщений об ошибках приложения (в VBA: VbObjectError + someCustomErrorNumber ), поэтому нет централизованного значения. Такое же число может означать совершенно разные вещи для разных программ.

В этом случае мы зашли в тупик:

Код ошибки «custom», и приложение должно документировать, что это такое, за исключением того, что Excel этого не делает. Кроме того, Excel (или фактический источник ошибки), похоже, не предоставляет никакой дополнительной информации через IErrorInfo.

Excel известен (по крайней мере, для меня) для загадочных кодов ошибок из автоматизации и неясных ситуаций, которые вызывают их. Это особенно важно для ошибок, которые можно было бы учитывать «ошибки времени разработки» («вы должны были знать лучше, чем вызов метода, который не существует в объекте»). Вместо приятного «Не удалось прочитать свойство Name» вы получаете « Ошибка времени выполнения« 1004 »: определенная или объектная ошибка приложения (которую я только что получил, пытаясь получить доступ к свойству Name в диапазоне, от VBA в Excel). Это НЕ очень полезно.

Проблема не маршрутизируется на Python или ее интерфейс с Excel. Сам Excel не объясняет, что произошло, даже для VBA.

Однако общая процедура выше остается в силе. Если в будущем вы получите сообщение об ошибке в Excel, вы можете получить сообщение об ошибке, которое вы можете отслеживать таким же образом.

Удачи!

Делай это так:

 try: [whatever code] except pythoncom.com_error as error: print(win32api.FormatMessage(error.excepinfo[5])) 

Дополнительная информация о переваривании объекта pythoncom.com_error здесь: http://docs.activestate.com/activepython/3.2/pywin32/com_error.html

Да, попробуйте модуль win32api:

 import win32api e_msg = win32api.FormatMessage(-2147352567) 

Вы можете получить любые коды, возвращенные из исключения, и передать их в FormatMessage. В вашем примере было 2 кода ошибок.

В частности, для pythoncom коды ошибок, которые являются результатом, более чем загадочны. Это связано с тем, что pythoncom представляет их внутренне как 32-битное целое число со знаком, когда правильное представление представляет собой 32-битное целое число без знака . В результате преобразование, которое вы видите в трассировке стека, неверно.

В частности, ваше исключение, согласно pythoncom, равно -2147352567, а ваше (из-за отсутствия лучшего слова) Err.Number – -2146788248.

Однако это вызывает некоторые проблемы при просмотре определенных ошибок, например ниже:

 DISP_E_EXCEPTION = 0x80020009 #... #except pywintypes.com_error as e: # print repr(e) # #pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None) # hr = e.hresult hr = -2147352567 if hr == DISP_E_EXCEPTION: pass #This never occurs else: raise 

Чтобы понять, почему у этого есть проблемы, давайте рассмотрим эти коды ошибок:

 >>> DISP_E_EXCEPTION = 0x80020009 >>> DISP_E_EXCEPTION 2147614729L >>> my_hr = -2147352567 >>> my_hr == DISP_E_EXCEPTION False 

Опять же, это связано с тем, что python видит константу, объявленную как положительную, а неправильное объявление pythoncom интерпретирует ее как отрицательную. Конечно, наиболее очевидное решение терпит неудачу:

 >>> hex(my_hr) '-0x7ffdfff7' 

Решение должно правильно интерпретировать число. К счастью, представление pythoncom обратимо. Нам нужно интерпретировать отрицательное число как 32-битное целое число со знаком, а затем интерпретировать его как целое без знака:

 def fix_com_hresult(hr): import struct return struct.unpack("L", struct.pack("l", hr))[0] >>> DISP_E_EXCEPTION = 0x80020009 >>> my_hr = -2147352567 >>> my_hr == DISP_E_EXCEPTION False >>> fixed_hr = fix_com_hresult(my_hr) >>> fixed_hr 2147614729L >>> fixed_hr == DISP_E_EXCEPTION True 

Итак, все вместе, вам нужно запустить fix_com_hresult () для этого результата из pythoncom, по существу, все время.

Поскольку обычно вам нужно это делать, проверяя исключения, я создал следующие функции:

 def fix_com_exception(e): e.hresult = fix_com_hresult(e.hresult) e.args = [e.hresult] + list(e.args[1:]) return e def fix_com_hresult(hr): import struct return struct.unpack("L", struct.pack("l", hr))[0] 

который затем можно использовать, как вы ожидаете:

 DISP_E_EXCEPTION = 0x80020009 try: #failing call except pywintypes.com_error as e: print repr(e) #pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None) fix_com_exception(e) print repr(e) #pywintypes.com_error: (2147614729L, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None) if e.hresult == DISP_E_EXCEPTION: print "Got expected failure" else: raise 

Мне не удалось найти документ MSDN, в котором перечислены все HRESULT, но я нашел это: http://www.megos.ch/support/doserrors_e.txt

Кроме того, поскольку у вас есть это, fix_com_hresult () также должен запускаться в расширенном коде ошибки (-2146788248), но, как сказал Euro Micelli, это не поможет вам в этом конкретном случае 🙂

Никто еще не упомянул атрибут strerror исключения pywintypes.com_error . Это возвращает результат FormatMessage для кода ошибки. Поэтому вместо того, чтобы делать это самостоятельно,

 try: [whatever code] except pythoncom.com_error as error: print(win32api.FormatMessage(error.excepinfo[5])) 

Вы можете просто сделать это:

 try: [whatever code] except pythoncom.com_error as error: print(error.strerror) 

Заметьте, что он вернет None если у вас есть нестандартный HRESULT 🙁

  • Получение MAC-адреса
  • Именованные каналы между C # и Python
  • Создание установщика Windows для Python + набора зависимостей
  • рисование в python
  • Как изменить шрифт (размер / семейство) в PyScripter?
  • ошибка с функцией parse в lxml
  • Добавьте каталог в sys.path Python, чтобы он включался каждый раз, когда я использую Python
  • Установка pzmq с помощью Cygwin
  •  
    Interesting Posts for Van-Lav

    Python cStringIO занимает больше времени, чем StringIO в письменной форме (производительность строковых методов)

    Добавление столбца фрейма данных с len () значений другого столбца

    Selenium и PhantomJS Ошибка: «Не удается подключиться к GhostDriver»

    Получение ошибки db_type () при использовании django-facebook connect для DjangoApp

    Время доступа массива numpy значительно влияет на последний индекс по сравнению со вторым последним

    Настройка Content-Type в объекте Django HttpResponse для приложения Shopify

    Python: отключение относительного импорта

    превращение вывода beautifulsoup в матрицу

    Amazon Elastic MapReduce – SIGTERM

    Django ORM: выбор соответствующего набора

    Как создать простой метакласс?

    Переменная ссылочного класса при понимании другой переменной класса

    Regex, чтобы получить список всех слов со специальными буквами (unicode graphemes)

    TF * IDF для поисковых запросов

    Очень простой сервер / клиент python-dbus в том же процессе

    Python - лучший язык программирования в мире.