新闻中心
C++如何与C#进行互操作(P/Invoke)_C++与C#互操作技巧与P/Invoke使用
答案:通过P/Invoke实现C#调用C++ DLL需使用extern "C"和__declspec(dllexport)导出函数,避免名称修饰;C#中用[DllImport]声明,指定正确的调用约定和字符集;传递字符串时使用StringBuilder,结构体需用[StructLayout]匹配内存布局;注意DLL路径、平台一致性及内存管理,避免双释放。

在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.Cdecl或StdCall)。
示例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是一个ChatGPT和谷歌结合的超级工具,可以让你在浏览互联网时提出问题或获得即时摘要
302
查看详情
处理复杂数据类型与内存管理
当涉及结构体、指针或数组时,需在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 Walker或dumpbin /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对象数组转置为键值对列表的实用指南


2025-11-12
浏览次数:次
返回列表
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()}");
}