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

调用C++导出库方法时触发System.AccessViolationException求助

解决C++库导入C#时的System.AccessViolationException错误

这个内存访问冲突问题大概率是跨语言调用时的类型不匹配、调用约定不一致或者C++名字修饰导致的,我帮你拆解问题并给出具体的修复方案:

问题根源分析

  1. std::string 无法被C#直接识别
    C++的std::string是标准库封装的类型,内存布局和C#的string完全不同,跨语言调用时不能直接用它作为函数参数——C#无法正确封送这个类型,必然会导致内存读写错误。

  2. C++函数导出的名字修饰问题
    你原来的代码里,只在声明时加了extern "C",但定义时没加,这会导致C++编译器对函数名进行名字修饰(mangling),C#通过DllImport查找的函数名和实际导出的名字不匹配,间接引发内存错误。

  3. 回调函数的调用约定一致性
    虽然你用了CALLBACK(本质是__stdcall),但C#端如果没有正确声明委托的调用约定,会导致栈不平衡,同样触发内存访问异常。

具体修复步骤

第一步:修改C++端代码

把函数参数换成C兼容的类型,确保导出的函数没有名字修饰,代码如下:

#include <string>

// 回调函数保持CALLBACK(__stdcall)调用约定不变
int CALLBACK xCallback(long xmitlen, int buflen, char *buf, long flen) { 
    return 0; 
}

// 用extern "C"包裹声明和定义,避免C++名字修饰
// 参数改用const char*,这是跨语言调用字符串的标准做法
extern "C" __declspec(dllexport) int __stdcall TXFIlestransfer(int port, const char* fileName) {
    int ret;
    // 如果sio_FtKermitTx要求非const的char*,可以用const_cast转换(确认库不会修改传入的字符串)
    ret = sio_FtKermitTx(port, const_cast<char*>(fileName), xCallback, 27);
    return ret;
}

第二步:修改C#端调用代码

需要正确声明回调委托和导入函数,保证调用约定、字符集和参数类型完全匹配:

using System;
using System.Runtime.InteropServices;

class FileTransferClient
{
    // 声明回调委托,必须指定StdCall调用约定,参数类型对应C++的类型
    // Windows下long是32位,对应C#的int;char*用IntPtr接收(如果需要操作缓冲区可以转成byte[])
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int XCallbackDelegate(int xmitlen, int buflen, IntPtr buf, int flen);

    // 导入C++函数,注意替换成你的DLL文件名
    // 指定StdCall调用约定和ANSI字符集(匹配C++的char类型)
    [DllImport("YourCppLibrary.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    private static extern int TXFIlestransfer(int port, string fileName);

    static void Main(string[] args)
    {
        try
        {
            // 测试调用,替换成你的端口和文件名
            int transferResult = TXFIlestransfer(5000, "testfile.txt");
            Console.WriteLine($"文件传输结果:{transferResult}");
        }
        catch (AccessViolationException ex)
        {
            Console.WriteLine($"错误:{ex.Message}");
        }
    }
}

额外注意事项

  • 字符集匹配:如果你的C库用的是Unicode(wchar_t*),那C#端要把CharSet改成CharSet.Unicode,同时C参数换成const wchar_t*。
  • 回调生命周期:如果C++库会在TXFIlestransfer返回后继续调用回调,一定要把C#的委托保存为静态成员(比如private static XCallbackDelegate _callback;),防止被GC回收导致内存错误。
  • 参数类型验证:确认sio_FtKermitTx的参数类型和你传递的完全一致,比如long在Windows是32位,对应C#的int,如果是64位系统的long则对应C#的long。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:32:42