我正在尝试为我的python应用程序使用"PortableDevice.PortableDevice“COM。当我尝试生成python包装器时,如下所示:
comtypes.client.GetModule("C:\\Windows\\system32\\PortableDeviceApi.dll")我得到以下错误消息:
assert sizeof(__MIDL_IOleAutomationTypes_0004) == 16, sizeof(__MIDL_IOleAutomationTypes_0004)
AssertionError: 8有没有人能帮我解决这个问题?
发布于 2014-02-10 23:58:33
失败的主要原因是a kludge in comtypes,其中DECIMAL类型没有正确定义。目前,双精度浮点数需要64位,即8字节,但实际的struct应该需要16字节,即128位。
对于您当前的目的,您可以接受具有适当大小的DECIMAL的任何定义,所以这里有一个:
# comtypes/automation.py
class tagDEC(Structure):
_fields_ = [("wReserved", c_ushort),
("scale", c_ubyte),
("sign", c_ubyte),
("Hi32", c_ulong),
("Lo64", c_ulonglong)]
DECIMAL = tagDEC# comtypes/tools/tlbparser.py
DECIMAL_type = typedesc.Structure("DECIMAL",
align=alignment(automation.DECIMAL)*8,
members=[], bases=[],
size=sizeof(automation.DECIMAL)*8)但是,您可能会发现Portable Device API中的某些方法不适合自动化。
例如,IPortableDeviceManager::GetDevices具有unique attribute (在实际的PortableDeviceApi.idl文件中,而不是在文档中),这意味着您实际上可以传递NULL。然而,type libraries don't capture this information。
这个参数实际上可以是一个数组,其大小由下一个参数决定。同样,类型库不支持这一点,只支持单对象顶级指针。此外,实际的IDL没有size_is attribute,这意味着方法调用不能跨单元工作,或者该接口具有自定义封送拆收器。
大致看一下Portable Device API就会发现,这种模式在实际使用数组的其他方法中也得到了一致的应用。看起来好像是某个熟悉Win32 API的人创建了这些方法,因为当数组参数为NULL时,有一堆Win32函数会被重载,以获取某个数组的大小。这根本不是通常的COM方式,最好有两个方法(在知道元素的数量、分配足够的内存和获取它们之间具有相同的竞争条件),一个只有out参数的方法(没有竞争条件,但不控制内存使用)或使用枚举器(例如IEnumPortableDevice,更难,但更简洁)。
无论如何,您可以将comtypes.client.GetModule("…PortableDeviceApi.dll")生成的代码作为第一步。然后,遵循these instructions,使Python方法以文档记录的方式实际调用COM方法。例如,IPortableManager::GetDevices将变成:
# comtypes/gen/_1F001332_1A57_4934_BE31_AFFC99F4EE0A_0_1_0.py
class IPortableDeviceManager(comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0.IUnknown):
# ...
def GetDevices(self):
cPnPDeviceIDs = c_ulong(0)
self.__com_GetDevices(None, byref(cPnPDeviceIDs))
PnPDeviceIDs = (WSTRING * cPnPDeviceIDs.value)()
self.__com_GetDevices(PnPDeviceIDs, byref(cPnPDeviceIDs))
deviceIDs = PnPDeviceIDs[:cPnPDeviceIDs.value]
for i in range(cPnPDeviceIDs.value):
windll.ole32.CoTaskMemFree(cast(PnPDeviceIDs, POINTER(c_void_p))[i])
return deviceIDs
# ...
IPortableDeviceManager._methods_ = [
COMMETHOD([], HRESULT, 'GetDevices',
( ['in'], POINTER(WSTRING), 'pPnPDeviceIDs' ),
( ['in'], POINTER(c_ulong), 'pcPnPDeviceIDs' )),
# ...下面的测试成功运行,尽管在我的例子中它返回一个空列表,因为我现在没有任何连接的设备:
# First run
import os
from comtypes.client import GetModule
GetModule(os.getenv("WINDIR") + "\\system32\\PortableDeviceApi.dll")
# Quit python
# Edit comtypes/gen/_1F001332_1A57_4934_BE31_AFFC99F4EE0A_0_1_0.py
# Subsequent runs
from comtypes.client import CreateObject
from comtypes.gen.PortableDeviceApiLib import *
CreateObject(PortableDeviceManager).GetDevices()如果不进一步研究comtype,我就无法提供更多的帮助。我建议您联系它的作者或维护者。
编辑:同时,我在SourceForge站点上使用created a ticket。由于这个项目是从SourceForge过渡过来的,它似乎被遗忘了,but it wasn't (here too)。
从那时起,你有没有尝试过导入模块?
https://stackoverflow.com/questions/21301565
复制相似问题