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

C导出带char*参数的DLL函数,C#导入调用问题咨询

问题分析与解决方案

首先,你的代码存在几个关键问题,咱们一步步拆解并修正:

1. 明显的笔误问题

你在DllImport中声明的函数是GetDllVersion,但在Main里调用的却是AltixDllVersion——这会直接导致编译错误,先把这个笔误改掉。

2. ref string的用法错误

C中的char*在这里是输出缓冲区,而C#的string是不可变类型,ref string会试图把托管字符串的内存地址传递给非托管代码。但CLR会保护托管字符串的内存,非托管代码直接写入会引发内存访问错误,完全不符合预期。

正确的做法是用StringBuilder,它是可变的字符缓冲区,在互操作时会被自动转换为非托管的char*,适合接收非托管代码的输出。

3. 调用约定的缺失

C语言编译的DLL默认使用cdecl调用约定,而C#的DllImport默认是stdcall——如果不明确指定调用约定,会导致栈不平衡,程序运行时崩溃。


正确实现代码

第一步:修正DLL导入声明

class DllSolderMask {
    // 指定字符集为Ansi(和C的char*匹配),调用约定为C默认的cdecl
    [DllImport("Dll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern int GetDllVersion(StringBuilder version);
}

第二步:正确调用函数

假设你的C函数要求调用者提供足够大的缓冲区(比如版本字符串不会超过256字符),可以这样写:

static void Main(string[] args) {
    // 预先分配足够大小的缓冲区
    StringBuilder versionBuffer = new StringBuilder(256);
    
    // 调用DLL函数
    int result = DllSolderMask.GetDllVersion(versionBuffer);
    
    // 这里需要根据C函数的返回值判断是否成功(比如返回0表示成功)
    Console.WriteLine(versionBuffer.ToString());
}

进阶:动态获取缓冲区大小

如果你的C函数支持传入NULL返回所需的缓冲区长度(很多DLL导出函数会这么设计),可以先调用一次获取长度,再分配精准的缓冲区:

static void Main(string[] args) {
    // 传入NULL获取所需缓冲区大小
    int requiredSize = DllSolderMask.GetDllVersion(null);
    
    if (requiredSize > 0) {
        StringBuilder versionBuffer = new StringBuilder(requiredSize);
        int result = DllSolderMask.GetDllVersion(versionBuffer);
        Console.WriteLine(versionBuffer.ToString());
    } else {
        Console.WriteLine("获取版本信息失败");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:28:59