新闻中心

C++如何与C#进行互操作(P/Invoke)_C++与C#互操作技巧与P/Invoke使用

2025-11-12
浏览次数:
返回列表
答案:通过P/Invoke实现C#调用C++ DLL需使用extern "C"和__declspec(dllexport)导出函数,避免名称修饰;C#中用[DllImport]声明,指定正确的调用约定和字符集;传递字符串时使用StringBuilder,结构体需用[StructLayout]匹配内存布局;注意DLL路径、平台一致性及内存管理,避免双释放。

c++如何与c#进行互操作(p/invoke)_c++与c#互操作技巧与p/invoke使用

在Windows平台上,C++与C#之间的互操作是一个常见需求,尤其是在需要调用本地C++代码来提升性能或复用已有库时。P/Invoke(Platform Invoke)是.NET提供的一种机制,允许托管代码(如C#)调用非托管DLL中的函数。下面介绍如何通过P/Invoke实现C#调用C++编写的原生函数,并给出关键技巧和注意事项。

导出C++函数供C#调用

要让C#通过P/Invoke调用C++函数,必须将C++函数导出为C风格的接口,避免C++的名称修饰(name mangling)。使用extern "C"__declspec(dllexport)确保函数能被正确导出。

示例C++ DLL代码(mylib.cpp):

// mylib.h
#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif
<p>extern "C" MYLIB_API int Add(int a, int b);
extern "C" MYLIB_API void GetString(char* buffer, int bufferSize);</p><p>// mylib.cpp</p><h1>include "mylib.h"</h1><h1>include <string.h></h1><p>int Add(int a, int b) {
return a + b;
}</p><p>void GetString(char<em> buffer, int bufferSize) {
const char</em> str = "Hello from C++!";
strncpy_s(buffer, bufferSize, str, strlen(str));
}

编译为DLL后,函数名在导出表中保持原始名称,便于P/Invoke查找。

C#中声明并调用非托管函数

C#使用[DllImport]特性声明外部DLL函数。需指定DLL名称和调用约定(通常为CallingConvention.CdeclStdCall)。

示例C#代码:

