C# 与 C 类型对照速查表
一、基础数值类型(无符号 / 有符号整数)
| C/C++ 原生类型 | Windows 宏别名 | 占用字节 | C# 对应类型 | 说明 |
|---|---|---|---|---|
| char | CHAR | 1 | sbyte / byte | char 有符号;unsigned char = byte |
| unsigned char | UCHAR, BYTE | 1 | byte | BYTE=unsigned char,0~255 |
| short | SHORT | 2 | short | 16 位有符号 |
| unsigned short | USHORT, WORD | 2 | ushort | WORD,0~65535 |
| int | INT | 4 | int | 32 位有符号 |
| unsigned int | UINT | 4 | uint | 32 位无符号 |
| long | LONG | 4 | int | Windows 下 long 固定 4 字节 |
| unsigned long | ULONG, DWORD | 4 | uint | DWORD=ULONG 0~0xFFFFFFFF |
| long long | LONGLONG | 8 | long | 64 位有符号 |
| unsigned long long | ULONGLONG, DWORDLONG | 8 | ulong | 64 位无符号大容量数值 |
| float | FLOAT | 4 | float | 单精度浮点 |
| double | DOUBLE | 8 | double | 双精度浮点 |
特殊常量对照
INVALID_FILE_ATTRIBUTES = (DWORD)-1→ C#public const uint INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF;INVALID_HANDLE_VALUE = (HANDLE)-1→ C#IntPtr(-1)
二、句柄、指针类(内核对象 / 内存地址)
| C/C++ 类型 | 含义 | C# 类型 | 使用说明 |
|---|---|---|---|
| void* | 通用指针 | IntPtr | 万能指针,存放地址 |
| HANDLE | 内核对象句柄(文件、线程、进程、事件) | IntPtr | CreateFile、OpenProcess 返回 |
| HMODULE | DLL/EXE 模块句柄 | IntPtr | LoadLibrary 返回 |
| HWND | 窗口句柄 | IntPtr | FindWindow、MessageBox 窗口参数 |
| HDC | 绘图设备上下文 | IntPtr | GDI 绘图 API |
| HBITMAP / HPEN / HBRUSH | GDI 资源句柄 | IntPtr | 位图、画笔、画刷 |
| HINSTANCE | 程序实例句柄 | IntPtr | 等价 HMODULE |
| LPVOID / LPCVOID | 通用读写缓冲区指针 | IntPtr / byte\[\] | ReadFile/WriteFile 数据缓冲区 |
| LPVOID* | 指针的指针 | out IntPtr | 输出句柄、输出指针 |
关键规则
- 所有句柄统一用
IntPtr,不用int/uint(64 位程序地址会溢出); - 无效句柄判断:
if (h == IntPtr.Zero || h == (IntPtr)(-1))。
三、字符串类型(ANSI / Unicode 宽字符,重点易错)
| C/C++ 类型 | 编码 | C# 入参类型 | C# 输出参数 | DllImport CharSet 配置 |
|---|---|---|---|---|
| LPCSTR / LPSTR | GBK ANSI 单字节 | string | StringBuilder | CharSet.Ansi |
| LPCWSTR / LPWSTR | UTF16 宽字符(xxxW) | string | StringBuilder | CharSet.Unicode |
| TCHAR / LPTSTR | 自适应 | string | StringBuilder | CharSet.Auto |
重点说明
- 输入字符串 :单纯传入路径 / 文本用
string; - 输出字符串 (API 填充缓冲区)不能用 string ,必须
StringBuilder; 例:GetModuleFileNameW、GetWindowTextW; - GetProcAddress 函数名参数是 ANSI:
[DllImport(..., CharSet.Ansi)]。
四、布尔类型
| C/C++ | 说明 | C# 类型 | 注意 |
|---|---|---|---|
| BOOL | int 底层,TRUE=1,FALSE=0 | bool / int | 推荐 bool,非 0 自动 true |
| BOOLEAN | BYTE 1 字节布尔 | byte | 极少 API 使用 |
五、函数指针 / 回调(DLL 动态调用、窗口回调)
C 写法
cpp
typedef int (WINAPI *MsgBoxPtr)(HWND hWnd, LPCWSTR txt, LPCWSTR cap, UINT type);
C# 对应规则
- 用
delegate定义; - 必须加特性
[UnmanagedFunctionPointer(CallingConvention.StdCall)]; - Windows API 统一
StdCall调用约定,漏写会栈崩溃。
表格
| C 类型 | C# 实现 |
|---|---|
| WINAPI 函数指针 | 标记 StdCall 的 delegate |
| LPVOID lpCallback | IntPtr / delegate |
C#
cpp
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int DlgMsgBox(IntPtr hWnd, string text, string cap, uint type);
C#
cpp
IntPtr pFunc = GetProcAddress(hMod, "MessageBoxW");
DlgMsgBox fn = Marshal.GetDelegateForFunctionPointer<DlgMsgBox>(pFunc);
六、结构体 / 联合体(Windows 常用大结构)
通用映射规则
- C# 结构体加
[StructLayout(LayoutKind.Sequential)]保持内存顺序; - 有指针 / 句柄成员一律用
IntPtr; - 字符数组缓冲区用
fixed byte[]或StringBuilder;
| C 结构示例 | C# 处理方案 |
|---|---|
| LARGE_INTEGER(联合体高低位) | long(直接用 ulong/long 替代 QuadPart) |
| OVERLAPPED 异步 IO 结构体 | 自定义 Struct,Sequential 布局 |
| SECURITY_ATTRIBUTES | 自定义结构体,nLength 必须赋值 |
LARGE_INTEGER 简化对照(最常用)
C:
cpp
typedef union _LARGE_INTEGER {
struct { DWORD LowPart; LONG HighPart; };
LONGLONG QuadPart;
} LARGE_INTEGER;
C# 直接简化:
cs
// GetFileSizeEx 直接传 out long 替代结构体
[DllImport("kernel32.dll")]
public static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);
七、指针输出参数(带 LP 前缀,输出值)
C 原型:BOOL GetXXX(DWORD* outValue);
| C 参数 | C# 修饰符 | 示例 |
|---|---|---|
| LPDWORD / DWORD* | out uint | out uint dwOut |
| LPULONGLONG / ULONGLONG* | out ulong | out ulong llOut |
| LPHANDLE / HANDLE* | out IntPtr | out IntPtr hOut |
| LPBOOL / BOOL* | out bool | out bool bRet |
c
cpp
BOOL GetDiskFreeSpaceEx(LPCWSTR path, ULARGE_INTEGER* avail, ULARGE_INTEGER* total, ULARGE_INTEGER* free);
C#:
cs
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool GetDiskFreeSpaceEx(string path, out long avail, out long total, out long free);
八、调用约定对照表
| C 宏 | 调用约定 | C# 委托标记 | 使用场景 |
|---|---|---|---|
| WINAPI / __stdcall | StdCall | CallingConvention.StdCall | 所有 Windows 系统 API(默认) |
| __cdecl | Cdecl | CallingConvention.Cdecl | C 标准库、第三方自定义 DLL |
九、高频易错坑总结
- DWORD 不要用 int:无符号数值,超过 21 亿会溢出;统一 uint;
- 句柄禁止用 int/long:64 位程序地址超 32 位,必须 IntPtr;
- 输出字符串不用 string,只用 StringBuilder;
- 宽字符 API 统一
CharSet.Unicode,解决中文路径乱码; - 函数指针委托必须指定 StdCall,否则程序直接崩溃;
- 结构体不加 Sequential 会内存对齐错乱,读取数据错误;
- LoadLibrary / CreateFile 路径传中文,必须 W 版本 + Unicode 字符集。
C# 使用 [DllImport] 引入原生 Win32 API,分宽字符 W 版本(推荐,支持中文路径)
一、基础知识点
[DllImport("kernel32.dll")]:从系统内核库导入 APICharSet = CharSet.Unicode= 调用 xxxW 宽字符版本,避免中文乱码StringBuilder作为输出字符串缓冲区(C# string 不可修改,不能当输出参数)IntPtr对应 C/C++ 里HMODULE / HANDLE / void*
1. GetModuleFileNameW C# 实现(获取程序自身路径)
cs
using System;
using System.Text;
using System.Runtime.InteropServices;
class Win32Helper
{
// 导入API
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetModuleFileNameW(
IntPtr hModule, // NULL=0 取当前EXE
StringBuilder lpFilename,
uint nSize
);
static void Main()
{
StringBuilder sbPath = new StringBuilder(1024);
uint ret = GetModuleFileNameW(IntPtr.Zero, sbPath, (uint)sbPath.Capacity);
if (ret > 0)
{
Console.WriteLine("程序完整路径:" + sbPath.ToString());
// 截取目录(去掉exe文件名)
string dir = System.IO.Path.GetDirectoryName(sbPath.ToString());
Console.WriteLine("程序目录:" + dir);
}
else
{
Console.WriteLine("获取失败");
}
Console.ReadKey();
}
}
2. LoadLibraryW + GetProcAddress + FreeLibrary C# 动态调用 DLL
模拟 C 里动态加载 user32 调用 MessageBoxW
cs
using System;
using System.Runtime.InteropServices;
class DllInvokeDemo
{
// 1. 加载释放DLL
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibraryW(string lpLibFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)] // 函数名是ASCII
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
// 2. 定义MessageBoxW委托(对应C函数指针)
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int DlgMsgBox(IntPtr hWnd, string text, string caption, uint type);
static void Main()
{
// 加载user32.dll
IntPtr hUser32 = LoadLibraryW("user32.dll");
if (hUser32 == IntPtr.Zero)
{
Console.WriteLine("加载DLL失败");
return;
}
// 获取MessageBoxW地址
IntPtr pMsgBox = GetProcAddress(hUser32, "MessageBoxW");
if (pMsgBox == IntPtr.Zero)
{
FreeLibrary(hUser32);
return;
}
// 转为委托调用
DlgMsgBox msgBox = Marshal.GetDelegateForFunctionPointer<DlgMsgBox>(pMsgBox);
msgBox(IntPtr.Zero, "C#调用Win32 API弹窗", "提示", 0);
// 释放库
FreeLibrary(hUser32);
Console.ReadKey();
}
}
3. 常用配套 API 补充(GetFileAttributesW / INVALID_FILE_ATTRIBUTES)
cs
public const uint INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetFileAttributesW(string lpFileName);
// 使用
uint attr = GetFileAttributesW(@"D:\test.txt");
if (attr == INVALID_FILE_ATTRIBUTES)
{
Console.WriteLine("文件不存在/无法访问");
}
else
{
bool isHidden = (attr & 2) != 0; // FILE_ATTRIBUTE_HIDDEN = 2
Console.WriteLine("是否隐藏:" + isHidden);
}
关键注意事项
- CharSet.Unicode 必须加 不加默认 Ansi,中文路径、中文参数会乱码。
- 输出字符串不能用
string,必须StringBuilder原生 API 要改写缓冲区,string 是只读。 - 函数名参数
GetProcAddress传 ANSI 字符串 导出函数名字符串固定 ASCII,所以[DllImport]写CharSet.Ansi。 - 委托必须标记
[UnmanagedFunctionPointer(CallingConvention.StdCall)]Windows API 统一__stdcall 调用约定,漏写会栈失衡崩溃。 - 资源释放
LoadLibrary后必须FreeLibrary,避免内存泄漏。
4. C# 与 C 类型对照速查表
| C/C++ 类型 | C# 对应类型 |
|---|---|
| HMODULE / HANDLE | IntPtr |
| DWORD | uint |
| LPCWSTR / LPWSTR | string / StringBuilder |
| WINAPI 函数指针 | delegate + Marshal.GetDelegateForFunctionPointer |
| BOOL | bool |