使用INTPTR到从C#到C DLL的缓冲液进行安装结构
我整天都在敲头,希望有人能提供帮助。我需要将托管的数据结构纳入非托管的C DLL。当我查看所有内存时,看来我正在做的事情正在工作,但是C DLL(对我来说是黑匣子)正在返回一个错误,表明数据已损坏。谁能指出我的错误?
C声明
typedef struct _TAG_Data
{
void *data; // Binary data
uint32_t size; // Data size bytes
} Data;
// Parse binary data, extract int value
ParseData(Data ∗ result, uint64_t parameter, int32_t ∗ value)
托管对象:
public class MyData
{
public byte[] data;
public UInt32 size;
}
相当于移动到未托管内存的填充物:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyData_Packed
{
public IntPtr data;
public UInt32 size;
}
此时,我有一个托管的“ mydata”结构,称为 myResult ,有有效的数据需要进入DLL 。这是我在做的事情:
[DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern Int32 ParseData_Native(IntPtr result, UInt64 parameter, ref Int32 value);
IntPtr MyResultPackedPtr = new IntPtr();
MyData_Packed MyResultPacked = new MyData_Packed();
// Copy "MyResult" into un-managed memory so it can be passed to the C library.
// Allocate un-managed memory for the data buffer
MyResultPacked.data = Marshal.AllocHGlobal((int)MyResult.size);
// Copy data from managed "MyResult.data" into the unmanaged "MyResultPacked.data"
Marshal.Copy(MyResult.data, 0, MyResultPacked.data, (int)MyResult.size);
MyResultPacked.size = MyResult.size;
// Allocate unmanaged memory for the structure itself
MyResultPackedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyData_Packed)));
// Copy the packed struct into the unmanaged memory and get our pointer
Marshal.StructureToPtr(MyResultPacked, MyResultPackedPtr, false);
// Pass our pointer to the unmanaged struct, which points to the unmanaged data buffer, to the C dll
Int32 tmp = 0;
ErrorCode = ParseData_Native(MyResultPackedPtr, parameter, ref tmp);
当我查看
为了更进一步,我在C中编写了相同的代码,并且可以正常编写。 C中的二进制缓冲区中的数据与C#中的二进制缓冲区中的数据匹配,该数据由Visual Watch Studio中的Memory Watch功能进行,因此看来我的数据处理是正确的。这使我认为我通过 myResultpackedptr 的方式出了问题。不幸的是,我没有DLL的来源,无法介入它。谁能提供有关下一步尝试的建议?
I've been banging my head all day and hope someone can help. I need to marshal a managed data structure to an unmanaged C dll. When I look at all the memory it appears that what I'm doing is working, but the C dll (a black box to me) is returning an error indicating the data is corrupt. Can anyone point out my error?
C declarations
typedef struct _TAG_Data
{
void *data; // Binary data
uint32_t size; // Data size bytes
} Data;
// Parse binary data, extract int value
ParseData(Data ∗ result, uint64_t parameter, int32_t ∗ value)
Managed object:
public class MyData
{
public byte[] data;
public UInt32 size;
}
Packed equivalent for moving to unmanaged memory:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyData_Packed
{
public IntPtr data;
public UInt32 size;
}
At this point I have a managed "MyData" struct called MyResult with valid data that needs to go into the dll. Here's what I'm doing:
[DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern Int32 ParseData_Native(IntPtr result, UInt64 parameter, ref Int32 value);
IntPtr MyResultPackedPtr = new IntPtr();
MyData_Packed MyResultPacked = new MyData_Packed();
// Copy "MyResult" into un-managed memory so it can be passed to the C library.
// Allocate un-managed memory for the data buffer
MyResultPacked.data = Marshal.AllocHGlobal((int)MyResult.size);
// Copy data from managed "MyResult.data" into the unmanaged "MyResultPacked.data"
Marshal.Copy(MyResult.data, 0, MyResultPacked.data, (int)MyResult.size);
MyResultPacked.size = MyResult.size;
// Allocate unmanaged memory for the structure itself
MyResultPackedPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyData_Packed)));
// Copy the packed struct into the unmanaged memory and get our pointer
Marshal.StructureToPtr(MyResultPacked, MyResultPackedPtr, false);
// Pass our pointer to the unmanaged struct, which points to the unmanaged data buffer, to the C dll
Int32 tmp = 0;
ErrorCode = ParseData_Native(MyResultPackedPtr, parameter, ref tmp);
When I look at the unmanaged memory pointed to by MyResultPacked.data, the data is correct so the copy was good. And when I look at MyResultPackedPtr in memory, the first 8 bytes are the address of the same unmanaged memory pointed to by MyResultPacked.data (64-bit machine), and the next 4 bytes are the proper size of the data. So it appears that MyResultPackedPtr points to a valid copy of MyResultPacked. But the return value from ParseData() indicates my data must be corrupt, so I must be doing something wrong.
To take it a step further, I wrote the same code 100% in C and it works. And the data in the binary buffer in C matched the data in the binary buffer in C#, going by the memory watch feature in Visual Studio, so it appears my data handling is correct. Which makes me think something is wrong with the way I'm passing MyResultPackedPtr to the dll. Unfortunately I don't have the source for the dll and cannot step into it. Can anyone offer a suggestion on what to try next?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不明白为什么您首先需要任何此自定义编组代码。您应该能够直接使用
byte []
数组传递结构,而守卫者将整理复制。您还需要正确设置呼叫约定。
I don't see why you need any of this custom marshalling code in the first place. You should be able to pass the struct with the
byte[]
array directly, and the marshaller will sort out the copying.You also need to set the calling convention correctly.