首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用comtypes.client.GetModule()为dll文件生成python包装器时出现AssertionError

使用comtypes.client.GetModule()为dll文件生成python包装器时出现AssertionError
EN

Stack Overflow用户
提问于 2014-01-23 15:06:38
回答 1查看 430关注 0票数 1

我正在尝试为我的python应用程序使用"PortableDevice.PortableDevice“COM。当我尝试生成python包装器时,如下所示:

代码语言:javascript
复制
comtypes.client.GetModule("C:\\Windows\\system32\\PortableDeviceApi.dll")

我得到以下错误消息:

代码语言:javascript
复制
assert sizeof(__MIDL_IOleAutomationTypes_0004) == 16, sizeof(__MIDL_IOleAutomationTypes_0004)
AssertionError: 8

有没有人能帮我解决这个问题?

EN

回答 1

Stack Overflow用户

发布于 2014-02-10 23:58:33

失败的主要原因是a kludge in comtypes,其中DECIMAL类型没有正确定义。目前,双精度浮点数需要64位,即8字节,但实际的struct应该需要16字节,即128位。

对于您当前的目的,您可以接受具有适当大小的DECIMAL的任何定义,所以这里有一个:

代码语言:javascript
复制
# comtypes/automation.py
class tagDEC(Structure):
    _fields_ = [("wReserved", c_ushort),
                ("scale", c_ubyte),
                ("sign", c_ubyte),
                ("Hi32", c_ulong),
                ("Lo64", c_ulonglong)]
DECIMAL = tagDEC
代码语言:javascript
复制
# 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将变成:

代码语言:javascript
复制
# 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' )),
    # ...

下面的测试成功运行,尽管在我的例子中它返回一个空列表,因为我现在没有任何连接的设备:

代码语言:javascript
复制
# 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)。

从那时起,你有没有尝试过导入模块?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21301565

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档