using System;
using System.Runtime.InteropServices;
<p>class Program {
[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);</p><pre class="brush:php;toolbar:false;">[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void GetString(StringBuilder buffer, int bufferSize);

static void Main() {
    // 调用Add
    int result = Add(3, 5);
    Console.WriteLine($"Add result: {result}");

    // 调用GetString
    var sb = new StringBuilder(256);
    GetString(sb, sb.Capacity);
    Console.WriteLine($"String from C++: {sb.ToString()}");
}

}

注意:字符串传递时使用StringBuilder作为可变缓冲区,CharSet设为Ansi以匹配C风格字符串。

Perplexity Perplexity

Perplexity是一个ChatGPT和谷歌结合的超级工具,可以让你在浏览互联网时提出问题或获得即时摘要

Perplexity 302 查看详情 Perplexity

处理复杂数据类型与内存管理

当涉及结构体、指针或数组时,需在C#端定义对应的布局,并使用[StructLayout]确保内存对齐一致。

例如,C++结构体:

struct Point {
    int x;
    int y;
};
extern "C" MYLIB_API void SetPoint(Point* p);

C#对应声明:

[StructLayout(LayoutKind.Sequential)]
public struct Point {
    public int x;
    public int y;
}
<p>[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetPoint(ref Point p);

使用ref传递结构体引用,保证按地址传参。注意不要在托管代码中直接释放非托管内存,避免双释放问题。

常见问题与最佳实践

P/Invoke调用容易出错,以下是一些实用建议:

  • 确保DLL位于运行路径下(如exe同目录),否则会抛出DllNotFoundException
  • 调用约定必须匹配,C++若用__cdecl,C#也要设为CallingConvention.Cdecl
  • 字符串编码需统一,Unicode环境下建议使用CharSet.Unicode并修改C++接口
  • 调试时可用Dependency Walkerdumpbin /exports检查DLL导出函数名
  • 考虑使用x86/x64平台目标一致,避免位数不匹配导致崩溃

对于频繁调用或复杂交互,可考虑使用C++/CLI作为桥梁,实现更自然的托管与非托管混合编程。

基本上就这些。只要注意函数导出、调用约定和数据类型映射,P/Invoke就能稳定工作。

以上就是C++如何与C#进行互操作(P/Invoke)_C++与C#互操作技巧与P/Invoke使用的详细内容,更多请关注其它相关文章!


# 如何使用  # 公司推广发帖网站怎么做  # 安福网络获客营销推广  # 新乐网站建设优化  # 舟山商城网站建设公司  # 江苏抖音营销推广公司  # 市区seo排名优化营销  # 定州网站建设保定  # 企业客户网站建设  # 服装网站建设课程评价  # 推广网站排行榜优化  # 互联网  # 内存管理  # 网络编程  # 有什么区别  # windows  # 第三方  # 操作技巧  # 微软  # 设为  # 是一个  # lsp  # .net  # c#  # 常见问题  # win  # c++  # ai  # 编码 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: J*aScript中赋值与自增运算符的复杂交互与执行机制  Win11如何开启讲述人功能 Win11屏幕阅读器(讲述人)开启与关闭【教程】  Composer的 archive 命令怎么用_快速打包你的PHP项目及其Composer依赖  C++ string find函数返回值npos详解_C++字符串查找失败的判断条件  从OpenAI API响应中高效提取生成文本  解决Django多数据库/多Schema环境下外键迁移问题  Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】  漫蛙漫画官方首页 漫蛙2漫画在线阅读入口  excel怎么制作工资条 excel快速生成工资条的方法  C++如何生成随机数_C++ random库使用方法与范围设置  UC浏览器网页版登录入口官网 电脑版网址入口  2025-2030年全球乘用车销量预测:新能源成增长主力  《铁拳8》黑皮辣妹新实机:元气满满的18岁少女!  word邮件合并后日期格式不对怎么改_Word邮件合并日期格式修改方法  响应式容器内容自动缩放与宽高比维持教程  Win10磁盘清理工具在哪 Win10打开并使用磁盘清理【教程】  J*a最大堆Heapify方法修复:索引计算与边界条件深度解析  Log4j Console Appender性能瓶颈与高并发优化策略  PrimeNG Sidebar背景色自定义指南:CSS覆盖与主题化实践  必由学官方登录入口 必由学教师学生账号快速访问  如何将HTML表格多行数据保存到Google Sheet  为什么我的微信朋友圈看不到别人的更新_微信朋友圈更新显示异常解决方法  支付宝解绑银行卡步骤_支付宝如何解除绑定银行卡  解决macOS上安装pyhdf时‘hdf.h’文件缺失的编译错误  outlook中文官网入口地址 outlook官方中文版直达首页链接  晋江读书网页版在线登录 晋江读书电脑版官网  快手赚钱渠道_快手收益来源  J*aScript类型检查_j*ascript代码规范  KFC游戏互动怎么赢取优惠券_KFC线上游戏活动参与与优惠代码赢取教程  如何使用J*aScript精确选择并批量修改特定父元素下子链接的样式  Golang指针如何与map组合使用_Golang map指针组合实践  蛙漫漫画免费阅读入口_蛙漫官方正版无广告纯净版  抖音DOU+怎么投最有效 抖音付费推广的ROI提升技巧  HTML元素状态管理:根据DIV内容动态启用/禁用按钮  京东单号查询入口_京东快递订单追踪入口  如何为你的Composer包编写自动化测试_集成PHPUnit到Composer的scripts工作流  qq游戏免费畅玩入口_qq游戏电脑版快速启动  C++如何检测键盘输入_C++ _kbhit与_getch函数非阻塞输入  J*aScript中正确使用querySelectorAll与复杂CSS选择器  Node.js CSV 数据处理:基于字段值条件过滤整条记录的策略  苹果手机指南针不准怎么校准 传感器校准方法详解【建议收藏】  CSS子选择器:如何区分并样式化嵌套列表的子层级  qq浏览器打开空白页怎么办 qq浏览器启动后显示白屏的解决教程  C++如何实现单例模式_C++设计模式之线程安全的单例写法  C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能  一加Ace 6T实拍样张首次公布!李杰:主摄实力完全看齐4K档性能旗舰  深入理解rpy2中的类型转换:优化Python对象到R矩阵的映射  J*aScript数据结构转换:将对象数组按类别分组  HuggingFaceEmbeddings中向量嵌入维度调整的限制与理解  将JSON对象数组转置为键值对列表的实用指南 

搜索