windows DLL中使用COM的注意事项

windows的DLL开发是有需要注意的地方的,不然会造成一些问题。由于我最近的使用不当,又造成了问题,虽然之前有写过一篇笔记, http://www.cnblogs.com/foohack/p/6645919.html 文章指出了在DLL中不能调用CoInitilazie

等初始化COM库的API。但是自己还是没有深刻理解。因为之前的项目只有一个线程,也就是主线程,主线程加载了一个DLL插件,DLL中有个Timer来定时在后台运行任务,任务需要使用wmic命令行提供的COM接口来

采集我所需要的数据,这样做是没问题的,就像贴出来的链接那篇文章所描述的一样,不需要初始化COM库了,因为主线程在加载DLL的那一刻已经初始化了COM库,我只用调用CoCreateInstance这个API创建COM接口的实例就可以了。

但是,最近的项目需要用Qt插件机制编写多个插件,关于数据采集那个插件需要用一个新的后台线程来运行Timer的定时任务,不然会阻塞Qt的UI主线程。由于采用了多个线程,我就没有注意到一个小细节上,

因为加载后台数据采集插件的线程还是主线程,只是加载完毕以后,我才通过Qt的moveToThread把任务对象移动到Qt新建的后台线程中的,所以这个新线程在调用COM接口的时候出错了,原因是新的后台线程没有初始化COM库,

DLL本质上还是主线程加载的。所以当然,COM接口是不会调用成功的了。所以,我就在运行DLL的后台线程里面有加入了CoInitializeEx等COM库的初始化函数,果然,COM接口调用成功了,并且能采集数据了,

之后神奇的事情发生了,看了日志,只有第一次调用的COM接口成功返回了数据,后面的COM接口的调用全部都失败了!! 后来查了MSDN的CoInitializeEx的函数说明,才知道,一个线程要使用COM接口,CoInitializeEx这个API有且只能在一个线程中调用

一次。不能调用两次,也不能调用0次, 由于我调用COM接口是封装在一个对象中的,在类的构造函数中调用了CoInitializeEx,所以新的对象反复初始化,就会导致该函数多次调用,导致后续的COM接口调用都不成功,后来我就把CoInitializeEx和CoInitializeSecurity提取出来,采用QThread的信号槽机制,在后台线程启动的那一刻,(接收started信号),来初始化COM库,这样在这个线程中对CoInitializeEx的调用就有且仅有一次了,所以后续的COM接口的调用都返回成功了。

 

references:

https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx

posted @ 2017-09-24 21:03  foo__hack  阅读(737)  评论(0编辑  收藏  举报