2011-12-23 60 views
0

私はC++で関数を持っていて、DLLでエクスポートしました。 関数C#の配列として配列を含む構造体ポインタを渡す

LONG LOGIN(LPDEVINFO info); 

LPDEVINFOの構造体がある:

struct{ 
     BYTE sSerialNumber[20]; 
} *LPDEVINFO; 

LPDEVINFOパラメータを渡すために、私は、マネージドコードでクラスを定義した:

class DEVINFO{ 
    Byte[] sSerialNumber = new Byte[20]; 
} 

、次いでP /呼び出しをこのように:

[DllImport ('MyDll.dll')] 
public static extern Int32 LOGIN(DEVINFO info); 
その後、

とは、C#でそれを呼び出す:私は、問題は、アレイsSerialNumberによって引き起こされると考え

An unhandled exception of type 'System.AccessViolationException' occurred in WindowsFormsApplication1.exe 

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 

:私はこのコードを実行すると

DEVINFO info = new DEVINFO(); 
Int id = LOGIN(info) 

、私はエラー以下ました。しかし、私はそれを正しい方法で定義する方法を知らない。

ありがとうございます! Fixed Size Buffersを参照してください

public unsafe struct DevInfo 
{ 
    public fixed byte sSerialNumber[20]; 
} 

+0

C++で 'LONG'が64ビット整数型として定義されている場合、関数を' extern Int64 LOGIN(DEVINFO info);または 'extern long LOGIN(DEVINFO info);としてエクスポートする必要があります。 '。あなたの 'DEVINFO'クラスについては、構造体にして、' [MarshalAs(UnmanagedType.ByValArray、SizeConst = 20)] 'という属性をバイト配列に適用します。 [この回答を参照してください](http://stackoverflow.com/questions/1354275/marshaling-a-byte-array-to-ac-sharp-structure) –

+0

@ Jim 'LONG'はWindowsではCとC++の32ビット整数です。 –

+0

ああ、私はそれが再定義されて見たことがあります。私はそれがなぜあるのか分からない。 –

答えて

3

は、固定サイズのバッファが含まれている構造体を宣言するfixedキーワードを使用します。また

、次のように関数を宣言し、ポインタ(ネイティブ側LPDEVINFOに相当)によって構造体を渡す:

[DllImport ('MyDll.dll')] 
public static extern Int32 LOGIN(ref DevInfo info); 

とそれを呼び出す:

DevInfo info = new DevInfo(); 
int id = LOGIN(ref info) 
+0

キーワードが "fixed"の場合、エラーが発生するCS0214:ポインタと固定サイズのバッファは、安全でないコンテキストでのみ使用される可能性があります – englefly

+0

@englefly struct宣言(my answerを修正)に 'unsafe'を、おそらく)それを使用するコードで。また、C#プロジェクトのプロパティで安全でないコードを有効にする必要があります。 –

0

機能が期待されています構造体へのポインタであり、実際の構造体ではありません。

Marshal.StructureToPtr()関数を使用して、構造体をIntPtrに変換します。 C#で

例:

[DllImport("MyDll.dll")] 
public static extern Int32 LOGIN(IntPtr info); 

... 

DEVINFO info = new DEVINFO(); 
IntPtr infoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(info)); 
Marshal.StructureToPtr(info, infoPtr, false); 
LOGIN(infoPtr); 

これはOUTパラメータである場合は、それはそれは呼び出し先によって変更されるので、関数が呼び出された後、あなたは、あなたがMarshal.PtrToStructureを使用し、そこから読む必要があります以下のように管理構造に戻ってそれを読むために:

DEVINFO info = (DEVINFO)Marshal.PtrToStructure(infoPtr, typeof(DEVINFO)); 
+1

structの代わりに 'class'を使用すると、質問のコードに従って、ポインタが渡されます。それは問題ではありません。 –

+0

ブラッドリーの答えが良いです。シンプルなリファレンス機能では不十分だった構造体へのポインタの配列へのポインタのような、奇妙な相互運用シナリオでは、単にStructureToPtrを使用することに慣れています。 –

+0

'class'の使用は問題ありません。私はいつもそれをする。 –

3

を私はここUmanagedType.ByValArrayを使用します。

class DEVINFO { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)] 
    public byte[] sSerialNumber; 
} 

それ以外の場合は、すべて私にはうまく見えます。特に、structではなく、classでこれを行うのは問題ありません。

+0

私はこの回答のdownvoteとブラッドリーの答えのdownvoteに困惑しています。私はどちらかに間違った何かを見ることはできません。間違っているものがあれば修正したいと思います。 –

+0

これは私がそれを解決する方法です。ありがとう。 –

+0

ありがとう。それはうまく動作します! – englefly

関連する問題