当前所在位置: 首页 > 维修大全

https://blog.csdn.net/u012818292/article/details/103745611

2025-04-12 本站作者 【 字体:

知识需要不断积累、总结和沉淀,思考和写作是成长的催化剂

文章目录

一、COM和.NET

COM组件对象模型是在.NET之前的一种编程规范,它允许不同的语言之间可以互相操作。由于COM规范比较复杂,注册表,内存对象管理,错误处理机制都和.NET不同,.NET做为其后秀,应用起来更简单,但一般不会因为新技术可用就重写已有的代码,所以就引来COM的互操作性

我们可能不必编写COM组件,但了解是有用的。经常会遇到嵌入互操作类型,为COM设置互操作问题

先看一下COM的一些基本概念,挑了几个重要的也是比较好理解的

元数据

COM的元数据信息存储在tlb类型库中,包含接口、方法和参数名称等,在.NET程序集中元数据都存储在程序集中的。

内存管理

我们知道.NET托管对象的内存释放都有垃圾回收器GC完成,不同于COM,COM依赖引用计数,

接口

COM三个基本接口,IClassFactory、IUnknown、Idispatch

IClassFactory,每个组件都有一个相关的类厂用于创建COM组件对象。非托管对象,客户端是无法直接New对象的,所以只能通过交给类厂来创建实例然后把实例的指针交给客户端

每个COM对象必须实现IUnknown接口,QueryInterface用于查询组件实现的其它接口,说白了也就是看看这个组件的父类中还有哪些接口类,AddRef()递增引用计数,Release()递减引用计数,为0后就销毁对象

IDispatch调度接口派生自IUnknown接口,在其基础上又增加了GetIDsOfNames()和Invoke(),调用接口会创建方法或属性对应的调用ID映射表,这样调用时先获取根据名字获取调度ID然后Invoke调用。因为并不是所有的语言(客户端)(像一些js脚本语言)都支持指针,也就不能通过虚函数表来调用,所以用调度接口增加函数ID映射。

注册

.NET中区分私有程序集和共享程序集。在COM中,通过注册表配置的所有组件都是全局可用的。所有COM对象都有一个唯一标识符CLSID类ID,创建COM对象时,COM API调用CoCreateInstacne()方法,在注册表中查找CLSID的dll或exe路径,然后加载,实例化组件

线程

COM使用单元模型,单元模型有**单线程单元模型STA和多线程单元模型MTA**

STA单线程单元模型,在Winfrom程序中经常看到Main入口函数上面标记STAThread特性。在STA中只允许创建实例的线程访问组件。一个进程中也可以包含多个STA

MTA多线程单元模型,在MTA中,多个线程可以同时访问组件

编组

.NET和COM之间的数据传递必须经过转换,这种机制就是编组(marshaling)。转换过程取决于数据类型。简单的数据类型如byte、short、int和long属性blittable类型,在com和net中是一样的表示方法,其他nonblittable类型的则需要进行转换,当然会有些开销

COM数据类型.Net数据类型

SAFEARRAY

Array

VARIANT

Object

BSTR

String

Iunknown,Idispatch

Object

二、.NET客户端调用COM组件

由于COM对象和.NET对象在生命周期、内存管理、接口服务上的差异,运行时提供了包装类来使其互相调用。托管客户端调用 COM 对象方法时,运行时就会创建一个**运行时可调用包装器 (RCW)**来封送引用机制之间的差异。 也会创建了一个 COM 可调用包装器 (CCW) 来逆转此过程

三、COM客户端调用.NET组件

没写过COM,也不是很了解,但一些约定规范必须遵守,原理和.NET客户端调用COM组件类似

比如在C#类库的AssemblyInfo.cs中修改

// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]

在程序集属性中勾选COM互操作注册

然后任何一个需要暴露给COM客户端的都需要有接口

[ComVisible(true)]  
[Guid("35A5CE1E-551C-41EC-81D4-005318550119")]  
public interface IMyClass  
{  
    void Initialize();  
    void Dispose();  
    int Add(int x, int y);
}  

编译时候因为勾选的为COM互操作注册,所以需要以管理员运行的才能注册成功

四、嵌入互操作类型

引用**PIA**(主互操作程序集,COM组件生成)时,可以设置是否嵌入互操作类型。嵌入互操作类型时(True)则PIA不随着程序一起部署,程序只是引用COM中的类型信息,这样的好处就是可以部署到不同COM版本的环境中。比如常用的Office开发Microsoft.Office.Interop.Excel,设置嵌入互操作类型,就可以不依赖office版本。改为互操作false后也就将PIA复制到本地

有时候会无法嵌入互操作类型请改为适当的接口,单纯一点就修改嵌入互操作设为false,OK编译通过。不太单纯的,可以修改创建对象的方式,像下面这样,直接实例化的普通类,无法嵌入互操作类型

Application excelApp = new ApplicationClass();

Application excelApp = new Application()

这样是可以的,Application虽然是一个接口,理论上应该不能实例化的,当它上面标记了

