gpt4 book ai didi

C# 将大型结构编码到 C DLL

转载 作者:行者123 更新时间:2023-11-30 18:34:32 25 4
gpt4 key购买 nike

我正在尝试访问某些 DLL 导出的函数(用于访问某些特定硬件)。使用 DLLImport 和简单数据类型访问函数是可行的。但是对于某些函数,我需要传递一些相当大的结构。为了克服自动编码的大小限制,我想出了使用 IntPtr。

typedef struct
{
double value[MemDepth];
double offset[MemDepth];
unsigned long start;
BOOL active;
} RegisterData;

typedef struct
{
RegisterData a,b,c,d,e,f,g,h;
BOOL active;
BOOL test;
} Register;

这就是我尝试将它们放入 C# 的方式:

[StructLayout(LayoutKind.Sequential)]
public struct RegisterData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = defines.MemDepth)]
public double[] value;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = defines.MemDepth)]
public double[] offset;

UInt32 start;

[MarshalAs(UnmanagedType.U1)]
bool active;
}

[StructLayout(LayoutKind.Sequential)]
public struct Register
{
RegisterData a,b,c,d,e,f,g,h;
[MarshalAs(UnmanagedType.U1)]
bool active;
[MarshalAs(UnmanagedType.U1)]
bool test;
}

我尝试调用的函数在 DLL 中如下所示:

long ResetControl(Register* control);

我翻译成:

[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 Reset(IntPtr control);

然后我尝试像这样调用函数:

public Int32 lib_Reset(ref Register control)
{
int size = System.Runtime.InteropServices.Marshal.SizeOf(control);

//IntPtr ptr = System.Runtime.InteropServices.Marshal.FreeHGlobal(size);
IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(size);

System.Console.WriteLine("requested size of: " + size); // shows correct

System.Runtime.InteropServices.Marshal.StructureToPtr(control, ptr, false);

System.Console.WriteLine("mem done");

Int32 ret = Reset(ptr);

System.Console.WriteLine("called reset");

System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, control);
System.Console.WriteLine("transfered back");

System.Runtime.InteropServices.Marshal.FreeCoTaskMem(ptr);
//System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);

System.Console.WriteLine("freeed mem");
ptr = IntPtr.Zero;

return ret;
}

这会导致“堆已损坏”。当调用 DLLs Reset 函数时。我已经尝试过不同的方法,但没有奏效。

编辑:

我现在通过使用 IntPtr 方法清理和重建项目来让它工作。它不能直接使用“ref”工作。使用“ref”时,我总是得到:

 Cannot marshal 'parameter #1': Internal limitation: structure is too complex or too large.

我现在执行以下操作,将结构体转换为指针并返回:

public Int32 lib_Reset(ref Register control)
{
int size = Marshal.SizeOf(control);
IntPtr ptr = Marshal.FreeHGlobal(size);
Marshal.StructureToPtr(control, ptr, false);
Int32 ret = Reset(ptr);
control = (Register)Marshal.PtrToStructure(ptr, typeof(control));
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
return ret;
}

这样我就可以调用 Reset,但函数似乎什么也没做。

Register reg = new Register();

reg.active = true;
System.Console.WriteLine(reg.active); // .active = true
lib_Reset(ref reg); // should set .active = false
System.Console.WriteLine(reg.active); // .active = true

Reset 函数应该初始化 Register 结构。因此它将 active 设置为 false。但在上面显示的代码中,active 的值没有改变。我用一个整数值进行了同样的测试。它也没有改变。

我希望这里的任何人都能为我指明访问数据的正确方向。

谢谢,托拜厄斯

最佳答案

现在可以了。清理和重建项目成功了。它现在正在使用 IntPtr 方法。但 Reset 函数不会影响结构中的值。

从 DLL 的代码中我知道元素应该被初始化为一些值。但是元素的值从调用前到调用后都没有变化:

Register reg = new Register();

reg.active = true;
System.Console.WriteLine(reg.active); // .active = true
lib_Reset(ref reg); // should set .active = false
System.Console.WriteLine(reg.active); // .active = true

其他元素同理。从结构到指针再从指针到结构的转换有问题吗?

如果我取一些整数类型的值,并在调用前将其设置为 4,则调用后将为 4。所以之前设置的值被保留。

关于C# 将大型结构编码到 C DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15971637/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com