从TLB程序集创建DLL

时间:2014-03-28 11:25:14

标签: c# dll com interop

使用dynamic关键字(more information here)从C#调用COM TLB方法时遇到一些性能问题。 Scince我没有任何运气试图优化这样的调用我现在正在寻找一种方法将我的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();

但这会给出编译时错误:

  

Interop type' 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?

  3. 感谢您的时间。

1 个答案:

答案 0 :(得分:4)

  

我使用regasm.exe注册此.dll

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

  

和空接口GrpCall

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

您无法做任何事情来避免这种情况,您必须与服务器作者合作才能取得成功。一个非常喜欢奶酪的顶部是它的方法,要求双界面。期待“不”,你可能会得到“是”。