最近在研究产品的架构代码,发现其中涉及到Com组件技术,即项目中的C# Project会通过Com接口来调用C++ Project中的方法,研究一下,实现一个小的例子,供自己学习。

一. 什么是COM Interop?

  COM Interop 是一种让 .NET Framework 的程序能够和 COM 的程序相互操作的一种桥接技术[维基百科]。它可以让 .NET Framework 的程序使用 COM 组件,也可以让 COM 程序使用 .NET Framework 的组件。例如像我们的产品中,它可以让C#去调用C++的方法,C++去调用C#的方法。

  这里涉及到一个概念,COM组件,COM技术是开发组件的一种,COM标准由微软定义,COM组件可以是一个动态连接库(DLL), 被称为进程内组件(in-of-process component),也可以是一个可执行程序(EXE),被称为进程外组件(out-of-process component)。COM对象是建立在二进制可执行代码级的基础上,而C++等语言中的对象是建立在源代码级基础上的,因此COM对象是语言无关的。

  这一特性使用不同编程语言开发的组件对象进行交互成为可能。

  这里我们讨论其中一个简单例子:C#调用C++代码中的方法。

二. 示例步骤:

  简单说明,这里COM组件由ATL COM开发,IDE为Visual Studio 2005,步骤如下:

  1. 实现一个简单的ATL COM服务器

    A. 创建一个新的Visual C++ ATL 项目,名字:MyComServer。

    B. 向MyComServer中添加一个新类,这里为了开发方便,推荐使用IDE的add->class,选择ATL Simple Object,名字:MyTest,可看到IDE自动为我们生成一个COM Class CMyTest。

    C. 在类视图中,为MyTest的接口添加方法,名字:DoSomething,其他默认,生成后可以根据需要添加DoSomething的方法内容。

    这时IDE已经为我们做了很多工作,可看到CMyTest的声明如下:   

 class ATL_NO_VTABLE CMyTest :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyTest, &CLSID_MyTest>,
public IDispatchImpl<IMyTest, &IID_IMyTest, &LIBID_MyComServerLib, /*wMajor =*/ , /*wMinor =*/ >
{
public:
CMyTest()
{
} DECLARE_REGISTRY_RESOURCEID(IDR_MYTEST) BEGIN_COM_MAP(CMyTest)
COM_INTERFACE_ENTRY(IMyTest)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct()
{
return S_OK;
} void FinalRelease()
{
} public:
STDMETHOD(DoSomething)(void);
};

    DoSomething方法的实现如下:

 STDMETHODIMP CMyTest::DoSomething(void)
{
// TODO: Add your implementation code here wprintf_s(_T("Hello, I'm here!")); return S_OK;
}

  2. 使用 Tlbimp 转换 COM DLL

  现在有了 COM DLL,让我们来看看如何从一个托管客户端访问它。打开 Visual Studio 命令提示,然后转到创建 COM DLL 的目录。现在运行以下命令:

tlbimp MSDNCOMServer.dll
  Tlbimp.exe 是 .NET Framework SDK 中附带的类型库导入程序。此命令输出一个名为MyComServerLIB.dll的托管 DLL,该 DLL 作为非托管 COM DLL 的托管包装。
  
  关于Tlbimp.exe的作用,可以参加以下图:
  
  其实就.NET Application不能直接访问C++开发的COM组件编译出的MyComServer.dll,因此需要通过Tlbimp.exe生成一个Com组件的托管DLL,C#代码可以直接调用这一MyComServerLIB.dll,使用其中的类和方法。
  这里要注意是RCW(Runtime Callable Wrapper),其作用是当.NET Application在运行时调用非托管代码(本例中是C++)的方法时,runtime创建一个runtime callable wrapper (RCW)。RCW抽象了托管代码和非托管代码引用机制的不同,能够对非托管代码的对象进行管理。Runtime还创建了一个COM callable wrapper (CCW)来实现其逆过程,使得COM的客户能够无缝的调用.NET对象的方法。这里不深入探讨。
  
  3. 实现一个C# Project去调用C++方法
  这里很简单,如下:
 using System;
using System.Collections.Generic;
using System.Text;
using MyComServerLib; namespace MyComClient
{
class Program
{
static void Main(string[] args)
{
MyTestClass test = new MyTestClass();
test.DoSomething();
}
}
}

  执行此C#程序,即可看到"Hello, I'm here!"的输出信息,证明调用成功!!

三. 小结

  由于时间有限,昨天开始研究COM Interop,到今晚刚刚实现一个成功的例子,对COM技术的认识肯定还有很多问题,这里做下总结,也希望以后能继续完善。

  在两天的时间里,上网找到了很多很好的参考资料,如下:

  1. 示例实现主要参考的文章

      http://msdn.microsoft.com/zh-cn/magazine/cc163494.aspx

  2. Understanding Classic COM Interoperability With .NET Applications

    http://www.codeproject.com/Articles/990/Understanding-Classic-COM-Interoperability-With-NE

3. COM组件简介

    http://www.cppblog.com/3522021224/archive/2007/06/22/26803.html

4. RCW的介绍

    http://www.blogjava.net/davidgw/archive/2007/07/25/132240.html

  对于COM Interop技术,自己已经有了初步了解,有助于自己更加了解项目中的COM应用。

  明天可以进入下一个学习阶段啦,开始Adapter的学习!加油!晚安:-)

  Best Regards

  Kevin Song

    

   

最新文章

  1. asp.net中缓存的使用介绍一
  2. MapKit 添加大头针
  3. Struts2 实战(一)
  4. [转]JEXUS的高级配置
  5. C++设计新思维的traits和policy
  6. 解决数据标准及质量AppScan(测试)安全性问题相关方法
  7. java线程安全理解
  8. dfa最小化,终于完成了。
  9. 2014-08-05 pig
  10. 取出当前会话的sid等
  11. ;(function($,window,undefined){})(jQuery,window)详细解析————借助B5教程解析自己整理了一下
  12. java学习之观察者设计模式
  13. eclipse 安卓运行一直跳转到调试模式
  14. ML(1)--概念理解
  15. SQL Server 数据类型转换函数
  16. Android Task 任务
  17. jsp/servlet相关技术及知识
  18. Linux基础常用命令
  19. 多个子域名前端网站调用同一个webAPI时session混用问题
  20. 用百度地图API分析打交通大数据

热门文章

  1. poj3321(dfs序+树状数组)
  2. kvm重新命名
  3. 同源策略与 JSONP CORS
  4. php __CLASS__、get_class()与get_called_class()的区别
  5. IOS开发-基于WebDriverAgent代理服务,实现iOS手机app自动化测试的框架搭建
  6. 斑马条码打印机通过js post 打印
  7. 搭建一个wordpress网站需要做哪些工作
  8. FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。
  9. 关于int类型表示的最大位数
  10. Python 3.6 TypeEror: iter() returned non-iterator of type