如何在C++嵌入的Python环境中传入本地创建的IDispatch COM对象并实现访问与事件处理
如何在C++嵌入的Python环境中传入本地创建的IDispatch COM对象并实现访问与事件处理
嗨,我来帮你搞定这个在C嵌入Python里传本地COM对象的问题!你之前用Dispatch的思路不对,因为win32com.client.Dispatch是用来从ProgID新建COM对象的,不是用来包装你已经在C里创建好的IDispatch指针的。下面给你一步步讲怎么改:
核心思路
咱们得把C++里的IDispatch对象直接包装成Python能识别的win32com对象,然后把它注入到Python的全局命名空间里,这样Python脚本就能直接用它,还能绑定事件处理器。
具体代码修改
首先,你得调整你的PassComObjectToPython函数,别再去调用Dispatch了,改用pythoncom提供的函数把IDispatch转换成Python对象,再放到Python的全局环境里。代码大概是这样:
#include <python.h> #include <pythoncom.h> // 必须包含这个头文件,编译时要链接pythoncom.lib和pywintypes.lib void PythonEng::PassComObjectToPython(const CString& ObjName, IDispatch* pMyComObject) { // 划重点:Py_Initialize和PyCOM_Initialize只需要初始化一次,别每次传对象都调用! static bool isPythonInitialized = false; if (!isPythonInitialized) { Py_Initialize(); PyCOM_Initialize(); // 初始化pythoncom环境,win32com全靠它 isPythonInitialized = true; } // 把C++的IDispatch对象转换成Python可识别的对象 PyObject *pPyObj = PyCom_PyObjectFromIUnknown( (IUnknown*)pMyComObject, IID_IDispatch, TRUE // 让Python自动管理这个COM对象的引用计数 ); if (pPyObj) { // 把这个Python对象注入到__main__模块的全局命名空间 PyObject *pMainModule = PyImport_AddModule("__main__"); if (pMainModule) { PyObject *pMainDict = PyModule_GetDict(pMainModule); // 用你指定的ObjName作为全局变量名,把对象放进去 PyDict_SetItemString(pMainDict, ObjName.GetString(), pPyObj); } Py_DECREF(pPyObj); // 释放引用,避免内存泄漏 } }
怎么在Python里使用这个对象
现在你在Python脚本里就可以直接用这个对象了!比如你传的ObjName是"Dialogs",那Python里直接写:
# 不用再Dispatch了,直接用全局的Dialogs对象 Dialogs.Message(0, "Hello from C++ passed object!")
事件处理的实现
如果要处理这个COM对象的事件,用win32com.client的WithEvents就行,举个例子:
import win32com.client # 定义你的事件处理器类,方法名要和COM对象的事件名对应 class DialogEventHandler: def OnMessageClicked(self, returnCode): # 这里写你处理事件的逻辑 print(f"用户点击了消息框,返回码:{returnCode}") # 把事件处理器绑定到我们从C++传过来的COM对象上 handler = DialogEventHandler() win32com.client.WithEvents(Dialogs, handler)
一些必须注意的细节
- 一定要链接
pythoncom.lib和pywintypes.lib,不然编译会报错,这两个库在你的Python安装目录的libs文件夹里 - 绝对不要多次调用Py_Initialize和PyCOM_Initialize,初始化一次就够了,重复初始化会导致各种奇怪的问题
- 要确保你的C++ COM对象
pMyComObject的生命周期足够长,直到Python脚本完全不再使用它,不然会出现访问非法内存的崩溃问题 - 记得正确管理Python对象的引用计数,比如用Py_DECREF释放不再需要的对象,不然会有内存泄漏的风险
备注:内容来源于stack exchange,提问作者Emil Dimitrov
相关产品推荐
相关产品推荐

