我在 .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...