[CoClass(typeof (ApplicationClass))

告诉运行时CLR,当有人要创建类型为Application的实例时,它实际上应该继续创建ApplicationClass的实例。

用COM接口的可以嵌入,直接使用coclass的无法嵌入

五、平台调用DllImport

还有一些非托管库不包含COM对象,只包含倒出的函数,这时候需要使用**平台调用服务(P-Invoke)**,CLR会加载包含所需调用函数的dll,并编组参数。在C++的非托管库中使用dllexport暴露函数,在C#中使用dllimport导入。基本语法如下

[DLLImport(“DLL文件”)]

修饰符 extern 返回变量类型 方法名称 (参数列表)

dllimport在命名空间System.Runtime.InteropServices下,该特性用于对照非托管库中导出的函数

[AttributeUsage(AttributeTargets.Method)]
public class DllImportAttribute: System.Attribute
{
   public DllImportAttribute(string dllName) {}    //定位参数为dllName
   public CallingConvention CallingConvention;      //入口点调用约定
   public CharSet CharSet;                              //入口点采用的字符接
   public string EntryPoint;                //入口点名称
   public bool ExactSpelling;               //是否必须与指示的入口点拼写完全一致,默认false
   public bool PreserveSig;                 //方法的签名是被保留还是被转换
   public bool SetLastError;                //FindLastError方法的返回值保存在这里
   public string Value { get {} }
}

需要注意的就是数据类型的映射,必须映射到.NET数据类型上。可以使用**P/Invoke Interop Assistant**工具,它支持托管代码和非托管代码之间的方法签名的转换,可以直接生成调用代码

一般会在一些特殊场合来调用win 32的api,比如像输入法程序设置永远不获取焦点,一些任务处理时不希望用户点击别的操作(当然窗体也不能崩了),这时候可以使用下面设置窗体控件不可用

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int wndproc);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
 
public const int GWL_STYLE = -16;
public const int WS_DISABLED = 0x8000000;
public static void SetControlEnabled(Control c, bool enabled)
{
     if (enabled)
     { 
		SetWindowLong(c.Handle, GWL_STYLE, (~WS_DISABLED) & GetWindowLong(c.Handle, GWL_STYLE));
	}
else
{ 
		SetWindowLong(c.Handle, GWL_STYLE, WS_DISABLED + GetWindowLong(c.Handle, GWL_STYLE)); 
	}
}

六、等等

关于COM也只是知晓一二,平常主要写业务,COM用的不多,充其量就是调用。做底层嵌入式开发应该用的比较多,比如设备打印机驱动等。了解总没坏处,拜了个拜

阅读全文
加载中~
相关推荐

轮胎翻新技术:延长使用寿命,了解轮胎翻新技术的原理和优势

轮胎翻新技术:延长使用寿命,了解轮胎翻新技术的原理和优势
什么是轮胎翻新技术?轮胎翻新技术是指将旧轮胎进行翻新处理,恢复轮胎的使用性能和外...

沈阳明夜起正式开栓供暖,供暖权威解答都在这里了!

沈阳明夜起正式开栓供暖,供暖权威解答都在这里了!
暖气不热,你先试试这些方法

如果买一台二手车,做哪些翻新是很有必要的?

如果买一台二手车,做哪些翻新是很有必要的?
尽管新车看起来光鲜又亮丽,但其实真正懂行的人都会买二手车。不仅价格便宜,性价比高...

开了17年本田车的老司机亲测:这三个保养技巧让你的爱车多开15年

开了17年本田车的老司机亲测:这三个保养技巧让你的爱车多开15年
“本田车开不坏,一车传三代”的江湖传言是否可信?作为拥有17年本田车龄、累计行驶...

那些年,魔兽世界中的拉风坐骑

<strong>那些年,魔兽世界中的拉风坐骑</strong>
魔兽世界里有着众多稀有坐骑。曾经需要一个团队才能down掉的boss,如今因为等...

燕郊电脑维修

燕郊电脑维修
燕郊电脑维修 燕郊附近电脑维修 燕郊维修电脑[6图]03-13北京修沙发塌陷修椅...

丰田旗下质量最好的3辆车!开20年无需大修,最后一辆是混动鼻祖

<strong>丰田旗下质量最好的3辆车!开20年无需大修,最后一辆是混动鼻祖</strong>
说到耐用车,丰田大概是绕不过去的品牌了。最近翻车厂的销量又创新高,这么多人买,肯...

物业动用维修基金的流程

物业动用维修基金的流程
维修基金是业主在收房的时候交的一笔房子的“养老金”,用于房子未来过了保修期后的一...

三、51.1%的门店进厂台次下滑超15%,快修快保店最难

三、51.1%的门店进厂台次下滑超15%,快修快保店最难
机会总是留给有准备的人。

科勒马桶服务电话丨全国24小时400客服中心

科勒马桶服务电话丨全国24小时400客服中心
科勒马桶服务电话丨全国24小时400客服中心无论在何处购买,不管是谁的责任,只要...
本站访客:4158
1097476955
服务热线

服务热线

18951535724

18951535724
返回顶部