1、谏言
最近我在弄64位调用32位dll的问题,在几种IPC之间,最后考虑了调用COM 毕竟我们只在windows平台
2、第一坑–修改编译后都需要重新注册,注册表
一直以为只需要编译就好了,结果调用没反应、报错什么的,需要先撤销注册再进行注册
3、第二坑–多线程调用问题
由于我编写的一个操作 是主线程 创建了 com对象后,有个子线程会一直在后台死循环调用最后回调
我最开始按照传入COM指针去进行调用结果是 没反应 也不报错
反复测试后发现是
主线程调用就有反应
子线程调用就没反应
超级奇怪的问题 最后发现是COM多线程调用会出现问题需要一点操作
IGlobalInterfaceTable* GIT = nullptr;// 初始化(通常在主线程)
CoCreateInstance(CLSID_StdGlobalInterfaceTable, nullptr, CLSCTX_INPROC_SERVER,IID_IGlobalInterfaceTable, (void**)&GIT);// 注册接口
GIT->RegisterInterfaceInGlobal(read, IID_Name, &Cookie);
首先我们需要一个IGlobalInterfaceTable 的对象,然后注册具体的com对象,我们再在子线程里面进行的查找COM对象
去调用
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
IICRead* pICRead = nullptr;
/*DWORD cookie = cookie;*/
reinterpret_cast<IGlobalInterfaceTable*>(GIT)->GetInterfaceFromGlobal((DWORD)Cookie, IID_Name, (void**)&pICRead);
这里 pICRead 就是我们查找出来的COM对象 这个对象和主线程是一样的
而我们要传递给子线程的 一个是IGlobalInterfaceTable 、 一个是 DWORD cookie 这个值很重要
是我们 RegisterInterfaceInGlobal 注册COM时的唯一标识符
子线程结束了需要调用COM的Release 与 CoUninitialize函数清除COM环境
当不再需要GIT时 我们一样需要Release 当然 之前我们还需要取消注册 RevokeInterfaceFromGlobal 参数是之前的那个cookie
4、第四坑–COM很多函数都是成对存在的
如
CoInitializeEx 与 CoUninitialize
RegisterInterfaceInGlobal 与 RevokeInterfaceFromGlobal
CoCreateInstance 与 Release
等等 只要用到COM对象 就需要清理
5、第五坑–COM读取数据块时
比如 现在我需要读取COM对象的函数 其中是返回一个数据块内部的数据的
我之前直接传入指针,发现返回出来的都是错误信息,一查才知道,有专门的手段
BYTE* pData = NULL;// 用于存储读取的数据
SAFEARRAY* p = SafeArrayCreateVector(VT_UI1, 0, 16);
read->Read_IC_Com(&p); // 读取数据到 SafeArray
SafeArrayAccessData(p, (void**)&pData); // 访问 SafeArray 数据
_memccpy(pDataBuff, pData, 0, 16); // 将 SafeArray 数据复制到 pDataBuff
SafeArrayUnaccessData(p);
SafeArrayDestroy(p);
我们需要使用 SafeArray 相关的东西 进行中转才可以
6、第六坑–多个线程同时调用COM对象可能会导致死锁,程序直接卡死
我写了一个这样的情况
我在com对象中写了个函数内部是死循环 条件 是可以通过另一个函数进行修改 从而达到可以结束的条件
问题就在这里了
我在子线程里面去调用这个COM跑死循环的函数
在主线程里面去调用这个可以结束COM死循环的条件函数
然后程序直接卡死
最后我修改死循环来到COM的调用方解决这个问题