Python向COM组件方法传递字符串引用时类型不兼容问题
OCX控件EcrCmd方法调用参数类型不兼容问题
方法定义(VS C#)
该OCX中的EcrCmd方法在C#中的定义如下:
[DispId(17)] [MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] int EcrCmd([MarshalAs(UnmanagedType.BStr)] string Command, [MarshalAs(UnmanagedType.BStr)] ref string pResult);
可以看到第二个参数pResult是引用传递的BStr类型字符串。
我的Python代码
self.frame = wx.Frame(parent=None, id=wx.ID_ANY,size=(500,500), title='Python Interface to COECRCOM') self.gd = wx.lib.activex.ActiveXCtrl(self.frame, "COECRCOM.CoEcrComCtrl.1") status = self.gd.ctrl.Status print(status) error = "" cmd = self.gd.ctrl.EcrCmd("nofis apri", error) print(cmd) print(error)
访问self.gd.ctrl.Status正常,但调用EcrCmd时触发类型不兼容错误。
报错信息
Traceback (most recent call last): File "...lib\site-packages\comtypes\automation.py", line 855, in Invoke byref(result), byref(excepinfo), byref(argerr)) _ctypes.COMError: (-2147352571, 'Type incompatibility.', (None, None, None, 0, None)) During handling of the above exception, another exception occurred: Traceback (most recent call last): File main.py", line 31, in <module> app = MainApp() File "main.py", line 20, in __init__ cmd = self.gd.ctrl.EcrCmd("nofis apri", error) File "...lib\site-packages\comtypes\_memberspec.py", line 448, in func return obj.Invoke(memid, _invkind=1, *args, **kw) # DISPATCH_METHOD File "...lib\site-packages\comtypes\automation.py", line 878, in Invoke args)) _ctypes.COMError: (-2147352571, 'Type incompatibility.', ('TypeError: Parameter 1', ('nofis apri', '')))
环境信息
- 系统:32位Windows
- Python版本:3.7.13
- comtypes版本:v1.2.1
- wxPython版本:4.0.4
解决方案
问题出在第二个参数的传递方式:C#中的ref string要求传递可修改的引用类型,而Python原生字符串是不可变类型,无法满足COM组件的参数要求。需要改用comtypes提供的BSTR类型并通过引用传递:
- 导入
comtypes相关类型:
import comtypes from comtypes.automation import BSTR
- 修改调用代码:
# 初始化BSTR对象 error = BSTR("") # 传递BSTR的引用给方法 cmd = self.gd.ctrl.EcrCmd("nofis apri", comtypes.byref(error)) print(cmd) # 通过value属性获取返回的字符串结果 print(error.value)
也可以使用ctypes的c_wchar_p类型实现(但BSTR更适配COM字符串标准):
import ctypes error = ctypes.c_wchar_p("") cmd = self.gd.ctrl.EcrCmd("nofis apri", ctypes.byref(error)) print(cmd) print(error.value)
核心逻辑是:COM组件需要能修改传入的字符串参数,必须用COM兼容的可变字符串类型并以引用方式传递,才能匹配ref string的参数要求。
内容的提问来源于stack exchange,提问作者Antonino Bonanno
相关产品推荐
相关产品推荐

