回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<h2>环境</h2>
<p>Windows10+Python3.6.3 64位(也尝试了32位)。我是一个python开发人员,尝试(几乎)第一次使用COM,并击中了这个巨大的拦截器。在</p>
<h2>问题</h2>
<p>当我试图通过<code>win32com</code>或<code>comtypes</code>使用dll中实现的IRTDServer时,我遇到了各种错误。结果发现使用<code>win32com</code>更加困难。下面两个库都包含了一个unittest示例。在</p>
<p>从Excel 2016访问服务器按预期工作;这将返回预期值:</p>
<pre><code>=RTD("foo.bar", , "STAT1", "METRIC1")
</code></pre>
<hr/>
<h2>使用win32com库的代码</h2>
<p>下面是一个简单的测试用例,它应该连接到服务器,但是没有连接到服务器(这只是一个版本,因为为了调试问题,我已经多次更改了它)</p>
^{pr2}$
<p>结果:</p>
<pre><code>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
</code></pre>
<p>按照这些指示,我成功地运行了<code>makepy</code>脚本:</p>
<pre><code>> 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
</code></pre>
<p><em>(为了隐私,我替换了stackoverflow上的UUID。此UUID与“”的typelib UUID相同美食酒吧“)</em></p>
<p>生成的文件包含<code>IRtdServer</code>和<code>IRTDUpdateEvent</code>的各种函数和类型定义。但是在这个文件中,两个接口都是<code>win32com.client.DispatchBaseClass</code>的子类,而根据OleViewDotNet,它们应该是<code>IUnknown</code>的子类?在</p>
<p>但是,当我再次尝试运行unittest时,我收到了与以前完全相同的错误。好像查找机制没有找到生成的模块?在</p>
<p>而且,<code>GetTypeInfo</code>返回{<cd10>}也在提醒我。据我所知,win32com使用该方法(属于<code>IDispatch</code>COM接口的一部分)来确定其他接口中所有其他函数的参数和返回类型,包括<code>IRtdServer</code>。如果不实现,它将无法正确确定类型。然而,生成的文件似乎包含了这些信息,这也令人费解。在</p>
<hr/>
<h2>使用comtypes库的代码</h2>
<pre><code>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()
</code></pre>
<p>结果:</p>
<pre><code> 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))
</code></pre>
<hr/>
<h2>我尝试过的其他解决方案</h2>
<p>(基于谷歌搜索和以下评论中的答案)</p>
<ul>
<li>(重新)注册了DLL</li>
<li>注册了32位版本的DLL,并尝试使用python 32位</li>
<li>将<code>python.exe</code>的兼容模式设置为Windows XP SP3</li>
<li><p>尝试不实例化IRtdServer,即替换以下两行:</p>
<pre><code>self._rtd = self._comObj.IRtdServer()
result = self._rtd.ServerStart(self)
</code></pre>
<p>有:</p>
<pre><code>result = self._comObj.ServerStart(self)
</code></pre>
<p>这次的错误是:</p>
<pre><code>TypeError: 'NoneType' object is not callable
</code></pre>
<p>这似乎表明<code>ServerStart</code>函数存在,但未定义?(看起来很奇怪。一定还有更多的秘密。)</p></li>
<li><p>尝试将<code>interface="IRtdServer"</code>参数传递给<code>CreateObject</code>:</p>
<pre><code>def __init__(self, clsid):
self._comObj = comtypes.client.CreateObject(clsid, interface="IRtdServer")
def connect(self):
result = self._comObj.ServerStart(self)
...
</code></pre>
<p>收到的错误是:</p>
<pre><code> 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_
</code></pre>
<p>跟踪<code>comtypes</code>库中的代码,这似乎表明接口参数需要接口类,而不是字符串。我发现了<code>comtypes</code>库中定义的各种接口:<code>IDispatch</code>,<code>IPersist</code>,<code>IServiceProvider</code>。它们都是<code>IUnknown</code>的子类。根据OleViewDotNet,<code>IRtdServer</code>也是<code>IUnknown</code>的一个子类。这使我相信我需要用python编写一个IRtdServer类来使用接口,但是我不知道如何去做。</p></li>
<li><p>我注意到了<code>dynamic</code>参数。代码表明这与<code>interface</code>参数互斥,因此我尝试了:</p>
<pre><code>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)
</code></pre>
<p>但是这个错误和我原来的错误是一样的:<code>IRtdServer</code>有{<cd29>}</p></li>
</ul>
<p>任何帮助或线索将不胜感激。提前谢谢你。在</p>
<hr/>
<p>(不知道我在做什么,)我试着用OleViewDotNet查看DLL:</p>
<p><a href="https://i.stack.imgur.com/UEaA4.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/UEaA4.png" alt="enter image description here"/></a></p>
<p><a href="https://i.stack.imgur.com/yOh6g.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yOh6g.png" alt="enter image description here"/></a></p>
<p><a href="https://i.stack.imgur.com/R6KpJ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/R6KpJ.png" alt="enter image description here"/></a></p>
<p><a href="https://i.stack.imgur.com/dt5xC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/dt5xC.png" alt="enter image description here"/></a></p>
<hr/>