如何将 COM 对象包装在本机 .NET 类中?

2024-03-04

我在 .NET (C#) 中使用广泛的现有 COM API(可能是 Outlook,但事实并非如此)。我通过在 Visual Studio 中添加“COM 引用”来完成此操作,因此所有“魔法”都是在幕后完成的(即,我不必手动运行tlbimp).

虽然现在可以从 .NET“轻松”使用 COM API,但它对 .NET 不太友好。例如,没有泛型、事件很奇怪、奇怪的事情比如IPicture https://stackoverflow.com/questions/2210594/convert-an-icon-to-ipicture-in-net-4-0等等。因此,我想创建一个使用现有 COM API 实现的本机 .NET API。

简单的第一遍可能是

namespace Company.Product {
   class ComObject {
       public readonly global::Product.ComObject Handle; // the "native" COM object
       public ComObject(global::Product.ComObject handle) {
          if (handle == null) throw new ArgumentNullException("handle");
          Handle = handle;
       }

       // EDIT: suggestions from nobugz
       public override int GetHashCode() {
          return Handle.GetHashCode();
       }
       public override bool Equals(object obj) {
          return Handle.Equals(obj);
       }
   }
}

这种方法的一个直接问题是您很容易最终得到多个实例通讯对象对于相同的底层“本机 COM”对象。例如,在进行枚举时:

IEnumerable<Company.Product.Item> Items {
   get {
      foreach (global::Item item in Handle.Items)
         yield return new Company.Product.Item(item);
   }
}

在大多数情况下,这可能是意想不到的。解决这个问题可能看起来像

namespace Company.Product {
   class ComObject {
       public readonly global::Product.ComObject Handle; // the "native" COM object
       static Dictionary<global::Product.ComObject, ComObject> m_handleMap = new Dictionary<global::Product.ComObject, ComObject>();
       private ComObject(global::Product.ComObject handle) {
          Handle = handle;
          handleMap[Handle] = this;
       }
       public ComObject Create(global::Product.ComObject handle) {
          if (handle == null) throw new ArgumentNullException("handle");

          ComObject retval;
          if (!handleMap.TryGetValue(handle, out retval))
              retval = new ComObject(handle);
          return retval;             
       }
   }
}

看起来好多了。枚举器更改为调用Company.Product.Item.Create(item)。 但现在的问题是字典将使两个对象保持“活动”状态,这样它们就永远不会被垃圾收集;这可能对 COM 对象不利。现在事情开始变得混乱......

看起来像解决方案的一部分 http://msdn.microsoft.com/en-us/magazine/cc163316.aspx正在使用弱引用 http://blogs.msdn.com/jaredpar/archive/2009/03/03/building-a-weakreference-hashtable.aspx某种程度上来说。还有建议 http://radio-weblogs.com/0105852/stories/2002/12/21/comInteropNotFundamentallyFlawedButHard.html关于使用I一次性但它似乎根本不适合 .NET 处理处置()在每一个物体上。然后就是各种讨论 http://blogs.msdn.com/cbrumme/archive/2003/04/16/51355.aspx当/如果释放通讯对象应该被称为。还有code http://www.codeproject.com/KB/COM/safecomwrapper.aspx结束了http://codeproject.com http://codeproject.com它使用后期绑定,但我对版本相关的 API 很满意。

因此,目前我不太确定最好的继续方式是什么。我希望我的本机 .NET API 尽可能“类似于 .NET”(甚至可能将 Interop 程序集嵌入到 .NET 4.0),并且不必采用“两点”规则等启发式方法。

我想到尝试的一件事是创建一个 ATL 项目,使用/clr标记并使用 C++ 编译器 COM 支持(产品::ComObjectPtr由...制作#import)而不是 .NET RCW。当然,我一般会而用 C# 编写代码 https://stackoverflow.com/questions/2185321/what-are-the-advantages-of-doing-100-managed-development-using-c-cli比 C++/CLI...


您自己并不是在处理 COM 对象。您已经在处理一个外观,它是在您向项目中添加对 COM 二进制文件的引用时创建的。 (.NET) 将为您生成一个外观,从而将使用 COM 对象的任务简化为仅使用常规 .NET 类。如果您不喜欢为您生成的界面,您可能应该为现有外观创建一个外观。您不必担心 COM 的复杂性,因为这已经为您完成了(可能有一些事情您确实需要担心,但我认为它们很少而且相差很远)。只需将该类用作常规 .net 类,因为它就是这样,并在出现任何问题时进行处理。

编辑:您可能遇到的问题之一是不确定的 COM 对象破坏。幕后发生的引用计数依赖于垃圾收集,因此您无法确定对象何时会被销毁。根据您的应用程序,您可能需要对 COM 对象进行更具确定性的破坏。为此,您将使用Marshal.ReleaseComObject. If是这样的话,那么你应该意识到this https://web.archive.org/web/20200815031612/http://geekswithblogs.net/jolson/archive/2004/02/03/1716.aspx gotcha.

抱歉,我会发布更多链接,但显然如果没有先获得 10 个声誉,我就无法发布超过 1 个链接。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 COM 对象包装在本机 .NET 类中? 的相关文章

随机推荐

  • jQuery 验证插件 - 如何在页面加载时显示标签

    填写输入后 该插件会插入一个标签 但是我希望在页面加载时插入所有标签 任何想法都会很棒 谢谢 该插件的链接在这里 http jqueryvalidation org documentation http jqueryvalidation o
  • 如何计算列表中点的距离?

    我有两组列表 A 和 O 它们都有来自 x y z 坐标的点 我想计算A点和B点之间的距离 我使用了for循环 但它只给了我一个结果 它应该从结果中给出 8 个数字 我很感激有人能看一下 这是我的项目的最后一步 Ax 232 34 233
  • 如何设置 Eclipse 工作区机制来共享设置?

    我该如何配置这个工具 我已经在 Eclipse 环境中设置了首选项 底部图标显示工作区机制正常 但是 当我打开工作区或创建新工作区时 没有任何反应 没有任何首选项 如何设置工作区机制 以及如何告诉工作区使用另一个工作区的设置 默认情况下 工
  • 在面向对象编程中,null 的最佳替代方案是什么?

    我觉得不满意在面向对象编程中 有其他解决方案吗 我不喜欢避免它this way http en wikipedia org wiki Null Object pattern either 最好的处理方法是什么 Java 8 有新的Optio
  • 在 Rails 中使用部分的最佳实践

    为了与 DRY 原则保持一致 当我重复某个特定模式超过一两次时 我会尝试使用部分模式 结果 我的一些观点由十个或更多不同的部分组成 我担心这可能会对整体表现产生负面影响 一些编程书籍将部分的使用与方法的使用进行比较 那么我应该使用相同的理由
  • 应用 CSS3 缩放时可排序行为错误

    我正在使用 CSS 转换缩放 JQuery 可排序元素 拖动时可排序项目的起始位置和偏移量都是错误的 因为 JQuery 不考虑 CSS 比例 我用这里找到的代码部分解决了这个问题 jQuery 拖动 使用 CSS 变换比例调整大小 htt
  • JSF2.0的宽度如何设置?

    代码 div div
  • 单个查询中多个日期范围的总和?

    我有以下查询 SELECT SUM balance transactions fee AS sum id FROM balance transactions JOIN charges ON balance transactions sour
  • Objective-C 插件架构安全性(Mac,不是 iPhone)

    我可能正在为 Cocoa 应用程序 Mac 而不是 iPhone 编写一个插件系统 一种常见的方法是将每个插件打包为一个包 然后将该包注入到主应用程序中 我担心这样做的安全隐患 因为捆绑包将具有对 Objective C 运行时的完全访问权
  • 查找数组中的最小值[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我有两个数组 int playerSums 9 string playerNames 9 我正在尝试获取最小值在数组中p
  • 网站的 A/B 测试是什么意思?

    请解释 举例 网站 A B 测试的含义 在网站上下文中 这意味着该网站 网络应用程序的某些用户获得slightly修改版本 并验证与基线 控制 版本相比 每个修改如何影响可用性 用户行为 与往常一样 A B 测试是一种统计技术 您需要足够大
  • 使用哪些 C# AES 加密选项以便可以在公共网站上解密结果? [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我想使用类似于下面的代码来加密字符串 并能够使用公开网站 例如其中一个网站 对其进行解密 但也对其他一些网站开放 htt
  • 用户窗体工具箱附加控件对话窗口未显示

    在使用 MS Excel 显然还有 Outlook Word 或 Power Point 时 我创建了一个用户表单 工具箱显示控件选项卡和代表各种控件的 16 个图标 当我右键单击工具箱控制区域中的某个空白区域时 会出现一个菜单 其中在顶部
  • 如何存储然后检索父子依赖性数据(Maya MEL/Python 脚本)

    我有一个需要的层次结构 分开 做一点事 按照以前的方式将其重新组装起来 我确实知道如何打破事物 并且对当层次结构扁平时我需要做什么有计划 问题是我如何养育他们 Details 这与我之前的问题有关 冻结带有动画子对象的父对象的缩放变换 MA
  • 在 Android 帐户管理器中存储其他数据

    我想使用安卓AccountManager但是 要同步我的网络服务和应用程序 联系人和日历的标准同步 AccountManager似乎只存储用户名和密码 我的 Web 服务需要三个凭据 用户名 密码和帐户 存储第三条信息的最佳实践是什么 正如
  • JPA - 事务未提交

    我正在开发一个项目 在该项目中我第一次使用 JPA Hibernate 和所有这些东西 但我遇到了事务未提交的问题 我使用类 User 如下所示 package org tomasherman JBTBackup Resource Enti
  • 通过正则表达式限制文本中的行数

    在任何编程语言中 我都知道如何有效地限制给定文件或字符串中的行数 这不是这里的问题 然而在这种情况下 我希望通过正则表达式来做到这一点 在这个模式中我只使用 n 换行符 我不需要其他人 例如 r 回车 n n 0 3 上面的正则表达式解释如
  • 通过 ByteBuffer 和 CQL 3 将 Java 对象序列化到 Cassandra 1.2

    我拼凑了下面的代码 它没有做任何复杂的事情 只是创建一个 byte 变量 将其写入 Cassandra 中的 blob 字段 v1 2 通过新的 Datastax CQL 库 然后将其读回又出来了 当我把它放进去时 它是 3 个元素长 当我
  • @AspectJ 类级别注释建议,以注释作为方法参数

    如何获取注释作为定义的建议的参数传递 类级注释 是否可以 来自帖子here https stackoverflow com questions 2011089 aspectj pointcut for all methods of a cl
  • 如何将 COM 对象包装在本机 .NET 类中?

    我在 NET C 中使用广泛的现有 COM API 可能是 Outlook 但事实并非如此 我通过在 Visual Studio 中添加 COM 引用 来完成此操作 因此所有 魔法 都是在幕后完成的 即 我不必手动运行tlbimp 虽然现在