gpt4 book ai didi

c# - 如何将 COM 对象包装在 native .NET 类中?

转载 作者:可可西里 更新时间:2023-11-01 03:08:47 25 4
gpt4 key购买 nike

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

虽然 .NET 现在可以“轻松”使用 COM API,但它对 .NET 不是很友好。例如,没有泛型,事件很奇怪,像 IPicture 这样的怪事 等。因此,我想创建一个使用现有 COM API 实现的 native .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);
}
}
}

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

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)。但现在的问题是 Dictionary<> 将使两个对象保持“事件状态”,因此它们永远不会被垃圾收集;这可能对 COM 对象不利。现在事情开始变得一团糟……

看起来像part of the solution正在使用 WeakReference 以某种方式。还有suggestions关于使用 IDisposable 但似乎对 .NET 不太友好,必须处理每个对象上的 Dispose()。然后是各种 discussions何时/如果 ReleaseComObject 应该被调用。还有codehttp://codeproject.com它使用后期绑定(bind),但我对依赖于版本的 API 很满意。

所以,在这一点上,我不确定什么是最好的继续进行的方法。我希望我的 native .NET API 尽可能“类似于 .NET”(甚至可能将 Interop 程序集嵌入到 .NET 4.0 中)并且不必使用像“双点”规则这样的启发式方法。

我想尝试的一件事是创建一个 ATL 项目,使用 /clr 标志进行编译并使用 C++ 的编译器 COM 支持(Product::ComObjectPtr 创建于#import) 而不是 .NET RCW。当然,我通常会 rather code in C#比 C++/CLI...

最佳答案

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

编辑:您可能遇到的问题之一是不确定的 COM 对象销毁。幕后发生的引用计数依赖于垃圾回收,因此您无法确定对象何时会被销毁。根据您的应用程序,您可能需要更确定性地销毁 COM 对象。为此,您可以使用 Marshal.ReleaseComObject如果是这种情况,那么您应该知道this明白了。

抱歉,我会发布更多链接,但显然我不能在没有先获得 10 个声誉的情况下发布超过 1 个链接。

关于c# - 如何将 COM 对象包装在 native .NET 类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2258902/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com