跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C Sharp P Invoke
”︁(章节)
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= C# P/Invoke = == 介绍 == '''P/Invoke'''(Platform Invocation Services)是 C# 中用于调用非托管代码(如 C/C++ DLL 或系统 API)的一种机制。它允许 .NET 应用程序与本地库交互,扩展了 C# 的功能范围。P/Invoke 在需要访问操作系统底层功能或调用现有本地库时非常有用。 === 核心概念 === * '''非托管代码''':不由 .NET 运行时管理的代码(如 Win32 API 或 C++ 库)。 * '''托管代码''':由 .NET 运行时管理的代码(如 C# 程序)。 * '''互操作性''':托管代码与非托管代码之间的通信。 == 基本语法 == P/Invoke 主要通过 `DllImport` 特性声明外部函数。以下是一个简单的示例: <syntaxhighlight lang="csharp"> using System; using System.Runtime.InteropServices; class Program { // 声明外部函数(来自 user32.dll) [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type); static void Main() { // 调用非托管函数 MessageBox(IntPtr.Zero, "Hello from P/Invoke!", "Message", 0); } } </syntaxhighlight> === 输出 === 执行此代码将弹出一个 Windows 消息框,显示文本 "Hello from P/Invoke!"。 == 参数传递 == P/Invoke 需要正确处理数据类型转换。以下是常见映射: {| class="wikitable" |- ! C/C++ 类型 !! C# 类型 |- | <code>int</code> | <code>int</code> |- | <code>char*</code> | <code>string</code> 或 <code>StringBuilder</code> |- | <code>HWND</code> | <code>IntPtr</code> |- | <code>BOOL</code> | <code>bool</code> |} === 示例:调用 Win32 API === <syntaxhighlight lang="csharp"> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern bool Beep(uint frequency, uint duration); static void Main() { Beep(1000, 500); // 发出 1000Hz 的蜂鸣声,持续 500ms } </syntaxhighlight> == 结构体和回调 == P/Invoke 支持传递结构体和回调函数。 === 结构体示例 === <syntaxhighlight lang="csharp"> [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT point); static void Main() { POINT cursorPos; GetCursorPos(out cursorPos); Console.WriteLine($"Cursor position: X={cursorPos.X}, Y={cursorPos.Y}"); } </syntaxhighlight> === 回调示例 === <syntaxhighlight lang="csharp"> public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); static bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) { Console.WriteLine($"Window handle: {hWnd}"); return true; } static void Main() { EnumWindows(EnumWindowsCallback, IntPtr.Zero); } </syntaxhighlight> == 错误处理 == P/Invoke 错误通常通过以下方式处理: * 检查返回值(如 <code>false</code> 表示失败)。 * 调用 <code>Marshal.GetLastWin32Error()</code> 获取错误代码。 == 实际案例 == === 案例:获取系统信息 === <syntaxhighlight lang="csharp"> [DllImport("kernel32.dll")] public static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo); [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public ushort wProcessorArchitecture; public uint dwPageSize; // 其他字段... } static void Main() { SYSTEM_INFO info; GetSystemInfo(out info); Console.WriteLine($"Page size: {info.dwPageSize} bytes"); } </syntaxhighlight> == 性能考虑 == * P/Invoke 调用比纯托管代码慢(因跨托管/非托管边界)。 * 频繁调用时应考虑批处理或缓存。 == 安全注意事项 == * 验证所有输入参数,防止缓冲区溢出。 * 避免暴露敏感数据给非托管代码。 == 进阶主题 == === 内存管理 === 使用 <code>Marshal</code> 类手动管理内存: <syntaxhighlight lang="csharp"> IntPtr ptr = Marshal.AllocHGlobal(1024); // 分配非托管内存 // 使用内存... Marshal.FreeHGlobal(ptr); // 释放内存 </syntaxhighlight> === 调用约定 === 指定调用约定(如 <code>CallingConvention.StdCall</code>): <syntaxhighlight lang="csharp"> [DllImport("lib.dll", CallingConvention = CallingConvention.Cdecl)] </syntaxhighlight> == 常见问题 == {| class="wikitable" |- ! 问题 !! 解决方案 |- | "DLL not found" 错误 | 确保 DLL 位于可执行文件目录或系统路径 |- | 访问冲突 | 检查参数类型是否正确映射 |- | 内存泄漏 | 确保释放所有分配的非托管资源 |} == 总结 == P/Invoke 是 C# 与本地代码交互的强大工具,适用于: * 调用操作系统 API * 复用现有本地库 * 访问硬件功能 通过正确使用数据类型、错误处理和内存管理,可以构建稳定高效的互操作解决方案。 [[Category:编程语言]] [[Category:C Sharp]] [[Category:C Sharp 高级主题]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)