C#互操作性入门系列(四):在C#中调用COM组件

简介:

C#互操作系列文章:

  1. C#互操作性入门系列(一):C#平台下互操作性介绍

  2. C#互操作性入门系列(二):使用平台调用调用Win32 函数

  3. C#互操作性入门系列(三):平台调用中的数据封送处理

  4. C#互操作性入门系列(四):在C# 中调用COM组件


本专题概要:

  • 引言

  • 如何在C#中调用COM组件——访问Office 互操作对象

  • 在C#中调用COM组件的实现原理剖析

  • 错误处理

  • 小结


一、引言

  COM(Component Object Modele,组件对象模型)是微软以前推崇的一个开发技术,所以现在微软的很多产品都用到了COM组件,如Office,IE 等。然而如果.NET 平台下的程序想访问COM组件的方式来实现某个功能怎么办呢? 正是由于开发人员有这个需求,所以微软在.NET FrameWork中为COM和托管代码之间进行互操作提供了支持,这种互操作性的技术就是COM Interop。 但是COM Interop(COm互操作)这项技术,不仅支持在托管代码中使用COM对象,并且也支持在COM中使用托管对象,本专题只针对在.NET中调用COM对象来介绍,由于COM技术现在用的不多,所以如何在COM中使用托管对象将不会在本系列中做出介绍,如果有需要的朋友可以参看MSDN的相关链接: http://msdn.microsoft.com/zh-cn/library/3y76b69k(v=vs.100).aspx

下面就从一个具体的实例来看看在.NET 中是如何调用COM组件的。

二、如何在C#中调用COM组件——访问Office 互操作对象

  因为Office产品中使用了很多COM组件,下面就演示通过调用Office中的COM对象来创建Word文档并保存创建的文档到文件目录下的例子(在新建的控制台程序里添加”Microsoft.Office.Interop.Word 14.0.0.0 “ 这个引用,14.0.0.0版本是对应于Office 2010的一个互操作程序集, 12.0.0.0版本则是对应于Office 2007的互操作程序集,如果你电脑中只安装了Office 2007的话,就只能找到 12.0.0.0的版本的,如果安装了Office 2010的话,就可以同时找到这两个版本。)。具体代码如下:


 
 
  1. using System;  

  2. // 添加额外的命名空间

  3. using Microsoft.Office.Interop.Word;  

  4. namespace COM互操作性  

  5. {  

  6. class Program  

  7.    {  

  8. staticvoid Main(string[] args)  

  9.        {  

  10. // 调用COM对象来创建Word文档

  11.            CreateWordDocument();  

  12.        }  

  13. privatestaticvoid CreateWordDocument()  

  14.        {  

  15. // 启动Word并使Word可见

  16.            Application wordApp = new Application() { Visible = true };  

  17. // 新建Word文档

  18.            wordApp.Documents.Add();  

  19.            Document wordDoc = wordApp.ActiveDocument;  

  20.            Paragraph para = wordDoc.Paragraphs.Add();  

  21.            para.Range.Text = "欢迎你,进入Learning Hard博客";  

  22. // 保存文档

  23. object filename = @"D:\learninghard.doc";  

  24.            wordDoc.SaveAs2(filename);  

  25. // 关闭Word

  26.            wordDoc.Close();  

  27.            wordApp.Application.Quit();  

  28.        }  

  29.    }  

  30. }

运行结果为:

此时在所指定的文件目录中就可以看到你刚才创建的Word文档了。通过COM互操作的技术我们可以Office的自动化操作。

三、在C#中调用COM组件的实现原理剖析

  通过上面的例子,大家可以看出在.NET 中调用COM组件是非常方便和简单的,以至于我们根本不能明白它背后的原理的,下面就介绍在托管代码中调用COM组件的实现原理和需要的步骤。

