最近在研究产品的架构代码,发现其中涉及到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

    

   

[COM Interop学习小结]实现一个C#调用C++的示例的更多相关文章

  1. 《Linux内核分析》第三周学习小结 构造一个简单的Linux系统OS

    郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 第三周 构造一个简单的Linux系统Me ...

  2. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  3. react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

    react学习小结   本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...

  4. objective-c基础教程——学习小结

    objective-c基础教程——学习小结   提纲: 简介 与C语言相比要注意的地方 objective-c高级特性 开发工具介绍(cocoa 工具包的功能,框架,源文件组织:XCode使用介绍) ...

  5. pthread多线程编程的学习小结

    pthread多线程编程的学习小结  pthread 同步3种方法: 1 mutex 2 条件变量 3 读写锁:支持多个线程同时读,或者一个线程写     程序员必上的开发者服务平台 —— DevSt ...

  6. dubbo学习小结

    dubbo学习小结 参考: https://blog.csdn.net/paul_wei2008/article/details/19355681 https://blog.csdn.net/liwe ...

  7. clone的fork与pthread_create创建线程有何不同&pthread多线程编程的学习小结(转)

    进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合,这些资源在Linux中被抽 象成各种数据对象:进程控制块.虚存空间.文件系统,文件I/O.信号处理函数.所以创建一个进程的 过程就是这 ...

  8. 插头$DP$学习小结

    插头\(DP\)学习小结 这种辣鸡毒瘤东西也能叫算法... 很优秀的一个算法. 最基本的适用范围主要是数据范围极小的网格图路径计数问题. 如果是像\(Noi2018\)那种的话建议考生在其他两道题难度 ...

  9. AJAX学习小结

    12345678910 $.ajax({ "url":"", //访问路径 "data":"", // 需要传输的数据 ...

随机推荐

  1. oracle ,mysql,postgres jdbc配置文件

    #db mysql #jdbc.driver=com.mysql.jdbc.Driver #jdbc.url=jdbc:mysql://localhost:3306/mysql?&useUni ...

  2. vue项目中使用了vw适配方案,引入第三方ui框架mint-ui时,适配问题解决

    问题分析: 一般第三方ui框架用的都是不同的适配方式,如果我们使用了vw适配,那么在使用mint-ui框架时,就会发现px单位会被转换成vw,从而导致样式变小的问题,如图 解决方案 网上看到了很多种解 ...

  3. 【笔记】Pandas分类数据详解

    [笔记]Pandas分类数据详解 Pandas  Pandas分类数据详解|轻松玩转Pandas(5) 参考:Pandas分类数据详解|轻松玩转Pandas(5)

  4. 07-图5 Saving James Bond - Hard Version (30 分)

    This time let us consider the situation in the movie "Live and Let Die" in which James Bon ...

  5. 导入json文件报错,TypeError expected string or buffer

    导入json文件报错,TypeError expected string or buffer 原因:用字符串赋值后,python会把双引号转换为单引号 import json data = [{&qu ...

  6. 工作必备,五分钟如何搞定Excel甘特图

    工作必备,五分钟如何搞定Excel甘特图  https://www.sohu.com/a/212628821_641930 EXCEL中如何给图表添加标题 1.选中图表 >> [布局] 菜 ...

  7. vue 子组件调用父组件的函数

    子组件调用父组件的函数,使用$emit(eventName,[...args]),触发当前实例上的事件.附加参数都会传给监听器回调. 子组件 <template> <div> ...

  8. java——newInstance()方法和new关键字

    https://www.cnblogs.com/liuyanmin/p/5146557.html 这两个都可以创建一个对象,那么这样个东西有什么不一样呢?什么时候用new,什么时候用newInstan ...

  9. 转 python trace walk DEMO

    https://blog.csdn.net/steadfast123/article/details/46965125 #quote from 'introduction to computation ...

  10. django建表报错

     今天在用pycharm创建数据库的表的时候碰见了一个报错,这还是头一次碰见这种奇怪的错误.这里记住希望能避免错误. 我所创建的表是用的django原有的用户表,做了一下继承. class UserI ...