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/