2

カード リーダーと対話する C++ DLL があります。データ構造体へのポインターが必要ですが、これは問題ではありません。ただし、C# で DLL を操作しようとすると、さまざまな問題が発生します。保護されたメモリへの書き込みエラー、getData コマンドの実行後にアプリケーションがシャットダウンするなど。

ヘッダーからの C++ メソッド

void readCard(cardData* dataBuffer);

C# コード

Wrapper.cs
public struct cardData{
   Byte[] data01;
   Byte[] data02;
}

[dllImport("card.dll")]
public static extern void readCard(ref cardData data);

form1.cs

Wrapper.cardData tmpData = new wrapper.cardData();
tmpData.data01 = new Byte[];
tmpData.data02 = new Byte[];
readCard(ref tmpData);

また、Marshal.StructureToPtr を使用して cardData を IntPtr として渡そうとしましたが、返されたときに ptr を構造体 Marshal.PtrToStructure に読み込もうとしたときにデータが返されませんでした...

多くの人が C/C++ DLL を操作しようとして問題を抱えているように見えるため、ヘルプ ファイルや他の投稿を使用してこれを解決しようとしています。私はすべてをC++で書き込もうとし、C++ DLLで解析されたデータを含む文字列を返そうとしましたが、保護されたメモリへの読み取り/書き込みエラーがスローされます

4

7 に答える 7

1

あなたのコードで私が目にする最大の問題は、あなたが byte[] メンバーに明示的なサイズを与えていないことです。このサイズ演算子がないと、マーシャラーはそれらを単純な参照型のように扱います。結果の構造体は、32 ビット プラットフォームで 8 バイトのサイズになり、ほぼ確実に保護されたメモリの書き込みにつながります。

C コードでバイト配列が固定サイズであると仮定すると、MarshalAs 属性を使用して、マネージ コードでバイト配列に同じセマンティクスを与える必要があります。これには、固定サイズを指定する必要があります。

[StructLayout(LayoutKind.Sequential)]
public struct cardData{
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
   Byte[] data01;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=300)]
   Byte[] data02;
}

300 を、配列のネイティブ コードで指定されているサイズに変更します。

また、StructLayout 属性も追加する必要があります。

于 2009-07-27T16:54:35.807 に答える
0

Ok。したがって、構造体は、構造体レイアウトで提案されているように設定されています。

Wrapper.cs

[StructLayout(LayoutKind.Sequential)]
public struct cardData{
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=99)]
   Byte[] data01;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=101)]
   Byte[] data02;
}

[DllImport("card.Dll")]
public static extern void readCard(ref cardData data);

そして今、それはただ閉じます...エラーもデータの変更もありません、アプリはただシャットダウンします。

于 2009-07-27T18:46:42.773 に答える
0

おそらく、cardData は StructLayoutAttribute を使用する必要があります。また、Dependency Walker を使用してそのメソッドの card.dll 内の場所を見つけ、それを名前付きパラメーターとして追加することもできます。

于 2009-07-27T16:43:39.777 に答える
0

あなたの Byte[] にはサイズが関連付けられていないことに気付きました。配列のサイズを知っていますか? IIRC、配列のスペースは、初期化時に割り当てる必要があります。

基地から外れている場合はお知らせください。この投稿を削除します。

于 2009-07-27T16:45:22.797 に答える
0

PInvoke Signature Toolkitは、これまで私を助けてくれました。

たとえば、次の C/C++:

struct cardData{
 byte[] data01;
 byte[] data02;
}

void readCard(cardData* dataBuffer);

それは持っています:

 System.Runtime.InteropServices.StructLayoutAttribute(  System.Runtime.InteropServices.LayoutKind.Sequential)]
 public struct cardData {

  /// byte[]
  public byte[] data01;

  /// byte[]
  public byte[] data02;
}

/// Return Type: cardData
///dataBuffer: cardData*
public delegate cardData readCard(ref cardData dataBuffer);
于 2009-07-27T16:52:10.740 に答える
0

これは、私が作成した C# の C-DLL ラッパーのスニペットです。

Yuriy が述べたように、StructLayout 属性がありません。おそらく、構造体と関数宣言でネイティブ型を使用する必要があります。これにはおそらくunsafeいくつかの場所でキーワードを使用する必要があり、それはあなたにとって受け入れられるかもしれないし、受け入れられないかもしれませんが、私にとっては問題ありませんでした.

[StructLayout(LayoutKind.Sequential)]
 public unsafe struct X_Message
 {
      public byte id;
      public byte* data;
      public DWORD data_length;
 }

 // ...

 [DllImport("x-driver.dll")]
 protected unsafe static extern int X_ReadMessage(void* h, X_Message* message);
于 2009-07-27T16:56:25.367 に答える
-1

byte[] の代わりに IntPtr を使用します。DLL はマネージド データを処理できません。

于 2009-07-27T17:00:04.297 に答える