使用INTPTR到从C#到C DLL的缓冲液进行安装结构

发布于 2025-02-13 20:54:26 字数 2730 浏览 0 评论 0原文

我整天都在敲头,希望有人能提供帮助。我需要将托管的数据结构纳入非托管的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);

当我查看myResultpacked.data指向的不受管理的内存时,数据是正确的,因此副本很好。当我查看记忆中的myResultpackedptr 时,前8个字节是 myResultpacked.data(64位机),接下来的4个字节是数据的适当大小。因此,看来 myResultpackedptr 指出了 myResultpacked 的有效副本。但是, parsedata()() 的返回值表明我的数据必须损坏,所以我必须做错了什么。

为了更进一步,我在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 技术交流群。

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

发布评论

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

评论(1

む无字情书 2025-02-20 20:54:26

我不明白为什么您首先需要任何此自定义编组代码。您应该能够直接使用byte []数组传递结构,而守卫者将整理复制。

您还需要正确设置呼叫约定。

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyData_Packed
{
    public byte[] data;
    public UInt32 size;
}

[DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CallingConvention = CallingConvention.CDecl)]
private static extern int ParseData_Native(ref MyData_Packed result, ulong parameter, out int value);
var MyResultPacked = new MyData_Packed
{
    data = MyResult,
    size = MyResult.size,
};

ErrorCode = ParseData_Native(ref MyResultPacked, parameter, out var tmp);

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.

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyData_Packed
{
    public byte[] data;
    public UInt32 size;
}

[DllImport("Some.dll", EntryPoint = "ParseData", SetLastError = true, CallingConvention = CallingConvention.CDecl)]
private static extern int ParseData_Native(ref MyData_Packed result, ulong parameter, out int value);
var MyResultPacked = new MyData_Packed
{
    data = MyResult,
    size = MyResult.size,
};

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