随笔-60  评论-262  文章-1  trackbacks-0

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

    本文不打算叙述, 参看以下文章.
    http://www.codeproject.com/KB/cs/cominterop.aspx


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

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

    源代码下载  http://www.cppblog.com/Files/free2000fly/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?

例子代码下载:  http://www.cppblog.com/Files/free2000fly/cstocpptest.zip

另一个例子, 用 C++ 的 ATL 定义接口, 然后用 C# 实现接口. 然后用 C++ 客户端来调用之. http://www.cppblog.com/Files/free2000fly/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

posted on 2009-03-23 16:02 free2000fly 阅读(6606) 评论(11)  编辑 收藏 引用

评论:
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-24 01:23 | LEEO
C#做出来的组件估计不能在没有.NET环境的机器上运行,那么这样做的意义就大打折扣了,相反到是常用C++做COM给C#调用.  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-24 06:56 | free2000fly
@LEEO
这样可以大大加快组件开发的速度. 至于 .net 环境, 到现在还是问题吗.  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-24 11:43 | eve
只能用于.net framework, win mobile上的.net compact framework 无法使用  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-24 14:58 | free2000fly
@eve
你有兴趣的话研究研究在 .net compact framework 上怎么搞吧. 造福程序员, 功德无量哟  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-25 15:59 | 2008s
通常做客户端的时候用C#来开发,把核心业务封装到C++写成的DLL里面。  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-03-25 16:49 | free2000fly
@2008s
有时候是恰恰相反, 尤其是那些有些历史的大型软件.  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-06-18 11:23 | alacom
用过在VS2008 MFC智能设备调用 C# DLL没有?
要是知道的话.能否交流?QQ 252561552 邮箱是:alecom@163.com  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-06-18 13:15 | free2000fly
@alacom
没搞过智能设备 :-)  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-06-26 15:50 | alacom
唉!没有人会啊!  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-07-17 17:02 | flyingbugs
有空我来搞一把看看?

一直想写一个轻便高效的windowsmobile的UI库,用类似WTL的实现,加上java里面swt的思想,提供一套给托管代码使用。

目前的感觉,.net cf开发mobile应用在界面上稍嫌慢了点,并且wm的界面的美观程度一般。 好像wm7将大大改善。 可能我想写的UI库,在wm7诞生后就失去了它存在的意义了。  回复  更多评论
  
# re: 打通 C++ 和 C# 关于 COM 组件互相调用的任督二脉 2009-08-05 16:40 | 路过
我的调查结果:WM下不能实现C++调用C#;
原因:C#端用COM的话,C++端是没有公开API来调用C#,COM库mscoree没有提供,所以实现不了查找C#COM的接口;
有什么疏漏之处请指教,我的MSN:bdsony@hotmail.com  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理