822 views
首页 > 技术心得 > 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉

打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉

2009年3月23日

一. 关于从 C# 客户端调用 C++ 非托管代码的方法.

本文不打算叙述, 参看以下文章.
http://www.codeproject.com/KB/cs/cominterop.aspx
二. 关于从 C++ 客户端调用 C# 托管代码的方法.

(一). 非常直接的方法, 参看这篇文章.
http://www.codeproject.com/KB/cs/unmanagedtomanaged.aspx

源代码下载  cpp-call-cs.zip

(二). 我们的方法. 这里主要讲我们的方法. 这里只讲实现过程, 不讲原理.

1. C# 实现的组件
(1). 打开 VS 2008, 然后新建一个 C# 工程, 类型是 windows 的 class library, 工程名为 MyTestClsLib.
见下图  [--图1--]

(2). 打开 class1.cs 文件, 在

using System.Text;

语句后面添加语句

using System.Runtime.InteropServices;

(3). 将 public class Class1 类名改为更好认的, 如 SimpleType.

(4). 在类 SimpleType 类头顶添加类接口属性 [ClassInterface(ClassInterfaceType.AutoDual)]
以上三步见下图  [--图2--]

(5). 在 SimpleType 类内部添加函数.

public string ConvertIntToString(int n)
{
return n.ToString();
}

(6). 打开工程的 AssemblyInfo.cs 文件, 将语句

[assembly: ComVisible(false)]

改为

[assembly: ComVisible(true)]

(7). 打开工程的 “属性(properties)” 对话框. 选中 build 选项卡, 在这一页的最下边勾选 “Register for COM interop” 检查框.
见下图  [--图3--]

(8). 编译这个工程, 如果一切顺利, 将在 bin\debug\ 目录下生成目标文件 MyTestClsLib.dll 和 MyTestClsLib.tlb 文件.

至此, C# 组件开发完毕. 通过查看注册表,可以看到增添了如下内容:


Windows Registry Editor Version  5.00

[HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}]
 @="MyTestClsLib.SimpleType"

[HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}\Implemented Categories]
 [HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
 [HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}\InprocServer32]
 @="mscoree.dll"
 "ThreadingModel"="both"
 "Class"="MyTestClsLib.SimpleType"
 "Assembly"="MyTestClsLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
 "RuntimeVersion"="v2.0.50727"
 "CodeBase"="file:///E:/WUTemp/MyTestClsLib/bin/Debug/MyTestClsLib.dll"

[HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}\InprocServer32\1.0.0.0]
 "Class"="MyTestClsLib.SimpleType"
 "Assembly"="MyTestClsLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
 "RuntimeVersion"="v2.0.50727"
 "CodeBase"="file:///E:/WUTemp/MyTestClsLib/bin/Debug/MyTestClsLib.dll"

[HKEY_CLASSES_ROOT\CLSID\{E57F961E-9925-3025-A854-AF3E4B7C0801}\ProgId]
 @="MyTestClsLib.SimpleType"

[HKEY_CLASSES_ROOT\MyTestClsLib.SimpleType]
 @="MyTestClsLib.SimpleType"

[HKEY_CLASSES_ROOT\MyTestClsLib.SimpleType\CLSID]
 @="{E57F961E-9925-3025-A854-AF3E4B7C0801}"

2. C++ 客户端的例子.
(1). 新建一个 C++ 控制台程序, 工程名字是 TestClient, 见下图  [--图4--] .

(2). 在包含文件 stdafx.h 内添加

#include <windows.h>

#include <atlbase.h>

(3). 在 TestClient.cpp 文件添加如下内容.

#import "..\MyTestClsLib\bin\Debug\MyTestClsLib.tlb" raw_interfaces_only
using namespace MyTestClsLib;

(4). 随便声明一个函数并实现之, 比如 void Foo(void); 在这个函数体内就可以调用我们先前实现的 C# 组件了.
比如这些代码:


void Foo(void)
{
HRESULT hr = E_FAIL;
CComPtr<_SimpleType> spTmp;
hr = spTmp.CoCreateInstance(__uuidof(SimpleType));
if (SUCCEEDED(hr))
{
CComBSTR str;
spTmp->ConvertIntToString(887, &str);
}
}

(5). 然后在 main 函数里就可以调用 Foo 函数了, 调用之前记得初始化 COM 环境. 见下图 [--图5--] .

(6). 到此, 打完收工. 现在, 就可以编译调试看看效果了. 看看 CComBSTR str 变量里是不是有了返回值 887?

例子代码 下载:  cstocpptest.zip
另一个例子, 用 C++ 的 ATL 定义接口, 然后用 C# 实现接口. 然后用 C++ 客户端来调用之. com2cs-impl.zip

参考资料:
(1)http://www.codeproject.com/KB/cs/ManagedCOM.aspx
(2) http://www.codeproject.com/KB/COM/cominterop.aspx
(3) http://www.codeproject.com/KB/cs/cominterop.aspx
(4) http://blogs.msdn.com/yizhang/archive/2007/11/05/net-mscoree-dll.aspx
(5) http://www.codeproject.com/KB/cs/unmanagedtomanaged.aspx

技术心得

  1. 目前还没有任何评论.
  1. 目前还没有任何 trackbacks 和 pingbacks.