C#中COM操作(二) 接口查询

上一篇末留下的一个疑问这一回来作个解答吧。大家看了下面的图就清楚了:


结论就是t1,t2,t3是三个不同的引用,也就是说在.NET里面代表了三种不同的类型,但是三种类型的GUID却是一样的,因为在COM里GUID代表了一个COM类,只要GUID是一样的那么就表示是一个COM类,因此仅从COM类这一角度出发的话,这三种类型就是同一个COM类型。

第1种方式创建的COM对象的.NET包装的类型一般来说就是COM导入的.NET包装程序集里面对应声明的类型.

第2种方式创建的COM对象的.NET包装的类型永远都是__ComObject.

第3种方式创建的COM对象的.NET包装或者是指针经过Marshal类的方法转成的.NET的包装,这两种方式对应的类型__ComObject.

第4种从本质上来讲是第1种方式的变种,只是更为灵活,使用范围更加广范了,因此对应的类型也应该是声明的时候的.NET中的类型

上一文里面留的第二个问题的结果就是原来是什么类型,经过一次Marshal类的方法与IntPtr互转换后的结果还是什么类型,应该是CLR内部记录了指针和.NET类型之前的对应关系,不会每次由IntPtr转到object的时候都用一个不同的包装(感觉有点像WinForm里面从Handle找Control一样).

上一篇我们讲到了C#中创建COM对象的几种方式。不知大家也注意到了,最后一种方式中JetEngineClass类并没有提供方法供我们调用,要使用它的话必须先把这个引用转成接口引用才能直接使用里面的方法,实现早期函数绑定。虽然我们在声明JetEngineClass类的时候并没指定该类实现了IJetEngine接口,但是后面在使用的时候却直接把engine用as操作转成了IJetEngine接口,而且居然转成功了。而且大家也可以用is操作符测试一下,engine is IJetEngine反回的结果也为true。这就是本篇要讲的---C#中COM对象接口的查询。

与COM创建的方法一样,C#中COM接口查询的方法也有好几种:

第1种 Marshal.QueryInterface方法

这个方法本身就是Framework提供的正统的用来查询COM对象的方法,这种方式MSDN上已经有详细的说明了,我也不再多说.唯一注意的是这里只能传COM对象的指针IntPtr,而且这个方法成功返回后,所引用的COM对象的计数会自增1.以后当返回的查询到的接口的指针不再使用了的时候,需要手动调用Marshal.Release,达到平衡COM引用计数的目的.虽说是简单,还是给段代码吧

1 IntPtr pJetClass = GetJetEngine(); // return JetEngineClass Ptr
2
3 IntPtr pJet;
4 Guid g = typeof(IJetEngine).Guid;
5 int hr = Marshal.QueryInterface(pJetClass, ref g, out pJet);
6 if(hr <0)
7   Marshal.ThrowExceptionFromHR(hr);
8

其实在使用IntPtr引用COM对象的时候,就像是在C++里面直接使用COM指针一样,理论上来说这个指针每复制一次,都需要我们手动的调用一次AddRef方法,增加COM对象的引用计数,每当我们把指针设置为无效或不再使用这个指针的时候,同样需要手动的把这个指针用Release方法减少引用计数,当引用计数变为0的时候就释放COM对象.这还是没有摆脱C++里面使用原始的COM指针的时候容易忘记平衡引用计数的问题.这里我故意使用了"原始的COM指针"这外概念,主要是区别于在C++里面我们常使用COM指针的另外一种方式COMPtr<T>泛型类,有了这个泛型类C++里面的COM对象的引用计数就能够正常及时的增加和减少了,使得开发人员不用花心思在COM引用计数的维护上.但是就算是这样,要想查询一个接口还是摆脱不了那个QueryInterface方法.

C#作为一种继承了C++大部分优点的一种语言,当然也提供了类似的方式让我们远离引用计数的陷阱,而且还提供了更加优雅的方式供我们使用.

这就是我们要讲的第2种COM接口查询的方式

时间: 2025-01-24 03:26:02

C#中COM操作(二) 接口查询的相关文章

在Hibernate中直接操作JDBC接口

简介: Hibernate 在处理多表关联及分组排序等复杂数据库查询操作时,其固有的 O-R 映射机制会 产生大量冗余 SQL 操作,系统性能比传统的 JDBC 低很多.本文分析了 Hibernate 产生此类问题的原因 ,提出了一个在 Hibernate 框架内直接操作 JDBC 的接口的解决方案,在实际项目中验证了该解决方案 可以有效提高此类查询的效率.文中提供的示例代码可以直接运用于使用 Hibernate 框架的 J2EE 系统 项目. 在 Hibernate 框架中提供直接操作 JDB

