公共语言运行库(CLR)开发系列课程(3):COM Interop基础 学习笔记
上章地址
什么是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都要对
- ComInterfaceType.InterfaceIsIUnknown 在.NET调用COM组件的时候总是用虚表的方式调用 和C++调用虚函数一样 要知道函数指针以及偏移量
接口的继承
- 需要重新定义父接口的成员函数 父接口函数放前面 自身接口放后面 按顺序声明
[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基础 学习笔记的更多相关文章
- 公共语言运行库(CLR)开发系列课程(1):Pinvoke 简介 学习笔记
前言 让拖管代码对象和非托管对象协同工作的过程称为互用性(Interoperability),通常简称为 Interop. P/Invoke在托管代码与非托管代码交互式时产生一个事务(Transiti ...
- 公共语言运行库(CLR)开发系列课程(2):Pinvoke 进阶 学习笔记
上一章地址 API版本 具有字符串参数的API通常有两种版本 GetWindowText GetWindowTextA GetWindowTextW 缺省情况下CLR会自动寻找合适的匹配 CharSe ...
- CLR 公共语言运行库
1..支持多语言..只是语言是面向CLR的..均可以在此基础上运行. 2..程序集加载..程序打包之后的Dll文件由CLR(公共语言运行库)来编译并加载到可以执行状态..由CLR(公共语言运行库)加载 ...
- 公共语言运行库(CLR)和中间语言(IL)(一)
公共语言运行库(.net运行库)即CLR 1.C#先编译为IL,IL为ms的中间语言,IL是平台无关性的. 2.CLR再将IL编译为平台专用语言. 3.CLR在编译IL时为即时编译(JIT) VB.V ...
- Silverlight for Windows Phone开发系列课程
Silverlight for Windows Phone开发系列课程(1):Windows Phone平台概况 课程简介:本节开始介绍系列课程的概况,包括课程内容,先决条件,学习目的 ...
- ASP.NET MVC框架开发系列课程 (webcast视频下载)
课程讲师: 赵劼 MSDN特邀讲师 赵劼(网名“老赵”.英文名“Jeffrey Zhao”,技术博客为http://jeffreyzhao.cnblogs.com),微软最有价值专家(ASP.NET ...
- ABP开发框架前后端开发系列---(6)ABP基础接口处理和省份城市行政区管理模块的开发
最近没有更新ABP框架的相关文章,一直在研究和封装相关的接口,总算告一段落,开始继续整理下开发心得.上次我在随笔<ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目 ...
- ASP.Net MVC开发基础学习笔记:一、走向MVC模式
一.ASP.Net的两种开发模式 1.1 ASP.Net WebForm的开发模式 (1)处理流程 在传统的WebForm模式下,我们请求一个例如http://www.aspnetmvc.com/bl ...
- ASP.Net MVC开发基础学习笔记(1):走向MVC模式
一.ASP.Net的两种开发模式 1.1 ASP.Net WebForm的开发模式 (1)处理流程 在传统的WebForm模式下,我们请求一个例如http://www.aspnetmvc.com/bl ...
随机推荐
- 在 Ubuntu16.04 中搭建 Spark 单机开发环境 (JDK + Scala + Spark)
1.准备 本文主要讲述如何在Ubuntu 16.04 中搭建 Spark 2.11 单机开发环境,主要分为 3 部分:JDK 安装,Scala 安装和 Spark 安装. JDK 1.8:jdk-8u ...
- 团队作业(五)-笔记app top5
在互联网快速发展的情况下,各个行业的软件层出不穷,五花八门.各个行业都有相当多的软件介入其中,在如此多的软件之中,便有了相当激烈的竞争角逐.今天我们十五万的总冠军就着笔记APP行业中位列top 5的软 ...
- iOS国际化——通过脚本使storyboard翻译自增
一. 针对两种文件的国际化处理 代码中即.m文件的国际化 首先在你需要进行国际化处理的字符串外面加一层NSLocalizedString,注意中文也是可以的哦 textfield.text = [NS ...
- jvm垃圾回收机制和常见算法
这是朋友给的面试题里边的,具体地址已经找不到,只能对原作者说声抱歉了: 理论上来讲sun公司只定义了垃圾回收机制规则,而步局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同. GC(Gar ...
- Beta 冲刺 一
团队成员 051601135 岳冠宇 031602629 刘意晗 031602248 郑智文 031602330 苏芳锃 031602234 王淇 照片 项目进展 岳冠宇 昨天的困难 无 今天的进度 ...
- [转帖]Windows10七大版本区别在哪?
Windows10七大版本区别在哪? http://os.51cto.com/art/201804/570132.htm 一.Windows10家庭版 对于绝大多数用户来说,最后可能获得的应该就是Wi ...
- php 有意思的小题
/** * 你的是一个数字和一个字符串进行比较,PHP会把字符串转换成数字再进行比较.* PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,若无则输出0.***/1)$a =”abc ...
- Tether USDT 节点钱包的安装与使用
当前,在进行数字资产交易的过程中,由于各国政府的政策因素,法币成为数字资产交易的一个重要问题.在法币接入数字资产交易的过程中,通常是用某种数字资产对法币进行锚定,例如bitshares上面的许多b ...
- 前端开发【第5篇:JavaScript进阶】
语句 复合表达式和空语句 复合表达式意思是把多条表达式连接在一起形成一个表达式 { let a = 100; let b = 200; let c = a + b; } 注意这里不能再块级后面加分号, ...
- 【BZOJ1560】[JSOI2009]火星藏宝图(贪心,动态规划)
[BZOJ1560][JSOI2009]火星藏宝图(贪心,动态规划) 题面 BZOJ 洛谷 题解 既然所有的位置的权值都大于\(0\),那么就可以直接贪心,按照行为第一关键字,列为第二关键字,来转移. ...