C++怎么调API C++调用Windows系统API函数【实战】

2次阅读

C++怎么调API C++调用Windows系统API函数【实战】

怎么在c++里直接调用windows API函数

能,而且非常直接——windows API本质就是一Win32导出的C风格函数,C++天然兼容。不需要额外绑定库或生成桩代码,只要包含对应头文件、链接正确.lib,就能调用。

关键不是“能不能”,而是“哪几个头文件要引”“哪个库要链”“为什么有时候编译过了但运行报错”。

  • #include <windows.h></windows.h> 是绝大多数API的入口头文件(它内部已包含windef.hwinbase.h等)
  • 多数基础API(如MessageBoxACreateFileAGetLastError)链接kernel32.libuser32.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这种无后缀名宏展开成哪个。

  • 如果没定义UNICODEMessageBox(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(CreateFileCreateEventCreateThread等)都要求显式调用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语义)。

text=ZqhQzanResources