2011-01-21 21 views
3

アンマネージVisual C++でDLLを作成しましたが、C#アプリケーションとC++アプリケーションの両方で動作させるのに少し問題があります。ここではC++ DLLでのプロトタイプは次のようになります。マネージコードからアンマネージDLL関数を呼び出す

extern "C" __declspec(dllexport) int WINAPI ZBNConnect(UCHAR dev, LPARAM hWnd, ZBCallbackFn rfn, ZBCallbackFn nfn, int DevType, byte * DevAddr, ZBCallbackFn dfn); 

私のC#アプリケーションは、機能には問題をリンクすることはできませんが、それは例外がスローされる関数を呼び出そうとした場合:

catch (Exception e) { /* ... */ } 

e.Message = "オブジェクト参照がオブジェクトのインスタンスに設定されていません。"

奇妙なことに、DLLのプロトタイプからWINAPIを取り出して再コンパイルすると、C#アプリケーションは問題なくこの関数を呼び出します。残念ながら、WINAPIは、その関数がC++アプリケーションでどのように定義されているかによって残る必要があります。

機能は、現在、このようなC#アプリケーションでプロトタイプされています

public delegate int ZBNConnectDelegate(uint dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, uint DevType, byte[] DevAddr, ZBdebugCallbackDelegate dfn); 
public ZBNConnectDelegate ZBNConnect; 

procName = "ZBNConnect"; 
fUintPtr = Kernel32.GetProcAddress(dllHandle, procName); 

if (fUintPtr == UIntPtr.Zero) 
{ 
    throw new ArgumentException(procName); 
} 

fIntPtr = unchecked((IntPtr)(long)(ulong)fUintPtr); 
ZBNConnect = (ZBNConnectDelegate)Marshal.GetDelegateForFunctionPointer(fIntPtr, typeof(ZBNConnectDelegate)); 

どのように私はこの作業を取得するためにC#アプリケーションを変更することができますか?ありがとう。

EDIT:追加情報

静的リンク([DllImport...])接続されているハードウェアをサポートしている別のDLLを実行時にロードされたシステムに接続されている依存しているハードウェアであるためオプションではありません。どちらのDLLも同じAPI呼び出しを持ちます。

+1

これは –

+0

全く違うDLL地獄ではありませんあなたはプロトタイプではexternを配置しようとしましたか? – bratao

+1

それでは、 'ZBNConnect'をどのように初期化して、アンマネージ関数を指し示すのでしょうか?書かれているように、それは 'ヌル 'になるでしょう。なぜあなたはP/Invoke( '[DllImport] static extern')を使うのですか? –

答えて

0

WINAPIを関数の宣言と定義に追加すると、DLLの関数名がマングルされていることが判明しました。残念ながら、既にデプロイされたアプリケーションとの互換性を維持するには、WINAPIが必要でした。修正プログラムは、リンカに余分な輸出を追加することでした:

#pragma comment(linker, "/EXPORT:[email protected]") 
3

何かが基本的に間違っています。関数がコールバックであるかのように、デリゲートを宣言しました。コールバックのようには見えませんが、[DllImport]で宣言する必要があります。あなたのように動作させるためには、LoadLibraryとGetProcAddress()をピンボケしなければなりません。フードの中で[DllImport]は何をしますか?私はあなたがそれを使用して表示されません。

+0

こんにちはハンス。 OPにいくつかの追加情報を追加しました。 –

+0

さて、実際にはGetProcAddressを使用します。まあ、アンマネージコードは、ヌルポインタでノーズダイビングをしています。多数の候補があり、関数の引数はすべてポインタです。あなたはそれをデバッグする必要があります。私はあなたが既にアンマネージコードをデバッグする方法を知っていると思いますよね? –

+0

私はDLLへのステップアップを試みていませんが、管理されたコード 'fIntPtr'と' ZBNConnect'に値(NULLではない)が割り当てられています。 –

0

WINAPIマクロは呼び出し規約を変更します。

あなたはネイティブ呼び出しを行う際に1バイト値とC#ののuintのあなたは、スタックを4中傷しているされているC++ UCHARs(DEV)

[UnmanagedFunctionPointer(CallingConvention = CallingConvention.StdCall] 
public delegate Int32 ZBNConnectDelegate(Byte dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, Int32 DevType, Byte[] DevAddr, ZBdebugCallbackDelegate dfn); 
0

extern "C" __declspec(dllexport) int WINAPI ZBNConnect(UCHAR dev, LPARAM hWnd, ZBCallbackFn rfn, ZBCallbackFn nfn, int DevType, byte * DevAddr, ZBCallbackFn dfn);

public delegate int ZBNConnectDelegate(uint dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, uint DevType, byte[] DevAddr, ZBdebugCallbackDelegate dfn);

をお試しください何らかの理由で、WINAPIはあなたがそれを手放すことを許しています。また、通常のP/Invoke DllImportを実行する代わりに、このようなデリゲートを使用すると、マーシャリングの仕方をカスタマイズできないため、問題が発生する可能性が高くなります。

+1

マシンワードより小さい値渡しの引数は、スタックに置かれたときに拡大されます。 –

+0

うん、私はあなたが100%保証されているとは確信していませんが、WINAPIがなぜ動作するのかは説明していますが、いい視点ね。 –

0

私は2 DLLIMPORTのdeclaractionsを使用し、C#の側から、実行時に正しいDLLを検出できた場合:

[DllImport("Dll1.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ZBNConnect")] 
extern static int ZBNConnect1(...) 
[DllImport("Dll2.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ZBNConnect")] 
extern static int ZBNConnect2(...) 

public static int ZBNConnect(...) 
{ 
    if (UseDll1) 
     return ZBNConnect1(...); 
    return ZBNConnect2(...); 
} 

P /呼び出しは、動的ローディングによって渡されます。 ZBNConnect1を決して呼び出さないと、Dll1.dllはロードされず、その逆もありません。

DLLIMPORTに

追加エントリーポイント=更新しました。

関連する問題