COM使用简介
1. 全球唯一标识符GUID是用来在注册表中确定COM的dll位置的。
接口ID(IID)用来查找同一个COM中的不同接口的。
GUID不用记,可以用hResult = ::CLSIDFromProgID(L"COMtest.Object", &firstComCLSID);去注册表查找,COMtest.Object为建COM时标记的,用来找GUID。
hResult = CoCreateInstance(firstComCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnknown);
它会返回一个IUnknown指针,指向这个COM的第一个接口上,以后可以用
hResult = pUnknown->QueryInterface(IID_IFirstCOM, (void **)&pFirstCom);查找接口。
(经常有些偷懒的人在CoCreateInstance中直接用接口的指针拿来搞,我感觉就问题哈,多个接口怎么办,不断构造COM么。。。)
2. 头文件,应该为这2个
#include "..\COMtest\COMtest\COMtest_i.h"
#include "..\COMtest\COMtest\COMtest_i.c"
就不需要自己输入
const IID IID_IFirst_ATL = {
0xD5870BE7,0x26BD,0x4FCD,
{0x8C,0x54,0xF8,0x9C,0xE1,0xEC,0xCF,0x6F}
};
const CLSID CLSID_First_ATL = {
0x2BA452EE,0x1D19,0x4E10,
{0xAA,0xD4,0x6D,0x1A,0x8E,0xD2,0x44,0x2E}
};这些东西了。
3. vs2008的ATL简单对象一个COM只有一个接口,插入多个ATL简单对象是没用的,那是多个COM,(一个dll可以有多个COM),还会造成CoCreateInstance失败,这不是多接口(浪费我好多时间)。多接口需要手动插入,http://www.vckbase.com/document/viewdoc/?id=1501 。
4. 杨老师使用的是自定义(custom)的接口,我用了dual 双接口,删掉嫌麻烦,修改就不大一样
public IDispatchImpl<ISecondCOM, &IID_ISecondCOM, &LIBID_COMtestLib, /*wMajor =*/ 1, /*wMinor =*/ 0> 还有其他。。。
而且编译错误
BEGIN_COM_MAP(CFirstCOM)
//COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IFirstCOM)
COM_INTERFACE_ENTRY(ISecondCOM)
END_COM_MAP()
把COM_INTERFACE_ENTRY(IDispatch)测试通过了。
附上我的测试代码:
#include "..\COMtest\COMtest\COMtest_i.h" #include "..\COMtest\COMtest\COMtest_i.c" #include <stdio.h> void main() { HRESULT hResult = 0; IUnknown *pUnknown;//组件的实例只有一个IUnknown接口 IFirstCOM* pFirstCom;//接口指针 if (!SUCCEEDED(CoInitialize(NULL))) //初始化COM库 { printf("Initialize COM library failed!\n"); return ; } GUID firstComCLSID; hResult = ::CLSIDFromProgID(L"COMtest.Object", &firstComCLSID); if (!SUCCEEDED(hResult)) { printf("Can't find the TestCom CLSID!\n"); return; } /*通过组件标识ID创建一个组件实例,pUnknown返回组件的一个通用接口, 通过它可以查询我们想要的接口, CLSTX_INPROC_SERVER表示是进程类主键, 其实此处也通过InProcServer32查找到组件的路径并加载到内存*/ hResult = CoCreateInstance(firstComCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnknown); if (!SUCCEEDED(hResult)) { printf("Create object failed!\n"); return; } /*查找要使用的接口,IDD_TestCom是组件的标识符,通过该标识符也就查找到对应的接口了 该标识符由服务端组件告知,否则写的组件也就失去其意义。*/ hResult = pUnknown->QueryInterface(IID_IFirstCOM, (void **)&pFirstCom); if (!SUCCEEDED(hResult)) { pUnknown->Release(); printf("QueryInterface first ITestInterFace failed!\n"); return; } //查找到接口后调用接口提供的功能 long ReturnValue; pFirstCom->Add(5,7,&ReturnValue); printf("The answer for 5 + 7 is: %ld\n",ReturnValue); ISecondCOM* pSecondCom;//接口指针 hResult = pUnknown->QueryInterface(IID_ISecondCOM, (void **)&pSecondCom); pSecondCom->Sub(5,7,&ReturnValue); printf("The answer for 5 - 7 is: %ld\n",ReturnValue); pSecondCom->Release(); //告诉接口,不在使用 pFirstCom->Release(); //判断该接口是否还被使用 if (pUnknown->Release() == 0) { printf("Com Free Succeeded!\n"); } CoUninitialize();//清理环境 }
Reference: http://www.vckbase.com/vckbase/columnist/yangfeng/