通过ComInterop在C#中编组非托管dll而不注册DLL

时间:2012-01-06 01:00:11

标签: c# marshalling com-interop unmanaged

我有一个非托管DLL,我目前正在使用COM Class Wrapper从C#调用。

[ComImport(), Guid("75E81043-CAD5-11D3-800D-00105A5E2FA0")]
public class MyObject { }

[ComImport(), Guid("75E81042-CAD5-11D3-800D-00105A5E2FA0"),
 InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface MyInterface
{
    string EncryptString([In, MarshalAs(UnmanagedType.BStr)] string bstrOrginal);    
}

然后致电:

MyInterface obj = (MyInterface)new MyObject();
string crypt = obj.EncryptString("something");

这样可行,返回值正如我所料。但是,它要求使用regsvr32注册dll。

我正在寻找一种方法,无需使用regsvr32。优选地,通过仅具有可用的dll的副本。值得注意的是,我有非托管dll的源代码,并且必要时可以修改它。

非常感谢正确方向的推动。

3 个答案:

答案 0 :(得分:3)

我想自己做同样的事情。正如Jim提到的那样,可以获取DllRegisterServer的地址并将其调用,但仍然会使用各种条目修改您的注册表。如果您不想这样做(例如,您可能没有必要的权限来写入注册表),那么还有另一种方法。

包含一个或多个进程内COM对象的任何DLL都必须公开DllGetClassObject函数。此函数用于获取用于创建COM对象的COM类工厂的实例。你需要做的是:

  1. 加载包含所需COM对象的库(DLL)
  2. 找到DllGetClassObject功能
  3. 调用DllGetClassObject,向其传递所需COM对象的CLSID,这将返回IClassFactory实例。
  4. 调用类工厂上的CreateInstance方法以获取COM对象的实例。
  5. 将返回的对象强制转换为您要使用的界面。
  6. 请注意,有这种方法的龙 - 它是相当低的水平。如果您遇到任何问题,您将遇到访问冲突异常或更糟。 (例如,您的接口声明必须与COM接口完全匹配)。

    我在gist添加了一些示例代码,如果您想这样做,可以使用它们。

    使用此代码看起来像这样:

    // Load the library. You dispose this after you are finished with
    // all of your COM objects. 
    var library = new LibraryModule();
    library.Load("mylibrary.dll"); or whatever your dll is called
    
    var clsid = new Guid("75E81043-CAD5-11D3-800D-00105A5E2FA0");
    
    var myObject = (MyInterface)ComHelper.CreateInstance(library, clsid);
    

    请注意,如果您丢弃LibraryModule对象,则会卸载DLL。根据您的需要,您可以将值分配给静态字段,以使其在程序的生命周期内存在。

答案 1 :(得分:2)

您需要为免注册COM设置非托管DLL。有一个非常完整的walkthrough here,有很多例子。除其他外,它涉及使用清单指向文件,并排程序集和一些互操作。

演练中的一个重要注意事项是,客户端的初始设置需要注册,但不能在以后注册。

答案 2 :(得分:1)

如果您的DLL必须是COM对象,则必须注册它。此注册不需要由regsvr32执行。所有regsvr32都会加载DLL,获取DllRegisterServer的地址并将其调用。 DllRegisterServer将必要的条目添加到注册表中,以便应用程序使用该对象。

如果你的DLL不需要是一个COM对象,你可以修改它只是导出你需要的函数并调用它(它们)。