编组问题

发布于 2024-07-29 09:33:45 字数 853 浏览 5 评论 0原文

我有一个与读卡器交互的 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 读入 struct Marshal.PtrToStructure 时,它​​没有返回任何数据...

我'我一直在尝试使用帮助文件和其他帖子来解决这个问题,因为似乎很多人在尝试使用 C/C++ DLL 时遇到了麻烦。 我什至尝试用 C++ 编写整个内容,并让它返回一个字符串,其中包含在 C++ DLL 中解析的数据,但这会引发读/写受保护内存错误

I have a C++ DLL that interacts with a card reader. It requires a pointer to a data struct, which isn't a problem to do. However, when trying to interact with the DLL in C# I'm getting all kinds of problems. Errors writing to protected memory, the application just shutting down after executing the getData command, etc. Here's what we have.

C++ Method from header

void readCard(cardData* dataBuffer);

C# code

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

I've also tried passing cardData as an IntPtr using Marshal.StructureToPtr, which didn't return any data when I returned tried to read the ptr into a struct Marshal.PtrToStructure...

I've been trying to work this out using the help files and other posts because it seems that alot of people have trouble trying to work with C/C++ DLLs. I even tried to write the whole thing in C++ and have it return a string with the data parsed in the C++ DLL but that throws a reading/writing to protected memory error

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

终止放荡 2024-08-05 09:36:58

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

Use IntPtr instead of byte[]. Your DLL can't handle managed data.

我是有多爱你 2024-08-05 09:36:33

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

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

现在它刚刚关闭...没有错误,数据没有变化,应用程序只是关闭。

Ok. So the struct has been set as suggested with the struct layout.

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

And now it just closes... No errors, no change in data, the app just shuts down.

温折酒 2024-08-05 09:36:08

下面是我用 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);

Here's a snippet of a C-DLL wrapper in C# that I've made.

Like Yuriy mentioned, you're missing a StructLayout attribute, and you probably ought to be using native types in your struct and your function declaration. This will probably require you to use the unsafe keyword in a few places, which may or may not be acceptable to you - but it was fine for me.

[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);
风渺 2024-08-05 09:35:44

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

The PInvoke Signature Toolkit has helped me in the past.

For example the following C/C++:

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

void readCard(cardData* dataBuffer);

It has:

 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);
记忆で 2024-08-05 09:35:20

我注意到你的 Byte[] 没有与它们相关的大小。 你知道数组的大小应该是多少吗? IIRC,数组的空间需要在初始化时分配。

如果我偏离了基地,请告诉我,我会删除这篇文章。

I noticed that your Byte[] have no size associated with them. Do you know what size the arrays are supposed to be? IIRC, the space for the arrays needs to allocated when they're initialized.

If I'm way off base, let me know and I'll delete this post.

夏日浅笑〃 2024-08-05 09:35:01

也许您的cardData需要使用StructLayoutAttribute。 您还可以使用 Dependency Walker 查找该方法在 card.dll 中的位置,并将其添加为命名参数。

Maybe your cardData needs to use the StructLayoutAttribute. Also you can use Dependency Walker to find the location in card.dll for that method, and add that as a named parameter.

幼儿园老大 2024-08-05 09:34:43

我在您的代码中看到的最大问题是您没有为 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 属性。

The biggest problem I see with your code is that you have not given your byte[] members an explicit size. Without this size operator, the marshaller will treat them just like a simple reference type. The resulting struct will have a size of 8 bytes on a 32 bit platform and will almost certainly lead to writing of protected memory.

Assuming the byte arrays are of a fixed size in the C code, you should use the MarshalAs attribute to give the byte arrays the same semantics in managed code. This does entail giving them a fixed size.

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

Change 300 to be whatever size is specified in the native code for the array.

Also you should add the StructLayout attribute as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文