1. 定义.NET接口,撰写.NET class
2. 部署.NET组件
3. 撰写COM客户端
第一步骤对经常从事.NET的开发朋友来说非常熟悉,这里给出例子,不再赘述。
csc /target:library a.cs
第二,要部署.NET组件,这里包括两个方面:
regasm a.dll /tlb
1. 把类型库(type library)导出。对于COM应用来说,它只懂得类型库,是为COM组件遵循的二进制”标准”。/tlb选项告诉regasm,导出类型库。我们可以用oleview察看tlb的内容,如下图所示,此前定义的.NET接口和类都在其中。

2. 把步骤2中生成的dll放到注册表中。COM并不懂得诸如GAC的概念,而是通过注册表来查询HKEY_CLASSES_ROOT\CLS_ID\00000000-0000-0000-FFFF-000000000004,观察这个注册表项,InprocServer32中把COM的动态链接库指向了mscoree.dll,这就是传说中的垫片(shim),它会负责加载公共语言运行时,并找到真正的.NET组件----a.dll。

有了以上两步,我们就可以在COM应用中使用.NET组件了。如何撰写COM组件超出了本文的范畴,有兴趣的读者可以参考代码中的注释。
cl client.cs
// client.cs
#define _WIN32_COM
#include <stdio.h>
#include <wtypes.h>
#import "a.tlb" no_namespace named_guids raw_interfaces_only
// a.tlb是第二步中导出的
int main()
{
IUnknown *pUnk = NULL;
IA *pIA = NULL;
HRESULT hresult;
// 0. 初始化COM组件
hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hresult))
{
printf("ERROR: cannot initialze COM: 0x%x\n", hresult);
return -1;
}
// 1. 获取IUnknown接口
hresult = CoCreateInstance(CLSID_A, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk);
if (FAILED(hresult))
{
printf("ERROR: cannot Get the IUnkown interface: 0x%x\n", hresult);
return -1;
}
// 2. 获得IA接口
hresult = pUnk->QueryInterface(IID_IA, (void **)&pIA);
if (FAILED(hresult))
{
printf("ERROR: cannot Convert to IDispatch interface: 0x%x\n", hresult);
pUnk->Release();
return -1;
}
pUnk->Release();
// 3. 调用.NET组件
hresult = pIA->Hello();
if (FAILED(hresult))
{
printf("ERROR: Invoke failed: 0x%x\n", hresult);
}
// 4. 清理
pIA->Release();
CoUninitialize();
return 0;
}
By com.microsoft.stbc.devdiv.ndp.interop.dev/mountaintai二世