最近在研究产品的架构代码,发现其中涉及到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. 数据结构5: 链表(单链表)的基本操作及C语言实现

    逻辑结构上一个挨一个的数据,在实际存储时,并没有像顺序表那样也相互紧挨着.恰恰相反,数据随机分布在内存中的各个位置,这种存储结构称为线性表的链式存储. 由于分散存储,为了能够体现出数据元素之间的逻辑关 ...

  2. 洛谷P2071 座位安排

    题目背景 公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决. 题目描述 已知车上有N排座位,有N*2个人参加省赛,每排座位只能坐两人,且每个人都有自己想坐的排数,问最 ...

  3. JavaBean简介和用法

    一.JavaBean的含义 JavaBean是使用Java语言开发的一个可重用组件,能使Html代码与JAVA代码分离,并节省开发时间,简单的说就是一个包含了setter和getter以及至少一个无参 ...

  4. postgresql 如何设置主键自增

    法一: CREATE TABLE customers ( customerid SERIAL primary key , companyname character varying, contactn ...

  5. 安装OFFICE2016错误代码0-1018(0)的解决方案 和激活方案

    一.安装OFFICE2016错误代码0-1018(0)的解决方案 下面方法亲测有效:Step 1. Go to C:\Program Files\Common Files\microsoft shar ...

  6. P1147 连续自然数和(思维题)

    题目描述 对一个给定的自然数MM,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为MM. 例子:1998+1999+2000+2001+2002 = 100001998+1999+2000 ...

  7. Codeforces Round #529 (Div. 3) C. Powers Of Two

    http://codeforces.com/contest/1095/problem/C 题意:给n找出k个2的幂,加起来正好等于n.例如 9,4:9 = 1 + 2 + 2 + 4 思路:首先任何数 ...

  8. jq方法(end)

    .end()方法: 使得结果集可以后退一步 $('div') .find('h3') .eq() .html('hello') .end()//退回到选中所有的h3元素的那一步 .eq()//选中第一 ...

  9. Oracle redo undo

    通常对undo有一个误解,认为undo用于数据库物理地恢复到执行语句或事务之前的样子,但实际上并非如此.数据库只是逻辑地恢复到原来的样子,所有修改都被逻辑地取消,但是数据结构以及数据库块本身在回滚后可 ...

  10. CF 520 B. Two Buttons(bfs)

    /*题意:一个数,就是输入的第一个数,让它变成第二个数最少用几步.可以点红色按钮,蓝色按钮来改变数字,红色:*2,蓝色:-1,如果变成负数,就变成原来的数.CF 520 B. Two Buttons思 ...