Entity Framework 中 In操作如何保证查询后的顺序

问题描述 string[]array=ids.Split(',');//id集合,格式:1,5,3,6,4varquery=query.Where(m=>array.Contains(m.Id.ToString())); 通常情况下这种查询返回来的数据顺序是不固定的.就上面的例子而言,我想返回来的数据顺序就是1,5,3,6,4,不能是其他的.如何保证查询得到的数据是上面ids所传入的顺序? 解决方案 解决方案二:学会排序.解决方案三:您的意思是查询完成以后在对数据进行排序?还是通过某种方法在查询

Mybatis中的resultType和resultMap查询操作实例详解_java

resultType和resultMap只能有一个成立,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,resultMap解决复杂查询是的映射问题.比如:列名和对象属性名不一致时可以使用resultMap来配置:还有查询的对象中包含其他的对象等. MyBatisConfig.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configura

Google Chrome中的高性能网络(二)

Chrome Predictor的预测功能优化 Chrome会随着使用变得更快. 它这个特性是通过一个单例对象Predictor来实现的.这个对象在浏览器内核进程(Browser Kernel Process)中实例化,它唯一的职责就是观察和学习当前网络活动方式,提前预估用户下一步的操作.下面是一个示例: 用户将鼠标停留在一个链接上,就预示着一个用户的偏好以及下一步的浏览行为.这时Chrome就可以提前进行DNS Lookup及TCP握手.用户的点击操作平均需要将近200ms,在这个时间就可能处

使用组件封装数据库操作(二)

封装|数据|数据库|组件封装 使用组件封装数据库操作(二)前段日子发表的文章,数据库的连接代码可以直接在ASP文件中显示出来.这次又进行了一次封装. 打开vb,新建Activex控件,工程名称为WebDb,类模块名称为GetInfomation 引用"Microsoft Activex Data Object 2.6 Library " Private Conn As ADODB.Connection Private Rs As ADODB.Recordset '作用:判断数据库是否正

代码-如何在VS中使用C#设计程序实现查询点、线、面要素的空间查询

问题描述 如何在VS中使用C#设计程序实现查询点.线.面要素的空间查询 各位大婶 本人GIS专业大三学生一枚 实习中遇到任务 要基于MO的开发环境实现点.线.面要素的空间查询?因为以前学的比较渣 然后现在对于VS操作步骤基本不会 然后对于代码也是一脸茫然 跪求会的大神在百忙之中能知道一二 代表组内成员不胜感激! 解决方案 大婶们来帮个忙呗 真的很着急啊 唉 解决方案二: 这么急,直接上淘宝找人做吧

GIS基础软件及操作(二)

原文 GIS基础软件及操作(二)  练习二.管理地理空间数据库 1.利用ArcCatalog 管理地理空间数据库 2.在ArcMap中编辑属性数据 第1步 启动 ArcCatalog 打开一个地理数据库 当 ArcCatalog打开后,点击, 按钮(连接到文件夹). 建立到包含练习数据的连接(比如"E:\ARCGIS\2练习二\Exec2"), 在ArcCatalog窗口左边的目录树中, 点击上面创建的文件夹的连接图标旁的 (+)号,双击个人空间数据库- National.mdb.打开

asp.net中实现根据选择月份查询以往记录

问题描述 如下demo:protectedvoidPage_Load(objectsender,EventArgse){stringdatetime=Session["dateTime"].ToString();stringsql="select*fromScorewheredate='"+datetime+"'";GridView1.DataSource=DBHelper.GetDataTable(sql);//注意查询和update的时候都要

急求从两张数据表中抽取个别列,查询后组合成一张新表,如何做?

问题描述 A表包含字段ABCDB表包含EFC表字段ABCDEF从winform上查询完A表和B表的数据之后,选择某条A和某条B点击按钮生成一条新的C表数据如何操作代码怎么样 解决方案 解决方案二:数据库可以直接做,也可以用linq解决方案三:可以写一个类C,包含ABCDEF属性,然后选中A表中的字段,给C的ABCD赋值,选中B表,赋值EF,然后增加到C表中~解决方案四:获取选择的A与B对象,拼接insertsql语句,inserttableC(A,B,C......)Values(A.A,A.B