• 上章地址

  • 什么是COM

    • Component Object Model 组建对象模型

    • 基于接口(Interface)

      • 接口=协议
      • IID 标识接口
      • V-table 虚表 方式调用
      • 单继承
    • 对象(Object)

      • 实现一个或者多个接口
  • 举例:IDispatch接口

  • 为什么要使用COM Interop

    • 重用代码:使用.NET调用已有的COM组件,提高生产率:使用.NET编写COM组件 
  • COM Interop基础概念

    • RCW:Runtime Callable Wrapper  .NET可调用COM组件的包装代理   .NET=>RCW=>COM 
    • CCW:Com Callable Wrapper     COM可调用的包装代理            COM=>CCW=>.NET
  • RCW基础

    • 定义COM接口

      [ComImport]
      [Guid("....")]
      [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      interface IMyInterface
      {
      void Func();
      }
    • Attributes

      • ComImport 接口按照对应的COM接口定义
      • Guid 指定IID
      • InterfaceType
        • ComInterfaceType.InterfaceIsIUnknown 在.NET调用COM组件的时候总是用虚表的方式调用 和C++调用虚函数一样 要知道函数指针以及偏移量

          • Early Bound  早绑定
          • 基于虚表
          • 函数顺序必须和COM接口完全一致    但是如果你不用后面方法只调用前三个 那么只需要前三个方法对应就行了 不建议可能导致顺序婚论
        • ComInterfaceType.InterfaceIsIDispatch 通过函数名字 和 Displd调用   COM组件用VB写的建议使用这种方式调用 这种方式中间会有Invoke 会慢点 方便点
          • Late Bound  后期绑定
          • 支持IDispatch
          • 通过Displd 属性指定Dispatch ID 或者自动生成
          • 函数顺序不重要  
        • ComInterfaceType.InterfaceIsDual     既支持虚表调用也支持IDispatch方式调用   上面两种他都支持
          • 支持  IUnknown和IDispatch两种方式  他需要 顺序和ID都要对
  • 接口的继承      

    • 需要重新定义父接口的成员函数   父接口函数放前面  自身接口放后面 按顺序声明

      [ComImport]
      interface IA
      {
      void FuncA();
      }
      [ComImport]
      interface IB:IA
      {
      void new FuncA();
      void FuncB();
      }
  • 定义RCW

    • [ComImport]
      public class MyRcw:IMyInterface
      {
      [MethodImplAttribute(MethodImplOptions.InternalCall)]
      public extern void MyFunc();
      }
    • ComImport 告诉CLR这个是RCW

    • extern + InternalCall 函数由CLR内部实现 具有ComImport特性的时候必须使用extern和InternalCall 强制约束

  • 自动生成RCW:TlbImp

    • TlbImp<tlb_name>

    • 生成Interop Assembly

      • Struct/Union
      • Enum
      • Interface
      • Class
    • 直接引用即可

    • VS中Add Reference

  • 使用RCW

    • 创建RCW    MyRCW  rcw=new MyRCW();

    • 释放RCW     GC自动处理    AppDomain Unload 时候    Marshal.ReleaseComObject     Marshal.FinalReleaseComObject

    • 调用方法 rew.Func()

    • Cast

      • ImyInterface2  interface2=rcw as IMyInterface2; 可能成功
      • 实际上对应QueryInterface调用  
      • 不需要RCW类型本身实现IMyInterface2!
      • 失败则抛出异常(Cast)或者返回Null (as 操作符)
  • DEMO

      不会建立com 组件的请参考csdn上一位大牛的帖子  上面有详细的创建流程在此感谢大牛的分享 ,这里在分享一篇有心人收集的对应表 com 我个人感觉用的是Windows数据类型 自己参考查看 对应表

  

c#代码片段

    class Program
{ [ComImport, Guid("31E95758-B52C-4252-B4E0-F33547F9B55A")] public interface IMyATLClass
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
void Add([In] int para1, [In] int para2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
void PopupDialog(string text);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
void Sum([In] int para1, [In] int para2, out int Sum); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
void Messg([In] string test); } [ComImport, CoClass(typeof(MyATLClassClass)), Guid("31E95758-B52C-4252-B4E0-F33547F9B55A")]
public interface MyATLClass : IMyATLClass
{
} [ComImport, Guid("D14CE5C7-9648-427B-BEAC-504E1A91DDAE")]
public class MyATLClassClass : IMyATLClass, MyATLClass
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
public virtual extern void Add([In] int para1, [In] int para2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
public virtual extern void PopupDialog([MarshalAs(UnmanagedType.BStr)] string text);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
public virtual extern void Sum([In] int para1, [In] int para2, out int Sum); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId()]
public virtual extern void Messg([In] string test);
}
static void Main(string[] args)
{
// MyATLComLib.IMyATLClass aa = new MyATLComLib.MyATLClass();
//int i;
//aa.Sum(1, 1, out i);
//aa.Add(1, 1); //IntPtr sb = Marshal.StringToCoTaskMemAnsi("123"); IMyATLClass aa = new MyATLClass();
int i;
aa.Sum(, , out i);
//aa.Add(1, 1); // IntPtr sb = Marshal.StringToCoTaskMemUni("21");
string a = "a";
IntPtr aPtr = Marshal.StringToHGlobalAnsi(a); IntPtr helloPtr = Marshal.StringToHGlobalAnsi("aaaa"); // aa.PopupDialog("a1");
aa.Messg("哈哈哈哈"); Console.Write(i);
Console.Read();
// int i;
// DemoObjectLib.IMyCOMDemo aaaa= new DemoObjectLib.MyCOMDemoClass();
}
}

    c++代码片段

