gpt4 book ai didi

c# - 来自 PInvoke 结构/函数的奇怪错误

转载 作者:行者123 更新时间:2023-11-30 21:13:25 24 4
gpt4 key购买 nike

我目前正在为 C++ API 编写 C# 包装器,但是特定结构和依赖于此结构的函数在调试时一直出现非常奇怪的错误。

C++ 结构:

typedef struct  
{
unsigned __int handle;
char name[80];
unsigned int unique_ID;
} DeviceInfo;

后面跟着这个函数:

int __stdcall get_device_info(DeviceInfo di[], const int length_of_di_array, int* p_numValidDevices);

结构和函数是这样导入的:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
public struct DeviceInfo
{
public UInt32 handle;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 80)]
public String name;
public UInt32 unique_ID;
}

[DllImportAttribute("MyC++API.dll", EntryPoint = "get_device_info", CallingConvention = CallingConvention.StdCall)]
public static extern int get_device_info(ref DeviceInfo di, int length_of_di_array, ref numValidDevices);

此结构和函数的预期用途只是从我正在访问的板中获取一些设备信息。目前我无法访问 C++ 中的函数体,所以我只能假设它 100% 正常工作(在 C++ 中工作正常)。

问题是,当我使用函数遍历结构数组时,它会输出我正在寻找的数据,但也会在运行时开始失败,给我各种错误窗口。

C#代码:

static void Main()  
{
int numValidDevices = 0; //initialize variable
DeviceInfo[] di = new DeviceInfo[16]; //max of 16 devices

for (int i = 0; i < numValidDevices; ++i) //sorts through all validated devices
{
rc = get_device_info(ref di[i], 16, ref numValidDevices); //accesses each device element and returns the data
Console.WriteLine("Handle: {0}\nName: {1}\nUnique ID: {2}", di[i].handle, di[i].name, di[i].unique_ID);
}
Console.ReadLine(); //stops console from closing prematurely
API_close(); //custom close function from the C++ API
}

调试时出错(仍然显示信息):“System.dll 中发生类型为‘System.Threading.ThreadStateException’的未处理异常

附加信息:线程尚未启动。"

“mscorlib.dll 中出现类型为‘System.ExecutionEngineException’的未处理异常”

调试时出错(没有显示信息,程序执行失败):“在 mscorlib.dll 中发生类型为‘System.AccessViolationException’的未处理异常

附加信息:试图读取或写入 protected 内存。这通常表明其他内存已损坏。”

关闭控制台窗口时:“‘0x7c9113c0’处的指令引用了‘0x00000000’处的内存。无法‘写入’内存。” (有时说“读”而不是“写”)。

我对 PInvoke 进行了大量研究并发现了 Microsoft InteropAssistant application 和各种堆栈溢出文章,例如 this one ,而 this post 似乎更接近我正在做的事情,但我仍在深入研究如何使用编码(marshal)。 CoTaskMemAlloc/Free,看看它是否会做任何事...

到目前为止,我的结构和函数都是正确的,我已经尝试更改结构以使用 IntPtr 但它不返回 di.name 值并且 di.unique_ID 变得乱码(奇怪的是 di.句柄保持有效)

C#代码:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
public struct DeviceInfo
{
public UInt32 handle;
IntPtr p_name;
public String name { get { return Marshal.PtrToStringAnsi(p_name); } }
public UInt32 unique_ID;
}

预期输出:

Handle: 3126770193  
Name: DEVICE_A
Unique ID: 12345678

IntPtr 输出:

Handle: 3126770193  
Name:
Unique ID: 1145128264

奇怪的是,使用 IntPtr 不会导致上述任何错误,并且运行良好。这让我相信问题出在将 C++ char 编码为字符串,但我不确定问题是否出在编码、内存管理(没有?),或者我没有完全理解的东西。

非常感谢任何和所有的反馈,我已经被这个问题难住了几个星期了......

最佳答案

您获得的异常表明您正在调用的非托管代码正在破坏垃圾收集堆。这不是 Crystal 为什么,但你不会给 pinvoke 编码器很多机会做正确的事。它无法正确固定阵列。首先正确声明函数,它需要一个数组,所以声明一个:

[DllImportAttribute("MyC++API.dll", CallingConvention = CallingConvention.StdCall)]  
public static extern int get_device_info(
DeviceInfo[] di,
int length_of_di_array,
out int p_numValidDevices
);

您对 DeviceInfo 的第一个声明是正确的,第二个不是,因为该字符串不是指针。

关于c# - 来自 PInvoke 结构/函数的奇怪错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6874147/

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