29

これは、Excel で記述された別のアプリケーションを制御する、Python で記述された信頼性の低いアプリケーションの最近の実行からのスタック トレースの一部です。

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

明らかに何かがおかしくなっています...しかし、何が?[1] これらの COM エラー コードは、非常にわかりにくいようです。

このエラー メッセージを解読するにはどうすればよいですか? この数値エラー コードをより意味のあるものに変換できるテーブルはどこかにありますか?

[1] 実際、このケースで何が問題だったのかはわかっています。Name プロパティを持たない Range オブジェクトの Name プロパティにアクセスしようとしていたのです... すべてのバグがこれほど簡単に見つかるわけではありません!

4

5 に答える 5

43

あなたは何も悪いことをしていません。スタックトレースの最初の項目(番号)は、COMオブジェクトによって返されるエラーコードです。2番目の項目は、エラーコードに関連付けられた説明です。この場合は「例外が発生しました」です。pywintypes.com_errorは、すでにwin32api.FormatMessage(errCode)に相当するものを呼び出しています。2番目の数字をすぐに見ていきます。

ちなみに、Visual Studio(C:\ Program Files \ Microsoft Visual Studio 9.0 \ Common7 \ Tools \ ErrLook.exe)にある「エラールックアップ」ユーティリティをクイック起動パッドとして使用して、COMエラーコードを確認できます。このユーティリティは、FormatMessageも呼び出して、結果を表示します。すべてのエラーコードがこのメカニズムで機能するわけではありませんが、多くのエラーコードが機能します。それが通常私の最初の目的地です。

COMでのエラー処理とレポートは少し面倒です。私はあなたにいくつかの背景を与えることを試みます。

すべてのCOMメソッド呼び出しは、成功または失敗を示すことができるHRESULTと呼ばれる数値コードを返します。COMのすべての形式のエラー報告は、その上に構築されます。

コードは通常16進数で表されますが、スタックトレースのように、大きな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の正式な名前を把握できますが、有用なものを見つけるために16進バージョンを使用する必要がある場合もあります。

DISP_で始まるエラーは、IDISPATCHエラーコードです。エラーは大まかに「オブジェクトによってスローされたCOM例外がありました」を意味し、より多くの情報が他の場所にパックされています(ただし、どこにあるかはよくわかりません。調べる必要があります)。

pywintypes.com_errorについて私が理解していることから、メッセージの最後の数字は、例外中にオブジェクトによって返された実際のエラーコードです。これは、VBAから取得する実際の数値コードですErr.Number

残念ながら、その2番目のコード-2146788248(0x800A9C68)は、カスタムアプリケーション定義のエラーメッセージ(VBA :)用に予約された範囲内にあるVbObjectError + someCustomErrorNumberため、一元化された意味はありません。同じ数は、プログラムごとにまったく異なることを意味する場合があります。

この場合、行き止まりに達しました。

エラーコードは「カスタム」であり、Excelが文書化していないことを除いて、アプリケーションはそれが何であるかを文書化する必要があります。また、Excel(またはエラーの実際の原因)は、IErrorInfoを介してこれ以上の情報を提供していないようです。

Excelは、自動化による不可解なエラーコードと、それらを引き起こすあいまいな状況で(少なくとも私には)悪名高いです。これは特に、「設計時エラー」(「オブジェクトに存在しないメソッドを呼び出すよりもよく知っているはずです」)と見なすことができるエラーの場合に当てはまります。素敵な「Nameプロパティを読み取れませんでした」の代わりに、「ランタイムエラー '1004':アプリケーション定義またはオブジェクト定義エラー」(VBAから範囲のNameプロパティにアクセスしようとしたときに発生しました)が表示されます。 Excelで)。それはあまり役に立ちません。

問題はPythonまたはExcelへのインターフェイスではルーティングされません。Excel自体は、VBAに対してさえ、何が起こったのかを説明していません。

ただし、上記の一般的な手順は引き続き有効です。将来Excelからエラーが発生した場合は、同じ方法で追跡できるより適切なエラーメッセージが表示される可能性があります。

幸運を!

于 2009-02-10T05:01:04.257 に答える
11

次のようにします。

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

pythoncom.com_error オブジェクトのダイジェストに関する詳細情報: https://web.archive.org/web/20170831073447/http://docs.activestate.com/activepython/3.2/pywin32/com_error.html

于 2011-03-16T14:49:34.277 に答える
7

特に pythoncom の場合、結果として生じるエラー コードは不可解なものではありません。これは、正しい表現が 32 ビットの符号なし整数であるのに、pythoncom が内部的に 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

したがって、すべてをまとめると、基本的に常に pythoncom からの結果に対して fix_com_hresult() を実行する必要があります。

通常、例外をチェックするときにこれを行う必要があるため、次の関数を作成しました。

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

すべての HRESULT を一覧表示している MSDN ドキュメントを見つけることができませんでしたが、これを見つけました: http://www.megos.ch/support/doserrors_e.txt

また、それを持っているので、拡張エラー コード (-2146788248) に対しても fix_com_hresult() を実行する必要がありますが、Euro Micelli が言ったように、この特定のインスタンスでは役に立ちません :)

于 2012-05-17T18:15:44.177 に答える
7

はい、win32api モジュールを試してください:

import win32api
e_msg = win32api.FormatMessage(-2147352567)

例外から返されたコードを取得して、FormatMessage に渡すことができます。あなたの例には2つのエラーコードがありました。

于 2009-02-06T19:31:24.393 に答える
1

Exceptionstrerrorの属性についてはまだ誰も言及していません。これは、エラー コードの結果を返します。だから、このように自分でやる代わりにpywintypes.com_errorFormatMessage

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:(

于 2015-03-17T14:09:05.487 に答える