要运行上面的程序必须添加一个互操作程序集——“Microsoft.Office.Interop.Word 14.0.0.0”,大家可以通过下面的步骤来添加这个程序集:

  • 请在“解决方案资源管理器”中,右击引用文件夹,然后单击添加引用

  • “.NET选项卡上,选中最新版本的 Microsoft.Office.Interop.Word例如,“Microsoft.Office.Interop.Excel 14.0.0.0”单击“确定”

  通过上面添加引用的步骤可以看出,Microsoft.Office.Interop.Word.dll 是一个.NET程序集,而不是COM组件,这时候朋友们肯定有这样的疑问——不是调用COM组件的吗?怎么在托管代码中调用.NET 程序集的?这样怎么能算是在.NET下调用COM组件的演示了? 然而事实是—— Microsoft.Office.Interop.Word.dll 确实是一个.NET程序集,并且它也叫做COM组件的互操作程序集,这个程序集中包含了COM组件中定义的类型的元数据, 托管代码通过调用互操作程序集中公开的接口或对象来间接地调用COM对象和接口的。由于托管代码中不能直接使用COM对象和接口,所以托管代码对COM对象的调用时是通过CLR的 COM Interop 层作为代理完成的,这个代理就是RCW(即Runtime Callable Wrapper,运行时可调用包装),所以对COM对象的调用,都是通过RCW来完成的,RCW做的工作主要有激活COM对象和在托管代码和非托管代码之间进行数据封送处理(从这里可以看出,RCW就是 .NET平台和COM组件之间的一个代理,微软的很多技术都使用了代理的,例如WCF技术——我们在代码中创建的对象其实只是服务的一个代理,通过代理对象来访问真真的对象的服务,即方法。讲到代理的技术,C#中的委托也是代理的一种实现,此时又想到了23中设计模式中的——代理模式,然而生活中也不乏代理的例子,租房中介,代理服务器等)。下面通过一个图来演示下 在.NET中调用COM组件的原理:

  关于通过Tlblmp.exe工具来生成互操作程序集步骤,这里我就不多详细诉说了,大家可以参考MSDN中这个工具详细使用说明 :http://msdn.microsoft.com/zh-cn/library/tt0cf3sx(v=VS.80).aspx 。

  然而我们也可以使用Visual Studio中内置的支持来完成为COM类型库创建互操作程序集的工作,我们只需要在VS中为.NET 项目添加对应的COM组件的引用,此时VS就会自动将COM类型库中的COM类型库转化为程序集中的元数据,并在项目的Bin目录下生成对于的互操作程序集,所以在VS中添加COM引用,其实最后程序中引用的是互操作程序集,然后通过RCW来对COM组件进行调用。 然而对于Office中的Microsoft.Office.Interop.Wordd.dll,这个程序集也是互操作程序集,但是它又是主互操作程序集,即PIA(Primary Interop Assemblies)。主互操作程序集是一个由供应商提供的唯一的程序集,为了生成主互操作程序集,可以在使用TlbImp命令是打开 /primary 选项。看到这里,朋友们肯定有这样的疑问:PIA与普通程序集到底有什么区别呢?——区别就是PIA除了包含了COM组件定义的数据类型外,还包含了一些特殊的信息,如公钥,COM类型库的提供者等信息。然而 为什么需要主互操作程序集的呢 ? 对于这个问题的答案就是——主互操作程序集可以帮助我们解决部署程序时,引用互操作程序集版本不一致的问题。(如果开发人员会为一个COM组件类型库生成多个互操作程序集,项目中引用的互操作程序集版本与部署时的互操作程序集版本不一致的问题,有了互操作程序集时,我们可以直接引用官方提供主互操作程序集。)

四、错误处理

知道了如何调用COM组件之后,大家或许会问:如果调用COM对象的方法失败时怎么去获取失败的信息呢?对于这个疑问,错误的处理的方法和我们平常托管代码中的处理方式是一样的,下面就具体看看是如何获取错误信息的,下面这段代码的功能是——打开一个现有的Word文档并插入相应的文本,当指定的Word文档不存在时,此时就会出现调用COM对象的Open方法失败的情况,具体代码如下:


 
 
  1. using System;  

  2. using Microsoft.Office.Interop.Word;  

  3. using System.IO;  

  4. using System.Runtime.InteropServices;  

  5. namespace COM互操作中的错误处理  

  6. {  

  7. class Program  

  8.    {  

  9. staticvoid Main(string[] args)  

  10.        {  

  11. // 打开存在的文档插入文本

  12. string wordPath = @"D:\test.docx";  

  13.            OpenWordDocument(wordPath);  

  14.            Console.Read();  

  15.        }  

  16. // 向现有文档插入文本

  17. privatestaticvoid OpenWordDocument(string wordPath)  

  18.        {  

  19. // 启动Word 应用程序

  20.            Application wordApp = new Application() { Visible = true };  

  21.            Document wordDoc=null;  

  22. try

  23.            {  

  24. // 如果文档不存在时,就会出现调用COM对象失败的情况

  25. // 打开Word文档

  26.                wordDoc = wordApp.Documents.Open(wordPath);  

  27. // 向Word中插入文本

  28.                Range wordRange = wordDoc.Range(0, 0);  

  29.                wordRange.Text = "这是插入的文本";  

  30. // 保存文档

  31.                wordDoc.Save();  

  32.            }  

  33. catch(Exception ex)  

  34.            {            

  35. // 获得异常相对应的HRESULT值

  36. // 因为COM中根据方法返回的HRESULT来判断调用是否成功的

  37. int HResult = Marshal.GetHRForException(ex);  

  38. // 设置控制台的前景色,即输出文本的颜色

  39.                Console.ForegroundColor = ConsoleColor.Red;  

  40. // 下面把HRESULT值以16进制输出

  41.                Console.WriteLine("调用抛出异常,异常类型为:{0}, HRESULT= 0x{1:x}", ex.GetType().Name, HResult);  

  42.                Console.WriteLine("异常信息为:" + ex.Message.Replace('\r', ' '));  

  43.            }  

  44. finally

  45.            {  

  46. // 关闭文档并

  47. if (wordDoc != null)  

  48.                {  

  49.                    wordDoc.Close();  

  50.                }  

  51. // 退出Word程序

  52.                wordApp.Quit();  

  53.            }  

  54.        }  

  55.    }  

  56. }

如果我们D盘中不存在一个 test.docx文档时,此时代码就会进入catch块,输出异常信息,运行结果为:

  从上面的结果我们看到了一个 HRESULT值,这个值真是COM代码中返回返回的。在COM中,COM方法通过返回 HRESULT 来报告错误;.NET 方法则通过引发异常来报告错误,为了方便地在托管代码中获得COM代码中出现的错误和异常信息,CLR提供了两者之间的转换,每一个代表错误发生的HRESULT都会被映射到.NET Framework中的一个异常类,对于具体的映射关系可以参考MSDN中 的文章: http://msdn.microsoft.com/zh-cn/library/9ztbc5s1(VS.80).aspx ,我这里就不具体用表格列出来的。 如果某个HRESULR不能被映射到等效的.NET Framework 异常类时,那么就会被映射到COMException异常类, 我们可以通过 Marshal类的GetHRForException方法来获得异常类对应的HRESULT值(该方法的使用在上面代码中已经贴出)

五、小结

  关于在.NET中调用COM组件的介绍就到这里的,即使我们在.NET中调用COM对象的方法是非常的简单和方便,但是理解CLR 为我们背后完成的工作到底有哪些和理解托管代码中调用COM组件原理也是相当有必要的。因为理解了调用的原理之后,当我们出现问题的时候就可以很快找到解决方案并解决它,不会觉得无从下手,这样就可以帮助我们提供解决问题的能力。




     本文转自LearningHard 51CTO博客,原文链接:http://blog.51cto.com/learninghard/1127124,如需转载请自行联系原作者


相关文章
|
6月前
|
存储 编译器 数据处理
C#基础入门之数据类型
C#基础入门之数据类型
|
1月前
|
开发框架 .NET API
RESTful API 设计与实现:C# 开发者的一分钟入门
【10月更文挑战第5天】本文从零开始,介绍了如何使用 C# 和 ASP.NET Core 设计并实现一个简单的 RESTful API。首先解释了 RESTful API 的概念及其核心原则,然后详细说明了设计 RESTful API 的关键步骤,包括资源识别、URI 设计、HTTP 方法选择、状态码使用和错误处理。最后,通过一个用户管理 API 的示例,演示了如何创建项目、定义模型、实现控制器及运行测试,帮助读者掌握 RESTful API 的开发技巧。
64 7
|
1月前
|
C#
C#入门
C#入门
26 0
|
11天前
|
程序员 C# 图形学
全面的C#/.NET自学入门指南
全面的C#/.NET自学入门指南
|
1月前
|
存储 消息中间件 NoSQL
Redis 入门 - C#.NET Core客户端库六种选择
Redis 入门 - C#.NET Core客户端库六种选择
62 8
|
2月前
|
设计模式 C# 开发者
C#设计模式入门实战教程
C#设计模式入门实战教程
|
2月前
|
安全 数据库连接 API
C#一分钟浅谈:多线程编程入门
在现代软件开发中,多线程编程对于提升程序响应性和执行效率至关重要。本文从基础概念入手,详细探讨了C#中的多线程技术,包括线程创建、管理及常见问题的解决策略,如线程安全、死锁和资源泄露等,并通过具体示例帮助读者理解和应用这些技巧,适合初学者快速掌握C#多线程编程。
82 0
|
2月前
|
开发框架 .NET Java
C#/.NET/.NET Core自学入门指南
C#/.NET/.NET Core自学入门指南
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
83 0
|
3月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
325 0
下一篇
无影云桌面