Skip to content

invoke

约 436 字大约 1 分钟

2026-06-21

运行环境

以下代码都是我在 Windows 11、.NET 10、VS2026 (Roslyn) 下跑过的

导出函数

这个比较基本,看示例:

[LibraryImport("user32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)]
private static partial int MessageBoxW(
    IntPtr hWnd,
    string lpText,
    string lpCaption,
    uint uType
);

MessageBoxW(IntPtr.Zero, "Command-line message box", "Attention!", 0);

在命令行环境调用 Windows 关于窗口显示 DLL 函数显示一个消息窗口。

关键在于应用于其的属性 LibraryImport,专门用来导入外部 DLL 的函数属性。

对比说明

.NET Framework 引入了一个 DllImport 属性和它功能相同但实现不同,现代 C# 基本都用 LibraryImport 属性。

参考 MSDN 的说明

其中语法上也有些区别,同时支持 AOT。

属性说明

属性说明
"user32.dll"构造函数参数,自然就是导入的 DLL 名字
StringMarshalling = StringMarshalling.Utf16指定导入函数使用 UTF-16 编码生成封送代码。对于 C# 来说一个 char 就是 UTF-16 编码的,C++ 的 char 则是根据平台定义的不小于 8 位 bit
EntryPoint = "MessageBoxW"表明函数入口点,就是 DLL 里这个函数名字;DLL 加载器根据这个名字在 DLL 查找函数;不指定就和声明函数一致
SetLastError = trueCLR 会在调用本机函数之后,自动调用 GetLastError 函数,并将获取到的错误代码缓存起来;托管代码调用 Marshal.GetLastPInvokeError() 方法来获取这个被缓存的错误代码。用这个原因是 Win32 DLL 很多函数失败不通过返回值表示,而是设置一个错误码
StringMarshallingCustomType自定义封送器,当 StringMarshalling = Custom 时使用

其他相关属性:

[return: MarshalAs(UnmanagedType.LPWStr)]  // 或 UnmanagedType.LPStr 等

[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)]  // 或 CallConvStdcall, CallConvThiscall)]