You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用非托管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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:24:51