大约是1995年, 就对OLE很感兴趣, 还买了本OLE 2的大部头,现在还睡在书柜里. 2000年的时候, 做过比较长时间的COM编程, 对COM有了比较深的理解.
对于.Net风靡的今天, 越来越多的人不再关心COM了. 但事实上, 很多技术还是和COM有着直接或间接的联系.
最近, 我就又体验了一次COM编程的苦与乐. 问题是调用微软的Application Verifier的组件。Application Verifier是微软开发的用来测试应用程序兼容性的免费工具。该软件通过COM技术公开了一系列组件,允许自动测试工具使用Application Verifier的功能。
Application Verifier的帮助文件中介绍了各个接口。其中比较重要的有,IAppVerifierManager, IAppVerifierImageChecks等。
现在的目标是创建这些接口然后调用其提供的方法。创建组件的根本方法是调用CoCreateInstance() API。比如要创建IAppVerifierManager接口的实例,那么可以使用类似如下的方法来调用CoCreateInstance:
::CoCreateInstance( CLSID_AppVerifierManager, NULL, CLSCTX_INPROC_SERVER, IID_IAppVerifierManager, reinterpret_cast< void** >( &m_pAppVerifierManager) );
其中,m_pAppVerifierChecks 是一个IAppVerifierManager类型的指针。即:
IAppVerifierManager * m_pAppVerifierManager;
那现在的问题是,从哪里得到上面用到的几个定义,IAppVerifierManager,CLSID_AppVerifierManager和IID_IAppVerifierManager。
首先想到的是使用VC6的Class Wisard中的从类型库中Add Class功能。使用该功能,并指定Application Verifier 3.3文件夹中的vrfauto.dll可以生成两个文件,一个是vrfauto.h,另一个是vrfauot.cpp.前者包含了对IAppVerifierManager 的定义。
EXTERN_C const IID IID_IAppVerifierManager;
#if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("6b0532d9-ee3c-4865-8c1a-8e4e9fcaa7fc") IAppVerifierManager : public IDispatch { public:......
后者包含一些对InvokeHelper函数的调用。
此时Biuld整个项目,链接时会失败,因为CLSID_AppVerifierManager和IID_IAppVerifierManager没用解决。因为vrfauto.h只是通过extern IID IID_IAppVerifierManager作了声明,没有真正定义。
那么如何得到这两个定义呢?方法是编译接口定义文件(IDL),于是把Application Verifier 3.3文件夹中的vrfauto.idl文件加入到项目中。但是MIDL在编译这个文件时遇到错误。
error MIDL2025 : syntax error : expecting ) near "a version number in the form 0000.0000.0000.000"
记得以前也遇到过MIDL报告诡异错误的情况,根据经验者大多是因为环境没有设置好。打开项目属性对话框,转到MIDL页,去除缺省选中的MkTypLib compatible 复选框,再次编译,刚才的离奇错误就不见了,而且MIDL生成两个文件:vrfauto.h和vrfauto_i.c,其中vrfauto_i.c中包含了对CLSID_AppVerifierManager和IID_IAppVerifierManager的定义。
const CLSID CLSID_AppVerifierManager = {0x597c1ef7,0xfc28,0x451e,{0x82,0x73,0x41,0x7c,0x6c,0x92,0x44,0xed}};const IID IID_IAppVerifierManager = {0x6b0532d9,0xee3c,0x4865,{0x8c,0x1a,0x8e,0x4e,0x9f,0xca,0xa7,0xfc}};将vrfauto_i.c文件加入到项目中,并将其的预编译头文件属性设为No,于是就可以顺利链接了。
归纳一下,对于C++程序,如果有IDL文件,那么就只要将IDL文件加入到项目中,并编译产生.h和_i.c文件,然后就可以使用CoCreateInstance创建接口了。也就是说使用VC6的Add Class根据DLL类型库创建的IDispatch节口是不必要的。对于VB来说,可以直接使用DLL类型库,根本不需要IDL文件。