source

pywin32에서 숫자 COM 오류 코드를 디코딩하는 방법이 있습니까?

manysource 2023. 4. 20. 21:36

pywin32에서 숫자 COM 오류 코드를 디코딩하는 방법이 있습니까?

다음은 Excel로 작성된 다른 애플리케이션을 제어하는 Python으로 작성된 신뢰할 수 없는 애플리케이션의 최근 실행에서 발생한 스택 추적의 일부입니다.

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

분명히 뭔가 잘못 된 것 같은데... 그런데?[1] 이러한 COM 에러 코드는, 지극히 기밀성이 높은 것 같습니다.

이 에러 메시지를 디코딩하려면 어떻게 해야 하나요?이 에러 코드를 보다 의미 있는 것으로 변환할 수 있는 표가 있습니까?

[1] 실제로 이 경우 무엇이 잘못되었는지 알고 있습니다.Name 속성이 없는 Range 객체의 Name prperty에 액세스하려고 했습니다.모든 버그가 이렇게 쉽게 찾을 수 있는 것은 아닙니다!

당신은 잘못한 게 없어요.스택 트레이스의 첫 번째 항목(번호)은 COM 오브젝트에 의해 반환되는 에러 코드입니다.두 번째 항목은 오류 코드와 관련된 설명입니다. 이 경우 "예외 발생"입니다.pywintypes.com_error는 이미 win32api와 동등한 값을 호출했습니다.FormatMessage(errCode)를 선택합니다.잠시 후에 두 번째 숫자를 보겠습니다.

참고로 Visual Studio (C:\Program Files\Microsoft Visual Studio 9.0)에 있는 "Error Lookup" 유틸리티를 사용할 수 있습니다.\공통7\Tools\ErrLook.exe)를 사용하여 COM 오류 코드를 확인합니다.또한 이 유틸리티는 Format Message를 호출하여 결과를 표시합니다.이 메커니즘에서는 모든 에러 코드가 동작하는 것은 아니지만, 많은 에러 코드가 동작합니다.보통 그곳이 제 첫 번째 방문지입니다.

COM에서의 에러 처리와 리포트는, 조금 복잡합니다.제가 배경 설명을 해드릴게요.

모든 COM 메서드콜은 성공 또는 실패를 나타내는 HRESULT라는 수치 코드를 반환합니다.그 위에 COM의 모든 형식의 에러 리포트가 구축되어 있습니다.

코드는 일반적으로 16진수로 표현되지만 스택트레이스처럼 큰 32비트 수치로 표시되는 경우가 있습니다.일반적인 결과와 문제에 대한 모든 종류의 미리 정의된 반환 코드가 있거나 개체가 특수한 상황에 대한 사용자 지정 숫자 코드를 반환할 수 있습니다.예를 들어 값 0(S_OK)은 일반적으로 "No error"를 의미하며 0x800002는 E_OUTOF MEMORY를 의미합니다.HRESULT 코드가 오브젝트에 의해 반환되는 경우도 있고 COM 인프라스트럭처에 의해 반환되는 경우도 있습니다.

