通过ComInterop在C#中封送非托管dll而不注册dll

通过ComInterop在C#中封送非托管dll而不注册dll,c#,marshalling,com-interop,unmanaged,C#,Marshalling,Com Interop,Unmanaged,我有一个非托管DLL,目前正在使用COM类包装器从C#调用它 [ComImport(), Guid("75E81043-CAD5-11D3-800D-00105A5E2FA0")] public class MyObject { } [ComImport(), Guid("75E81042-CAD5-11D3-800D-00105A5E2FA0"), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface MyInt

我有一个非托管DLL,目前正在使用COM类包装器从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的源代码,并且能够在必要时对其进行修改


如果您的DLL必须是COM对象,则必须进行注册。此注册不需要由regsvr32执行。regsvr32所做的就是加载DLL,获取DllRegisterServer的地址并调用它。DllRegisterServer向注册表添加应用程序使用该对象所需的条目


如果您的DLL不需要是COM对象,您可以对其进行修改,只需导出所需的函数并p调用即可。

您需要为免注册COM设置非托管DLL。这是一个非常完整的例子。其中包括使用清单指向文件、并行程序集和一些互操作


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

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

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

  • 加载包含所需COM对象的库(DLL)
  • 找到
    DllGetClassObject
    函数
  • 调用
    DllGetClassObject
    ,将所需COM对象的CLSID传递给它,这将返回一个
    IClassFactory
    实例
  • 调用类工厂上的
    CreateInstance
    方法以获取COM对象的实例
  • 将返回的对象强制转换为要使用的接口
  • 请注意,这种方法可能有龙——它的级别相当低。如果出现任何错误,您将遇到访问冲突异常或更糟的情况。(例如,接口声明必须与COM接口完全匹配)

    我已经包含了一些示例代码,如果您想这样做,您可能会在其中使用这些代码

    使用此代码将如下所示:

    // 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。根据您的需要,您可以将该值分配给一个静态字段,使其在程序的整个生命周期内都存在。

    这可能会有所帮助:我有很多阅读工作要做,但我会尝试一下。谢谢。PInvoke方法会很棒,只是dll api远没有我的示例那么简单。我的问题更多的是它必须通过外部方法注册。。。Boo的建议可能是我最后的选择,不太准确。有这样一件事,可能就是为了这个。这正是我所希望的。谢谢,你好。感谢您提供了非常有趣的解决方案。但是,当我尝试使用您的代码时,它无法说明加载的dll中不存在DllGetClassObject。我加载的dll是一个.net 4程序集,已选中“Register for COM interop”,并为接口和类使用了正确的(我猜)属性。你能帮忙吗?