Windows10+Python3.6.3 64位(也尝试了32位)。我是一个python开发人员,尝试(几乎)第一次使用COM,并击中了这个巨大的拦截器。在
当我试图通过win32com
或comtypes
使用dll中实现的IRTDServer时,我遇到了各种错误。结果发现使用win32com
更加困难。下面两个库都包含了一个unittest示例。在
从Excel 2016访问服务器按预期工作;这将返回预期值:
=RTD("foo.bar", , "STAT1", "METRIC1")
下面是一个简单的测试用例,它应该连接到服务器,但是没有连接到服务器(这只是一个版本,因为为了调试问题,我已经多次更改了它)
^{pr2}$结果:
Traceback (most recent call last):
File "env\lib\site-packages\win32com\client\gencache.py", line 532, in EnsureDispatch
ti = disp._oleobj_.GetTypeInfo()
pywintypes.com_error: (-2147467263, 'Not implemented', None, None)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test\test.py", line 23, in test_win32com
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = win32com.client.CastTo(dispatch, 'IRtdServer')
File "env\lib\site-packages\win32com\client\__init__.py", line 134, in CastTo
ob = gencache.EnsureDispatch(ob)
File "env\lib\site-packages\win32com\client\gencache.py", line 543, in EnsureDispatch
raise TypeError("This COM object can not automate the makepy process - please run makepy manually for this object")
TypeError: This COM object can not automate the makepy process - please run makepy manually for this object
按照这些指示,我成功地运行了makepy
脚本:
> env\Scripts\python.exe env\lib\site-packages\win32com\client\makepy.py "foo.bar"
Generating to C:\Users\user1\AppData\Local\Temp\gen_py\3.5\longuuid1x0x1x0.py
Building definitions from type library...
Generating...
Importing module
(为了隐私,我替换了stackoverflow上的UUID。此UUID与“”的typelib UUID相同美食酒吧“)
生成的文件包含IRtdServer
和IRTDUpdateEvent
的各种函数和类型定义。但是在这个文件中,两个接口都是win32com.client.DispatchBaseClass
的子类,而根据OleViewDotNet,它们应该是IUnknown
的子类?在
但是,当我再次尝试运行unittest时,我收到了与以前完全相同的错误。好像查找机制没有找到生成的模块?在
而且,GetTypeInfo
返回{IDispatch
COM接口的一部分)来确定其他接口中所有其他函数的参数和返回类型,包括IRtdServer
。如果不实现,它将无法正确确定类型。然而,生成的文件似乎包含了这些信息,这也令人费解。在
from unittest import TestCase
class COMtest(TestCase):
def test_comtypes(self):
import comtypes.client
class RTDclient:
# are these for win32com only?
_com_interfaces_ = ["IRTDUpdateEvent"]
_public_methods_ = ["Disconnect", "UpdateNotify"]
_public_attrs_ = ["HeartbeatInterval"]
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid)
def connect(self):
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
assert result > 0
def UpdateNotify(self):
print("UpdateNotify() callback")
def Disconnect(self):
print("Disconnect() called")
HeartbeatInterval = -1
_rtd = RTDclient("foo.bar")
_rtd.connect()
结果:
File "test\test.py", line 27, in test_comtypes
_rtd.connect()
File "test\test.py", line 16, in connect
self._rtd = self._comObj.IRTDServer()
File "env\lib\site-packages\comtypes\client\dynamic.py", line 110, in __getattr__
dispid = self._comobj.GetIDsOfNames(name)[0]
File "env\lib\site-packages\comtypes\automation.py", line 708, in GetIDsOfNames
self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
_ctypes.COMError: (-2147352570, 'Unknown name.', (None, None, None, 0, None))
(基于谷歌搜索和以下评论中的答案)
python.exe
的兼容模式设置为Windows XP SP3尝试不实例化IRtdServer,即替换以下两行:
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
有:
result = self._comObj.ServerStart(self)
这次的错误是:
TypeError: 'NoneType' object is not callable
这似乎表明ServerStart
函数存在,但未定义?(看起来很奇怪。一定还有更多的秘密。)
尝试将interface="IRtdServer"
参数传递给CreateObject
:
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
def connect(self):
result = self._comObj.ServerStart(self)
...
收到的错误是:
File "test\test.py", line 13, in __init__
self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
File "env\lib\site-packages\comtypes\client\__init__.py", line 238, in CreateObject
obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
File "env\lib\site-packages\comtypes\__init__.py", line 1223, in CoCreateInstance
p = POINTER(interface)()
TypeError: Cannot create instance: has no _type_
跟踪comtypes
库中的代码,这似乎表明接口参数需要接口类,而不是字符串。我发现了comtypes
库中定义的各种接口:IDispatch
,IPersist
,IServiceProvider
。它们都是IUnknown
的子类。根据OleViewDotNet,IRtdServer
也是IUnknown
的一个子类。这使我相信我需要用python编写一个IRtdServer类来使用接口,但是我不知道如何去做。
我注意到了dynamic
参数。代码表明这与interface
参数互斥,因此我尝试了:
def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid, dynamic=True)
def connect(self):
self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
但是这个错误和我原来的错误是一样的:IRtdServer
有{
任何帮助或线索将不胜感激。提前谢谢你。在
(不知道我在做什么,)我试着用OleViewDotNet查看DLL:
似乎已经有了用于Excel 2002的服务器/客户端。
pyrtd
看看这个源代码,一旦您创建了一个分派对象,那么它似乎被强制转换到IRtdServer。
提取相关零件,如下所示。
请参考客户端.py和例子/rtdtime.py以下来源。
pyrtd - default
pyrtd/电阻式温度检测器/客户端.py
pyrtd/示例/rtdtime.py
我也遇到了同样的问题。在
我还试着用win32com让excel运行,说实话,这有点不稳定…我甚至连我的excel都摸不着。在
所以我花了一些时间来研究这个问题。问题出在卡斯托身上。认为您(和我)加载的COM对象没有包含足够的信息来进行强制转换(有些方法,如GetTypeInfo没有实现等等…)
因此,我创建了一个包装器,使那些COM对象的方法可调用…不明显。这似乎对我有用。在
客户机代码是从一个名为pyrtd的项目中修改的,该项目由于各种原因而不能工作(想想由于RTD模型的改变…RefreshData的返回现在完全不同了)。在
相关问题 更多 >
编程相关推荐