
怎么在c++里直接调用windows API函数
能,而且非常直接——windows API本质就是一堆Win32导出的C风格函数,C++天然兼容。不需要额外绑定库或生成桩代码,只要包含对应头文件、链接正确.lib,就能调用。
关键不是“能不能”,而是“哪几个头文件要引”“哪个库要链”“为什么有时候编译过了但运行报错”。
-
#include <windows.h></windows.h>是绝大多数API的入口头文件(它内部已包含windef.h、winbase.h等) - 多数基础API(如
MessageBoxA、CreateFileA、GetLastError)链接kernel32.lib、user32.lib,VS项目默认已加;但像ShellExecuteEx需要显式加shell32.lib - 别手动写
extern "C"——windows.h里早已用宏处理好C链接约定
宽字符 vs ANSI:为什么MessageBoxW不弹窗,而MessageBoxA可以
Windows API有两套命名:带A后缀的是ANSI版本(实际走MultiByteToWideChar转换),带W后缀的是原生UTF-16版本。默认宏UNICODE和_UNICODE是否定义,决定了MessageBox这种无后缀名宏展开成哪个。
- 如果没定义
UNICODE,MessageBox(L"hello")会调用MessageBoxA,但传入宽字符串指针——结果是乱码或崩溃 - VS新建项目默认启用Unicode,此时应统一用
L"xxx"+MessageBoxW(或直接MessageBox) - 混用风险高:比如用
CreateFileA打开含中文路径的文件,大概率返回INVALID_HANDLE_VALUE,错误码GetLastError()可能是ERROR_PATH_NOT_FOUND——其实路径是对的,只是ANSI编码截断了
GetLastError() 总是返回0?调用顺序和线程安全要注意
GetLastError()不是全局变量,而是当前线程的TLS(线程局部存储)值。它只在API调用失败(返回值表明失败)后才有效,且**下一次API调用会覆盖它**。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
CreateFile(...); int err = GetLastError();—— 中间可能被CRT内部调用(如malloc)悄悄改掉 - 正确写法:必须紧接失败判断之后立即读取,例如
HANDLE h = CreateFile(...); if (h == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); ... } - 多线程下无需加锁——每个线程有自己的
GetLastError状态 - 注意:部分API(如
WaitForSingleObject)失败时不设置GetLastError,得查文档确认;而FormatMessage本身也会改这个值,调用前最好先缓存
资源没释放导致句柄泄漏:CloseHandle()不是可选操作
几乎所有返回HANDLE的API(CreateFile、CreateEvent、CreateThread等)都要求显式调用CloseHandle。C++析构函数不会自动帮你关——这不是RAII对象。
- 漏掉
CloseHandle不会立刻崩溃,但进程句柄数上限(默认约16K)耗尽后,后续CreateFile等会失败,错误码常为ERROR_NO_SYSTEM_RESOURCES - 不要对同一
HANDLE多次CloseHandle——会导致未定义行为(常见蓝屏或AV) - 更稳妥的做法是用
std::unique_ptr配合自定义deleter,例如:auto h_deleter = [](HANDLE h) { if (h != INVALID_HANDLE_VALUE) CloseHandle(h); };<br>std::unique_ptr<std::remove_pointer_t<HANDLE>, decltype(h_deleter)> h(CreateFile(...), h_deleter);
最易被忽略的点:很多API返回的HANDLE看起来像指针(比如FindFirstFile),但仍是内核对象句柄,同样要CloseHandle(对应FindClose是特例封装,但底层仍是CloseHandle语义)。