2012-01-06 18 views
3

現在、COMクラスラッパーを使用してC#から呼び出しているアンマネージDLLがあります。DLLを登録せずにC#でComInteropを使用して管理されていないDLLをマーシャリング

[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"); 

をこれは動作しますが、戻り値があります。ただし、dllはregsvr32に登録されている必要があります。

私はregsvr32を必要とせずにこれを行う方法を探しています。好ましくは、dllのコピーを入手するだけです。注目すべきことは、アンマネージドDLLのソースと、必要に応じてそれを変更する機能があることです。

正しい方向に押していただければ幸いです。

+1

これは役立つかもしれません:http://msdn.microsoft.com/en-us/library/windows/desktop/ms694515(v=vs.85).aspx –

+0

私は読むことがたくさんありますが、私はこれを試してみてください。ありがとうございました。 – Jon

答えて

3

私は同じことを自分でやりたいと思っています。ジムが言及したように、DllRegisterServerのアドレスを取得して呼び出すことは可能ですが、それでもレジストリはさまざまなエントリで変更されます。これをやりたくない場合(たとえば、レジ​​ストリに書き込むために必要な権限がないなど)、別の方法があります。

1つ以上のインプロセスCOMオブジェクトを格納するDLLは、DllGetClassObject関数を公開する必要があります。この関数は、COMオブジェクトを作成するために使用されるCOMクラスファクトリのインスタンスを取得するために使用されます。何をする必要がある:

  1. は希望COMオブジェクト
  2. DllGetClassObject機能
  3. コールDllGetClassObject、それに所望のCOMオブジェクトのCLSIDを渡し、この意志を見つけ収容するライブラリ(DLL)をロードしますIClassFactoryインスタンスを返します。
  4. クラスファクトリでCreateInstanceメソッドを呼び出して、COMオブジェクトのインスタンスを取得します。
  5. 返されたオブジェクトを使用するインターフェイスにキャストします。

このアプローチのドラゴンがあることに注意してください。かなり低いレベルです。何か間違ったことがあれば、アクセス違反の例外が発生するか、悪化します。 (たとえば、インターフェイス宣言は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をアンロードすることに注意してください。必要に応じて、静的フィールドに値を割り当てて、プログラムの存続期間中存在するようにすることができます。

+0

これはまさに私が望んでいたものです。ありがとうございました。 – Jon

+0

こんにちは。非常に興味深い解決法をありがとう。しかし、あなたのコードを使用しようとすると、ロードされたdllにDllGetClassObjectが存在しないというエラーが発生します。私がロードしたdllは、 "Register for COM interop"がチェックされ、インターフェイスとクラスの適切な(私が推測する)属性を使用している.net 4アセンブリです。助けてもらえますか? – Elias

1

DLLをCOMオブジェクトにする必要がある場合は、そのDLLを登録する必要があります。この登録は、regsvr32によって実行する必要はありません。すべてのregsvr32はDLLをロードし、DllRegisterServerのアドレスを取得して呼び出します。 DllRegisterServerは、アプリケーションがオブジェクトを使用するために必要なエントリをレジストリに追加します。

DLLがCOMオブジェクトである必要がない場合は、必要な機能をエクスポートしてp-invoke(単に)するだけで、DLLを変更できます。

+0

PInvokeメソッドは、dll apiが私の例ほど単純ではないことを除いて素晴らしいでしょう。私の問題は、それが外部の方法で登録されなければならないという点でより多くでした...ブーの提案は、私が終わりに行く方法かもしれません。 – Jon

+0

あまり正確ではありません。 [登録無料COM](http://msdn.microsoft.com/en-us/library/ms973913.aspx)のようなものがあります。 – ssube

2

登録不要のCOM用にアンマネージDLLを設定する必要があります。たくさんの例があるかなり完全なwalkthrough hereがあります。とりわけ、マニフェストを使用してファイル、サイド・バイ・サイド・アセンブリー、およびいくつかのinteropを指すことが必要です。

ウォークスルーで重要な点は、クライアントの初期セットアップでは登録が必要ですが、それ以降ではありません。

関連する問題