또한 IE 오류 정보를 구현하여 IER 오류 정보를 구현함으로써 훨씬 부유한 오류 정보를 제공할 수 있습니다.COM 오브젝트는 IErrorInfo 라고 하는 인터페이스를 실장함으로써 보다 풍부한 에러 정보를 제공할 수도 있습니다.객체 구현예: IER 오류 정보를 제공할 때 세부 사용자 정의 오류 메시지와 같은 모든 유형의 세부 정보를 제공할 수 있습니다.오브젝트가 IErrorInfo를 구현하면 상세 커스텀에러 메시지, 문제를 설명하는 도움말파일 이름 등 발생한 모든 종류의 상세 정보를 제공할 수 있습니다.VB6 및 VBA에 있습니다.VB6 v VBA the 서)Err개체에 액세스할 수 있는 모든 정보를 액세스할 수 있습니다. 보 세 습 스 니 object 있를 allows(다 thatation수액사 to inform all (모정 you할에용하든면object accessErr.Description, 등)

설상가상으로 레이트바운드의 COM 오브젝트(COM Automation 또는 IDispatch라고 불리는 메커니즘을 사용)는 정보를 얻기 위해 제거해야 하는 레이어를 추가합니다.Excel은 보통 레이트바인딩을 통해 조작됩니다.

이제 당신의 상황을 다시 한 번 살펴봅시다.첫 번째 번호로 표시되는 것은 매우 일반적인 에러 코드입니다.DISP_E_EXCEPTION.주의: 보통 번호를 검색하면 HRESULT의 정식 이름을 알 수 있습니다.단, 도움이 되는 것을 찾기 위해 16진수 버전을 사용해야 하는 경우도 있습니다.

DISP_로 시작하는 오류는 IDISPATCH 오류 코드입니다.이 오류는 대략 "개체에 의해 던져진 COM 예외가 있었다"는 의미이며, 자세한 정보는 다른 곳에 보관되어 있습니다(어디서 찾아봐야 합니다).

pywintypes.com_error에 대해 알고 있는 바로는 메시지의 마지막 숫자는 예외 중에 객체에 의해 반환된 실제 오류 코드입니다.VBA에서 Err.Number.

두 코드 프로그램 메시지용으로 경우: -2146788248(0x800A9C68).VbObjectError + someCustomErrorNumber집중화된 의미는 없습니다.같은 숫자는 프로그램에 따라 전혀 다른 의미를 가질 수 있습니다.

이 경우 우리는 막다른 골목에 다다랐습니다.

에러 코드는 「custom」이며, Excel에서는 기록되지 않는 것을 제외하고, 애플리케이션은 그 에러를 기록할 필요가 있습니다.또한 Excel(또는 실제 오류 발생원)은 IErrorInfo를 통해 더 이상의 정보를 제공하지 않는 것으로 보입니다.

Excel은 자동화 및 불분명한 상황으로 인한 암호 오류 코드로 악명이 높다.이는 특히 "디자인 타임 오류"를 고려할 수 있는 오류(개체에 존재하지 않는 메서드를 호출하는 것보다 더 잘 알고 있어야 합니다)."이름 속성을 읽을 수 없습니다" 대신 "런타임 오류 '1004'가 표시됩니다. 응용 프로그램 정의 오류 또는 개체 정의 오류" (Excel의 VBA에서 범위 내의 Name 속성에 액세스하려고 시도하여 얻은 오류입니다.)그것은 별로 도움이 되지 않는다.

Python 또는 Excel 인터페이스에서는 문제가 발생하지 않습니다.Excel 자체는 VBA에 무슨 일이 일어났는지 설명하지 않습니다.

다만, 상기의 일반적인 순서는 유효합니다.나중에 Excel에서 오류가 발생하면 동일한 방법으로 추적할 수 있다는 더 나은 오류 메시지가 나타날 수 있습니다.

행운을 빕니다.

다음과 같이 합니다.

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 를 참조하십시오.

예, win32api 모듈을 사용해 보십시오.

import win32api
e_msg = win32api.FormatMessage(-2147352567)

예외에서 반환된 코드를 가져와 Format Message에 전달할 수 있습니다.이 예에는 2개의 에러 코드가 있습니다.

특히 pythoncom의 경우 발생하는 에러 코드는 암호화 이상입니다.이는 pythoncom이 이들을 내부적으로 32비트 부호 있는 정수로 나타내기 때문입니다.정확한 표현은 32비트 부호 없는 정수입니다.그 결과 스택트레이스에 표시되는 변환은 올바르지 않습니다.

특히 pythoncom에 따르면, 당신의 예외는 -2147352567이며, 당신의 (더 좋은 단어가 없기 때문에) Err입니다.번호는 -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이 positive로 선언된 상수를 인식하고 pythoncom의 잘못된 선언은 이를 negative로 해석하기 때문입니다.물론 가장 명백한 솔루션은 실패합니다.

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

또한 fix_com_hresult()는 확장 에러 코드(-2146788248)에서도 실행되어야 하지만 Euro Miselli가 말한 것처럼 이 특정 인스턴스에서는 도움이 되지 않습니다.

아무도 아직 언급하지 않았다.strerror예외 속성입니다.그러면 결과가 반환됩니다.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:(

언급URL : https://stackoverflow.com/questions/521759/is-there-a-way-to-decode-numerical-com-error-codes-in-pywin32