windows 有没有办法在 pywin32 中解码数字 COM 错误代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/521759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way to decode numerical COM error-codes in pywin32
提问by Salim Fadhley
Here is part of a stack-trace from a recent run of an unreliable application written in Python which controls another application written in Excel:
这是最近运行一个用 Python 编写的不可靠应用程序的堆栈跟踪的一部分,该应用程序控制另一个用 Excel 编写的应用程序:
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
Obviously something has gone wrong ... but what?[1] These COM error codes seem to be excessively cryptic.
显然出了点问题……但是什么?[1] 这些 COM 错误代码似乎过于神秘。
How can I decode this error message? Is there a table somewhere that allows me to convert this numerical error code into something more meaningful?
如何解码此错误消息?是否有表格可以让我将此数字错误代码转换为更有意义的内容?
[1] I actually know what went wrong in this case, it was attempting to access a Name prperty on a Range object which did not have a Name property... not all bugs are this easy to find!
[1] 我实际上知道在这种情况下出了什么问题,它试图访问没有 Name 属性的 Range 对象上的 Name 属性……并非所有错误都这么容易找到!
回答by Euro Micelli
You are not doing anything wrong. The first item in your stack trace (the number) is the error code returned by the COM object. The second item is the description associated with the error code which in this case is "Exception Occurred". pywintypes.com_error already called the equivalent of win32api.FormatMessage(errCode) for you. We'll look at the second number in a minute.
你没有做错任何事。堆栈跟踪中的第一项(数字)是 COM 对象返回的错误代码。第二项是与错误代码相关的描述,在这种情况下是“发生异常”。pywintypes.com_error 已经为你调用了 win32api.FormatMessage(errCode) 的等价物。我们将在一分钟内查看第二个数字。
By the way, you can use the "Error Lookup" utility that comes in Visual Studio (C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\ErrLook.exe) as a quick launching pad to check COM error codes. That utility also calls FormatMessage for you and displays the result. Not all error codes will work with this mechanism, but many will. That's usually my first stop.
顺便说一下,您可以使用 Visual Studio (C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\ErrLook.exe) 中的“错误查找”实用程序作为检查 COM 错误代码的快速启动板。该实用程序还会为您调用 FormatMessage 并显示结果。并非所有的错误代码都适用于这种机制,但很多都适用。那通常是我的第一站。
Error handling and reporting in COM is a bit messy. I'll try to give you some background.
COM 中的错误处理和报告有点混乱。我会试着给你一些背景。
All COM method calls will return a numeric code called an HRESULT that can indicate success or failure. All forms of error reporting in COM build on top of that.
所有 COM 方法调用都将返回一个称为 HRESULT 的数字代码,可以指示成功或失败。COM 中所有形式的错误报告都建立在此之上。
The codes are commonly expressed in hex, although sometimes you will see them as large 32-bit numbers, like in your stack trace. There are all kinds of predefined return codes for common results and problems, or the object can return custom numeric codes for special situations. For example, the value 0 (called S_OK) universally means "No error" and 0x80000002 is E_OUTOFMEMORY. Sometimes the HRESULT codes are returned by the object, sometimes by the COM infrastructure.
这些代码通常以十六进制表示,但有时您会看到它们是大的 32 位数字,就像在堆栈跟踪中一样。对于常见的结果和问题,有各种预定义的返回代码,或者对象可以为特殊情况返回自定义数字代码。例如,值 0(称为 S_OK)普遍表示“无错误”,而 0x80000002 是 E_OUTOFMEMORY。有时 HRESULT 代码由对象返回,有时由 COM 基础结构返回。
A COM object can also choose to provide much richer error information by implementing an interface called IErrorInfo. When an object implements IErrorInfo, it can provide all kinds of detail about what happened, such as a detailed custom error message and even the name of a help file that describes the problem. In VB6 and VBA. the Err
object allows you to access all that information (Err.Description
, etc).
COM 对象还可以通过实现名为 IErrorInfo 的接口来选择提供更丰富的错误信息。当一个对象实现 IErrorInfo 时,它可以提供有关所发生事件的各种详细信息,例如详细的自定义错误消息,甚至是描述问题的帮助文件的名称。在 VB6 和 VBA 中。该Err
对象允许您访问所有这些信息(Err.Description
等)。
To complicate matters, late bound COM objects (which use a mechanism called COM Automation or IDispatch) add some layers that need to be peeled off to get information out. Excel is usually manipulated via late binding.
更复杂的是,后期绑定的 COM 对象(使用称为 COM 自动化或 IDispatch 的机制)添加了一些需要剥离以获取信息的层。Excel 通常通过后期绑定进行操作。
Now let's look at your situation again. What you are getting as the first number is a fairly generic error code: DISP_E_EXCEPTION. Note: you can usually figure out the official name of an HRESULT by googling the number, although sometimes you will have to use the hex version to find anything useful.
现在让我们再看看你的情况。你得到的第一个数字是一个相当通用的错误代码:DISP_E_EXCEPTION。注意:您通常可以通过谷歌搜索数字来找出 HRESULT 的正式名称,尽管有时您必须使用十六进制版本才能找到任何有用的信息。
Errors that begin with DISP_ are IDISPATCH error codes. The error loosely means "There was a COM exception thrown by the object", with more information packed elsewhere (although I don't quite know where; I'll have to look it up).
以 DISP_ 开头的错误是 IDISPATCH 错误代码。该错误大致意味着“对象抛出了 COM 异常”,其他地方包含更多信息(尽管我不太清楚在哪里;我必须查找)。
From what I understand of pywintypes.com_error, the last number in your message is the actual error code that was returned by the object during the exception. It's the actual numeric code that you would get out of VBA's Err.Number
.
根据我对 pywintypes.com_error 的理解,消息中的最后一个数字是对象在异常期间返回的实际错误代码。这是您从 VBA 中获得的实际数字代码Err.Number
。
Unfortunately, that second code -2146788248 (0x800A9C68) is in the range reserved for custom application-defined error messages (in VBA: VbObjectError + someCustomErrorNumber
), so there is no centralized meaning. The same number can mean entirely different things for different programs.
不幸的是,第二个代码 -2146788248 (0x800A9C68) 在为自定义应用程序定义的错误消息保留的范围内(在 VBA: 中VbObjectError + someCustomErrorNumber
),因此没有集中的含义。对于不同的程序,相同的数字可能意味着完全不同的事情。
In this case, we have reached a dead end:
在这种情况下,我们已经走到了死胡同:
The error code is "custom", and the application needs to document what it is, except that Excel doesn't. Also, Excel (or the actual source of the error) doesn't seem to be providing any more information via IErrorInfo.
错误代码是“自定义”,应用程序需要记录它是什么,但 Excel 没有。此外,Excel(或错误的实际来源)似乎没有通过 IErrorInfo 提供更多信息。
Excel is notorious (to me at least) for cryptic error codes from automation and obscure situations that cause them. This is especially so for errors that one could consider "design-time errors" ("you should have known better than calling a method that doesn't exist in the object"). Instead of a nice "Could not read the Name property", you get "Run-time error '1004': Application defined or object-defined error" (which I just got by trying to access a Name property on a Range, from VBA in Excel). That is NOT very helpful.
Excel 因来自自动化的神秘错误代码和导致它们的模糊情况而臭名昭著(至少对我而言)。对于可以考虑“设计时错误”(“您应该比调用对象中不存在的方法更清楚”)的错误尤其如此。你得到的不是一个很好的“无法读取 Name 属性”,而是“运行时错误‘1004’:应用程序定义或对象定义的错误”(我只是通过尝试访问范围上的 Name 属性而得到的,来自 VBA在 Excel 中)。这不是很有帮助。
The problem is not routed on Python or it's interface to Excel. Excel itself doesn't explain what happened, even to VBA.
问题不是在 Python 或它的 Excel 接口上路由的。Excel 本身并没有解释发生了什么,即使是 VBA。
However, the general procedure above remains valid. If you get an error from Excel in the future, you might get a better error message that you can track the same way.
但是,上述一般程序仍然有效。如果以后您从 Excel 中收到错误消息,您可能会收到一条更好的错误消息,您可以通过相同的方式进行跟踪。
Good luck!
祝你好运!
回答by shellster
Do it like this:
像这样做:
try:
[whatever code]
except pythoncom.com_error as error:
print(win32api.FormatMessage(error.excepinfo[5]))
More information on digesting the pythoncom.com_error object here: http://docs.activestate.com/activepython/3.2/pywin32/com_error.html
有关在此处消化 pythoncom.com_error 对象的更多信息:http://docs.activestate.com/activepython/3.2/pywin32/com_error.html
回答by Jason Coon
Yes try the win32api module:
是的,试试 win32api 模块:
import win32api
e_msg = win32api.FormatMessage(-2147352567)
You can grab any codes returned from the exception and pass them to FormatMessage. Your example had 2 error codes.
您可以获取从异常返回的任何代码并将它们传递给 FormatMessage。您的示例有 2 个错误代码。
回答by EB.
Specifically for pythoncom, the errors codes that result are more than cryptic. This is because pythoncom represents them internally as a 32bit signed integer, when the correct representation is a 32bit unsignedinteger. As a result, the conversion that you end up seeing in the stack trace is incorrect.
特别是对于 pythoncom,产生的错误代码不仅仅是神秘的。这是因为当正确的表示是 32 位无符号整数时,pythoncom 在内部将它们表示为 32 位有符号整数。因此,您最终在堆栈跟踪中看到的转换是不正确的。
In particular, your exception, according to pythoncom, is -2147352567, and your (for lack of a better word) Err.Number is -2146788248.
特别是,根据pythoncom,您的异常是-2147352567,而您的(由于缺少更好的词)Err.Number 是-2146788248。
This however causes some issues when watching for specific errors, like below:
然而,这在观察特定错误时会导致一些问题,如下所示:
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
To see why this has issues, lets look into these error codes:
要了解为什么会出现问题,让我们查看以下错误代码:
>>> DISP_E_EXCEPTION = 0x80020009
>>> DISP_E_EXCEPTION
2147614729L
>>> my_hr = -2147352567
>>> my_hr == DISP_E_EXCEPTION
False
Again, this is because python sees the constant declared as positive, and pythoncom's incorrect declaration interpreted it as negative. Of course, the most obvious solution fails:
同样,这是因为 python 将常量声明为正数,而 pythoncom 的错误声明将其解释为负数。当然,最明显的解决方案失败了:
>>> hex(my_hr)
'-0x7ffdfff7'
The solution is to properly interpret the number. Luckily, pythoncom's representation is reversible. We need to interpret the negative number as a 32 bit signed integer, then interpret thatas an unsigned integer:
解决方案是正确解释数字。幸运的是,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
So, putting it all together, you need to run fix_com_hresult() on that result from pythoncom, essentially all the time.
所以,把它们放在一起,你需要在 pythoncom 的结果上运行 fix_com_hresult(),基本上一直。
Since normally you need to do this when checking for exceptions, I created these functions:
由于通常在检查异常时需要执行此操作,因此我创建了以下函数:
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]
which can then be used how you expect:
然后可以按照您的期望使用它:
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
I was unable to find a MSDN document listing all HRESULTs, but I found this: http://www.megos.ch/support/doserrors_e.txt
我找不到列出所有 HRESULT 的 MSDN 文档,但我找到了这个:http: //www.megos.ch/support/doserrors_e.txt
Also, since you have it, fix_com_hresult() should also be run on your extended error code (-2146788248), but as Euro Micelli said, it doesn't help you in this particular instance :)
此外,既然你有它, fix_com_hresult() 也应该在你的扩展错误代码 (-2146788248) 上运行,但正如 Euro Micelli 所说,它在这个特殊情况下对你没有帮助:)
回答by Day
No-one has yet mentioned the strerror
attribute of the pywintypes.com_error
Exception. This returns the result of FormatMessage
for the error code. So instead of doing it yourself like this
还没有人提到Exception的strerror
属性。这将返回错误代码的结果。所以不要像这样自己做pywintypes.com_error
FormatMessage
try:
[whatever code]
except pythoncom.com_error as error:
print(win32api.FormatMessage(error.excepinfo[5]))
You can just do this:
你可以这样做:
try:
[whatever code]
except pythoncom.com_error as error:
print(error.strerror)
Note it will return None
if you have a non-standard HRESULT
:(
请注意,None
如果您有非标准,它将返回HRESULT
:(