调用非托管DLL的UP_GetProgList函数遇Access Violation及数组取值问题
问题:C# P/Invoke调用非托管DLL函数
UP_GetProgList触发Access Violation,如何正确获取数组结果? 我有一个非托管DLL up_control64.dll,其中包含函数:
int __stdcall UP_GetProgList(int prog_type, int *sn_list, int count, int *count_returned)
我最初尝试的P/Invoke声明如下:
[DllImport(@"C:\Program Files (x86)\ASIX\UP\up_control64.dll")] private static extern int UP_GetProgList(int prog_type, out int[] sn_list, int count, out int count_returned);
调用代码:
[DllImport(@"C:\Program Files (x86)\ASIX\UP\up_control64.dll")] private static extern int UP_GetProgList(int prog_type, out int[] sn_list, int count, out int count_returned); const int PROG_FORTE = 2; void Main() { var list = new int[20]; var count = 0; var result = UP_GetProgList(PROG_FORTE, out list, 20, out count); foreach (var sn in list) { Console.Out.WriteLine(sn); } }
调用时触发了Access Violation错误。
补充:函数文档说明
1.3.11 UP_GetProgList
该函数返回可用编程器列表,仅当库未被任何编程器占用时才返回列表。调用此函数会清除UP_ProgConfig函数设置的配置。
函数定义:
int __stdcall UP_GetProgList(int prog_type, int *sn_list, int count, int *count_returned);参数:
- prog_type - 根据常量选择编程器类型。
- sn_list - 整数数组,返回可用FORTE编程器的序列号列表,序列号以24位值形式返回,与UP软件中显示的一致。
- count - 指定要读取的序列号数量的变量。
- count_returned - 返回sn_list中实际返回的序列号数量的变量。
返回值:
- ERR_NONE - 函数调用成功。
- ERR_PROG_BUSY - 编程器正忙。
- ERR_DRIVER - 编程器驱动错误。
函数会在sn_list中返回可用编程器列表,并在count_returned中返回实际返回值的数量。
示例:
int prog_list[20]; int prog_list_count; int FuncRes; FuncRes=UP_GetProgList(PROG_FORTE, prog_list, 20 , &prog_list_count);
补充2:部分可行的修改
如果将声明修改为以下形式,调用可以正常运行,但只能获取第一个值:
[DllImport(@"C:\Program Files (x86)\ASIX\UP\up_control64.dll")] private static extern int UP_GetProgList(int prog_type, out int sn_list, int count, out int count_returned);
请问如何获取数组中的其他值?
解决方案
错误原因
最初的声明用out int[] sn_list不符合C函数的参数语义:C中int* sn_list是传入已分配好的数组指针,让函数往数组内写入数据;而out int[]会让P/Invoke尝试将非托管内存的数组封送为新的托管数组,导致内存访问错误。
修改后的out int sn_list仅传递单个int的指针,因此只能拿到数组第一个元素,无法获取完整结果。
正确的P/Invoke声明
直接传入已分配的int数组,无需out修饰符,显式指定调用约定更清晰:
[DllImport(@"C:\Program Files (x86)\ASIX\UP\up_control64.dll", CallingConvention = CallingConvention.StdCall)] private static extern int UP_GetProgList(int prog_type, int[] sn_list, int count, out int count_returned);
正确调用代码
const int PROG_FORTE = 2; void Main() { // 预先分配足够大的数组,对应C++示例的20个元素 var list = new int[20]; int countReturned = 0; int result = UP_GetProgList(PROG_FORTE, list, list.Length, out countReturned); // 仅遍历实际返回的元素,避免读取未初始化的无效数据 for (int i = 0; i < countReturned; i++) { Console.WriteLine(list[i]); } }
关键说明
- C++的
int* sn_list对应C#的int[]:传入托管数组时,P/Invoke会自动转换为非托管内存指针,函数可直接写入数组元素。 - 无需
out修饰:数组是引用类型,传递的是引用,函数修改的是数组内部元素,而非重新分配数组。 - 用数组长度作为
count参数,和C++示例逻辑一致。 - 依赖
count_returned的值遍历数组,确保只处理有效数据。
内容的提问来源于stack exchange,提问作者RoadieRich
相关产品推荐
相关产品推荐

