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

好的。因此,结构已按照结构布局的建议进行设置。

包装器.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 签名工具包过去曾帮助过我。

例如以下 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

使用 IntPtr 而不是 byte[]。您的 DLL 无法处理托管数据。

于 2009-07-27T17:00:04.297 回答