// MyATLClass.cpp : CMyATLClass 的实现

#include "stdafx.h"
#include "MyATLClass.h" // CMyATLClass STDMETHODIMP CMyATLClass::Add(LONG para1, LONG para2)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
LONG a = para1 + para2;
AfxMessageBox(a);
// TODO: 在此添加实现代码
return S_OK;
} STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加实现代码
AfxMessageBox((LPCTSTR)text);
return S_OK;
} STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加实现代码
*sum = para1 + para2;
return S_OK;
} STDMETHODIMP CMyATLClass::Messg(BSTR test)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: 在此添加实现代码
AfxMessageBox(test);
return S_OK;
}

  

   

公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记的更多相关文章

  1. 公共语言运行库(CLR)开发系列课程(1):Pinvoke 简介 学习笔记

    前言 让拖管代码对象和非托管对象协同工作的过程称为互用性(Interoperability),通常简称为 Interop. P/Invoke在托管代码与非托管代码交互式时产生一个事务(Transiti ...

  2. 公共语言运行库(CLR)开发系列课程(2):Pinvoke 进阶 学习笔记

    上一章地址 API版本 具有字符串参数的API通常有两种版本 GetWindowText GetWindowTextA GetWindowTextW 缺省情况下CLR会自动寻找合适的匹配 CharSe ...

  3. CLR 公共语言运行库

    1..支持多语言..只是语言是面向CLR的..均可以在此基础上运行. 2..程序集加载..程序打包之后的Dll文件由CLR(公共语言运行库)来编译并加载到可以执行状态..由CLR(公共语言运行库)加载 ...

  4. 公共语言运行库(CLR)和中间语言(IL)(一)

    公共语言运行库(.net运行库)即CLR 1.C#先编译为IL,IL为ms的中间语言,IL是平台无关性的. 2.CLR再将IL编译为平台专用语言. 3.CLR在编译IL时为即时编译(JIT) VB.V ...

  5. Silverlight for Windows Phone开发系列课程

    Silverlight for Windows Phone开发系列课程(1):Windows Phone平台概况         课程简介:本节开始介绍系列课程的概况,包括课程内容,先决条件,学习目的 ...

  6. ASP.NET MVC框架开发系列课程 (webcast视频下载)

    课程讲师: 赵劼 MSDN特邀讲师 赵劼(网名“老赵”.英文名“Jeffrey Zhao”,技术博客为http://jeffreyzhao.cnblogs.com),微软最有价值专家(ASP.NET ...

  7. ABP开发框架前后端开发系列---(6)ABP基础接口处理和省份城市行政区管理模块的开发

    最近没有更新ABP框架的相关文章,一直在研究和封装相关的接口,总算告一段落,开始继续整理下开发心得.上次我在随笔<ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目 ...

  8. ASP.Net MVC开发基础学习笔记:一、走向MVC模式

    一.ASP.Net的两种开发模式 1.1 ASP.Net WebForm的开发模式 (1)处理流程 在传统的WebForm模式下,我们请求一个例如http://www.aspnetmvc.com/bl ...

  9. ASP.Net MVC开发基础学习笔记(1):走向MVC模式

    一.ASP.Net的两种开发模式 1.1 ASP.Net WebForm的开发模式 (1)处理流程 在传统的WebForm模式下,我们请求一个例如http://www.aspnetmvc.com/bl ...

随机推荐

  1. Spring所需的Jar包下载

    作者:zhidashang 来源:CSDN 原文:https://blog.csdn.net/zhidashang/article/details/78706027 版权声明:本文为博主原创文章,转载 ...

  2. Spring+Junit测试用例的使用

    1.[导包]使用Spring测试套件,需要两个jar包:junit-X.X.jar和spring-test-X.X.X.RELEASE.jar,在maven项目下可添加如下依赖: <depend ...

  3. BZOJ2655 calc(动态规划+拉格朗日插值法)

    考虑暴力dp:f[i][j]表示i个数值域1~j时的答案.考虑使其值域++,则有f[i][j]=f[i][j-1]+f[i-1][j-1]*i*j,边界f[i][i]=i!*i!. 注意到值域很大,考 ...

  4. Winform Treeview 的按需加载

    最近项目里用到treeview,原先设计的是一开始就把所有数据都加载到treeview里,后来发现客户的数据量实在太大,加载所有数据要2分钟,这个是客户没法接受的.后来就考虑到用户也不是一开始就要看所 ...

  5. LookupError: unknown encoding: cp65001解决方案

    本人遇到这个问题搜索了很多网站,有人建议在cmd中执行命令chcp 936,然而,,,最终决定更换cmd窗口,window的cmd真的很烂, 果断使用git cmd,完美解决...

  6. 解题:LNOI 2014 LCA

    题面 这题有点意思 转化问题,我们把询问区间的点到根链加,再查询询问点到根的权值和就是每个询问的答案. 然后如果你数据结构没学傻只需要差分一下就可以扫一遍出解了 #include<cstdio& ...

  7. mybatis异常invalid comparison: java.util.Date and java.lang.String

    原文链接:http://blog.csdn.net/wanghailong_qd/article/details/50673144 mybatis异常invalid comparison: java. ...

  8. 解决小米note5 安装了google play store 打不开的问题

    打不开的原因是缺少了google play store 运行的一些后台程序 去豌豆荚下载如下谷歌安装器(注:安装器有很多种,我试了如下这种成功) 重启手机,google play store 即可正常 ...

  9. Kafka+Zookeeper+Filebeat+ELK 搭建日志收集系统

    ELK ELK目前主流的一种日志系统,过多的就不多介绍了 Filebeat收集日志,将收集的日志输出到kafka,避免网络问题丢失信息 kafka接收到日志消息后直接消费到Logstash Logst ...

  10. package.json浅谈

    相信很多小伙伴都见过各种各样的Node.js项目,而里面都有一个名为package.json的文件,而这个文件究竟是干什么的呢? 简单的来说,这个文件就是对整个项目的各种情况的配置(也是介绍),下面给 ...