此失敗的主要原因是a kludge in comtypes,其中DECIMAL
類型未正確定義。因爲它需要64位或8個字節的雙精度浮點數,但實際需要16個字節或128個位,因此實際需要的值爲struct
。
對於當前的目的,你可以使用的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)
然而,你可能會難倒因爲便攜式設備API中的某些方法不適合自動化。
例如,IPortableDeviceManager::GetDevices
具有unique
attribute(在實際的PortableDeviceApi.idl文件中,不在文檔中),這意味着您實際上可以通過NULL
。但是,type libraries don't capture this information。
相同的參數實際上可以是一個大小由下一個參數決定的數組。同樣,類型庫不支持這個,只有單對象頂級指針。此外,實際的IDL沒有size_is
attribute,這意味着方法調用不會在公寓間工作,或者此接口具有自定義封送拆分器。
快速查看便攜式設備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()
我如果不能進一步清除comtypes,就無法提供更多的幫助。我建議你聯繫它的作者或維護者。
編輯:同時,我在0123F在SourceForge站點。由於該項目正在從SourceForge轉換而來,似乎已被忘記,but it wasn't(here too)。
你從那以後試過導入模塊嗎?