【问题标题】:Create a DLL from a TLB Assembly从 TLB 程序集创建 DLL
【发布时间】:2014-05-07 20:06:15
【问题描述】:

在使用 dynamic 关键字 (more information here) 从 C# 调用 COM TLB 方法时,我遇到了一些性能问题。因为我在尝试优化此类调用时没有任何运气,我现在正在寻找一种将我的 TLB 库转换为本机包装 DLL 的方法,我可以直接在我的 C# 项目中使用它(在这个阶段我什至不确定这是否会帮助,而是将性能问题抽象到一层)。

我已使用tlbimp.exe 使用 VS2013 命令提示符和命令从我的 COM .tlb 文件(已注册)创建一个 .dll

tlbimp F:\SomeDir\GrpSvr.tlb /out:F\SomeDir\GrpSvr.dll 

这产生了一个托管包装 C# .dll,我可以使用 dotPeek 检查它。它包含预期的命名空间

namespace GRPSVR
{
    [TypeLibType(TypeLibTypeFlags.FCanCreate)]
    [Guid("FFB54BC4-B15E-11D1-99BC-0000E803C444")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComImport]
    public class GrpCallClass : IGrpCall, GrpCall { /*Expected Methods et al.*/ }
}

和两个接口IGrpCall 包含生成类的完整模板和空接口GrpCall。我使用regasm.exe

注册了这个 .dll
regasm F:\SomeDir\GrpSvr.dll 

现在,我在我的项目中包含对这个 .dll 的引用,并尝试通过

实例化 GrpCallClass
private GRPSVR.GrpCallClass grpSvr = new GRPSVR.GrpCallClass();

但这会给编译时错误:

无法嵌入互操作类型“GRPSVR.GrpCallClass”。请改用适用的接口。

那我试试

private GRPSVR.IGrpCall grpSvr = new GRPSVR.GrpCall();

这在编译时有效,但在运行时我得到一个

附加信息:检索具有 CLSID {FFB54BC4-B15E-11D1-99BC-0000E803C444} 的组件的 COM 类工厂失败,原因是以下错误:80040154 未注册类(来自 HRESULT 的异常:0x80040154 (REGDB_E_CLASSNOTREG))。

但是我已经注册了 .dll。

  1. 这种方法是否有助于提高初始 COM TLB 程序集中调用方法的性能?

  2. 谁能解释我做错了什么以及如何将我的 COM .tlb 库转换为本机包装器 .dll?

感谢您的宝贵时间。

【问题讨论】:

  • 看起来你正朝着正确的方向前进。在注册表中查找您的类并查看它是否存在,就像您查看任何其他 COM 对象一样。此外,请注意许多 COM 组件仅是 32 位的,因此您的调用应用程序也应该是 32 位的。请注意,注册实用程序也有 32 位和 64 位版本。

标签: c# dll com interop


【解决方案1】:

我使用 regasm.exe 注册了这个 .dll

这是一个致命的错误。 覆盖本机 COM 服务器的注册表项。 Regasm 只应在以 .NET 语言编写服务器时使用。您将不得不重新安装服务器以修复损坏。请务必先运行 Regasm /unregister 以清理注册表。

和空接口 GrpCall

您看到一个空界面是您必须在 C# 代码中使用 dynamic 关键字的原因。 COM 服务器的作者只允许你在后期使用它。 .NET 中的 [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 的等价物。这并不少见,它避免了很多 DLL Hell 的痛苦。但可以肯定的是,后期绑定并不是很快,因为在运行时需要额外调用才能找到您正在调用的方法的 dispid。设置堆栈帧以进行调用也很慢,每个参数都必须转换为 VARIANT。与早期绑定调用相比,x10 的减速是很正常的,对于一个简单的属性可能会下降几个数量级。

您无法采取任何措施来避免这种情况,您必须与服务器作者合作才能取得成功。一个非常令人愉快的顶部是奶酪,要求一个双界面。期待“否”,您可能会得到“是”。

【讨论】:

  • 汉斯,再次感谢您的光临。一如既往,非常感谢......一切顺利。
  • 澄清一下,您是说即使我从tlbimp 获得C# 包装器,我仍然会受到这种性能影响?我认为使用这个包装器 dll 我可以摆脱后期绑定?我也刚刚意识到我可以在我的 VS2013 项目中添加对 COM 库的引用,从而允许我直接访问上面的类/接口——这又是一种在幕后进行后期绑定的方法/什么会在这种情况下我的电话会发生什么情况?
  • 附言。我没有取消注册就删除了生成的 DLL。我是一个白痴。我现在可以做些什么来取消注册该 DLL?我尝试重新安装使用 TLB/COM 库的应用程序,但现在无法正确注册!我是傻瓜。
  • 您可以重新运行 tlbimp.exe 并在 dll 上使用 Regasm /uninstall 来清理注册表。使用互操作库不会有任何区别,您仍然需要进行后期绑定调用。服务器作者不希望您使用它,因此您不应该使用它。这是有风险的,因为他可能会更改 GrpCallClass 的 [Guid](就像他在进行任何更改时应该更改的那样),这会用“未注册的类”来轰炸您的代码。这也是您期望“不”的原因。
  • 对不起,汉斯的所有问题。我认识的服务器作者,但是这是旧代码。尽管如此,他应该能够进行所需的任何更改,以使其在诞生时正常工作,而无需后期绑定电话。我现在对他如何编译他的旧代码以启用类型的编译时解析感到困惑?
猜你喜欢
  • 2017-12-01
  • 2012-05-23
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 2019-09-15
  • 2010-09-29
  • 2020-06-11
  • 1970-01-01
相关资源
最近更新 更多