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

调用SI_GetProductStringSafe成功却触发访问违例,如何从非托管void*取字符串?

解决SI_GetProductStringSafe调用的AccessViolationException问题

你的代码触发System.AccessViolationException的核心原因是对lpvDeviceString参数的声明完全错误:

非托管函数中,lpvDeviceString是调用者预先分配的缓冲区指针,函数会将产品字符串写入这个缓冲区;但你用了out IntPtr,相当于要求函数返回一个指针,这会导致函数尝试往未初始化的内存地址写入数据,直接触发内存访问冲突。虽然返回值显示SI_SUCCESS,但这只是函数执行逻辑层面的返回,内存操作已经违规。

修正步骤及代码

1. 修正DllImport参数声明

  • 将out IntPtr lvpDeviceString改为IntPtr lpvDeviceString(传入我们分配的缓冲区指针)
  • 匹配参数类型:dwDeviceNum、dwFlags对应非托管DWORD,用C#uint更准确;DeviceStringLenInBytes对应size_t,用UIntPtr适配32/64位系统

2. 预先分配缓冲区并调用函数

提前分配足够大小的非托管缓冲区,传入函数后再从中读取字符串,最后释放缓冲区避免内存泄漏。

完整代码示例:

using System;
using System.Runtime.InteropServices;

class UsbDeviceTest
{
    // 定义SI_STATUS枚举(根据SDK实际定义补充其他状态值)
    public enum SI_STATUS : uint
    {
        SI_SUCCESS = 0,
        SI_DEVICE_IO_FAILED = 1,
        SI_DEVICE_NOT_FOUND = 2
    }

    [DllImport("SiUSBXp.dll", CharSet = CharSet.Auto, EntryPoint = "SI_GetProductStringSafe")]
    private static extern SI_STATUS SI_GetProductStringSafe(
        uint dwDeviceNum,
        IntPtr lpvDeviceString,
        UIntPtr deviceStringLenInBytes,
        uint dwFlags);

    static void Main(string[] args)
    {
        const int bufferSize = 100; // 缓冲区大小,需足够容纳产品字符串+结束符
        IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
        
        try
        {
            SI_STATUS result = SI_GetProductStringSafe(0, buffer, (UIntPtr)bufferSize, 0);
            
            if (result == SI_STATUS.SI_SUCCESS)
            {
                string productStr = Marshal.PtrToStringAuto(buffer);
                Console.WriteLine($"产品字符串: {productStr}");
            }
            else
            {
                Console.WriteLine($"调用失败,错误码: {result}");
            }
        }
        finally
        {
            // 必须释放非托管内存
            Marshal.FreeHGlobal(buffer);
        }
    }
}

额外说明

  • CharSet.Auto会自动适配系统的ANSI/Unicode编码,与非托管函数的字符串处理逻辑匹配;如果明确知道函数是宽字符版本,可指定CharSet.Unicode
  • 缓冲区大小需根据实际产品字符串长度设置,避免溢出;如果不确定长度,可先调用函数获取所需长度(参考AN169文档中的相关说明)
  • 必须在finally块中释放非托管缓冲区,防止内存泄漏

内容的提问来源于stack exchange,提问作者Piglet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:46:15