在没有类型库的情况下使用C#中的COM dll
我需要使用很久以前在Delphi中开发的COM组件(dll)。 问题是:dll不包含类型库……并且.NET中的每个互操作function(例如,TlbImp)似乎都依赖于TLB。 这个组件已经在Delphi程序中使用了很多年没有问题,因为“使用Delphi的COM对象并不是什么问题,因为我们知道接口”(引用Delphi开发人员)。
有没有办法在没有TLB的情况下从c#中使用这个DLL? 我尝试使用DLL作为非托管,但它导出的唯一方法是DllUnregisterServer
, DllRegisterServer
, DllCanUnloadNow
和DllGetClassObject
。 我知道我将要使用的类和函数的名称,如果这可以有任何帮助。
更新:我已经尝试过实施Jeff的建议,但是我收到了这个错误:
“无法将’ComTest.ResSrvDll’类型的COM对象强制转换为接口类型’ComTest.IResSrvDll’。此操作失败,因为对于具有IID'{75400500-939F-11D4-9E44-0050040CE72C}的接口的COM组件上的QueryInterface调用’由于以下错误而失败:不支持此类接口(来自HRESULT的exception:0x80004002(E_NOINTERFACE))。“
这就是我所做的:
我从Delphi中的一个人那里得到了这个接口定义:
unit ResSrvDllIf; interface type IResSrvDll = interface ['{75400500-939F-11D4-9E44-0050040CE72C}'] procedure clearAll; function ResObjOpen(const aClientID: WideString; const aClientSubID: WideString; const aResFileName: WideString; aResShared: Integer): Integer; {safecall;} ... end; implementation end.
从这个我做了这个界面
using System.Runtime.InteropServices; namespace ComTest { [ComImport] [Guid("75400500-939F-11D4-9E44-0050040CE72C")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IResSrvDll { int ResObjOpen(string aClientID, string aClientSubID, string aResFileName, int aResShared); } }
而这个coclass(得到了delphi人的指导)
using System.Runtime.InteropServices; namespace ComTest { [ComImport] [Guid("75400503-939F-11D4-9E44-0050040CE72C")] public class ResSrvDll { } }
UPDATE
Jeff的解决方案是实现这一目标的方法。 但值得注意的是,接口定义必须与COM组件完全匹配! 即。 相同的顺序,相同的名称等
您只需要CLS_ID和接口ID。 我在博客上写过这个具体问题:
“ 在.NET中使用模糊的Windows COM API ”
在VB.Net中写一个包装器。 VB.Net支持真正的后期绑定(没有凌乱的reflection)。 你需要的只是progId。 您还应该实现IDisposable以明确管理组件生命周期。
您经常遇到一个没有类型库(Delphi或其他)支持的接口实现。 Shell扩展就是一个例子。
您基本上需要进行Windows API调用以通过正确的COM函数调用来创建实例。 API将通过您之前提到的导出函数来管理DLL。
您需要在C#代码中重新创建接口定义,但之后您只需创建对象,将其强制转换为接口,并且与其他任何东西都没有区别。 这里唯一真正的警告是,根据您的使用情况,您可能会遇到一些线程问题需要处理,因此请检查用于DLL的“线程模型”并考虑您的使用情况。
这是一个关于使用非基于TLB的接口的教程的链接。 教程
是的,不是。
所有C#(和任何CLR语言)需要与COM对象进行通信才是兼容的接口签名。 通常指定接口的方法,GUID和公寓样式。 如果您可以将此定义添加到代码库中,则不需要TLB。
该声明附带一个小警告。 我相信如果您尝试在公寓边界使用COM对象并且没有合适的TLB注册,您将遇到麻烦。 我不能100%记住这一点。
您也可以进行后期绑定 ,然后通过reflection调用方法( myObject.InvokeMember("NameOfTheMethod", options, params, etc.)
)。
但是,包装器应该提供更好的性能和更快的编组。
我怀疑dynamic
关键字(C#4.0)会实现这一点。 如果是这样,它将给出大致相当于调用方法的结果,即Groo如何建议。
如果你已经设法创建了一个对象的实例,那么你已经超越了第一个主要障碍!
现在试试这个:
myObject.GetType().InvokeMember( "ResObjOpen", // method name goes here BindingFlags.InvokeMethod, null, myObject, new object[] { someClientID, // arguments go here someSubId, somFileName, someInt} );
我认为您可能需要这样做的原因是Delphi COM对象不是“双重”对象。 它可能只支持后期绑定,即您在上面看到的调用类型。
(在C#4.0中,他们使用dynamic
关键字使这更容易。)
编辑:刚发现一些非常可疑的东西。 接口的IID和对象本身的CLSID看起来是一样的。 那是不对的。
鉴于您已成功创建对象,它似乎是对象的CLSID。 所以这不是正确的IID。 你需要回到你的Delphi人员并要求他们告诉你IResSrvDll
接口的IID是什么。
再次编辑:您可以尝试从ComInterfaceType
更改指定的枚举成员。 应该有IDispatch
和“dual” – 虽然你的对象不支持IDispatch
,但这些都不是正确的选择。 IUnknown
设置(显示在示例代码中)应该有效 – 表明IID是错误的。
上述就是C#学习教程:在没有类型库的情况下使用C#中的COM dll分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1019674.html