如何解决WriteFileEx不调用完成例程的问题?HID设备异步写入异常
核心问题
WriteFileEx 的完成例程必须在线程进入可警告等待状态(Alertable Wait)时才会被系统触发。你的代码里虽然调用了 WriteFileEx 且返回成功,但如果当前线程没有调用支持可警告等待的函数(比如带Ex后缀的等待/睡眠函数,且最后一个参数设为TRUE),系统根本没机会执行你的完成例程,自然无法释放OVERLAPPED结构。
具体修复方案
让线程进入可警告等待状态
如果你是在DirectInput的回调线程里执行的WriteFileEx,得确保这个线程后续会进入可警告等待。比如如果是消息循环线程,修改消息循环:MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); // 插入可警告等待,给系统触发完成例程的机会 MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE); }如果是工作线程,空闲时用
SleepEx(INFINITE, TRUE)替代普通Sleep或非Ex版本的等待函数。确认OVERLAPPED结构的有效性
你初始化OVERLAPPED{0}没问题,但要注意这个结构必须在完成例程执行前保持存在——目前你动态分配的方式是对的,但只要完成例程不触发就会内存泄漏,这也是必须解决完成例程调用问题的原因。备选:用GetOverlappedResultEx主动查询(临时排查)
如果暂时没法修改线程等待逻辑,可以用GetOverlappedResultEx主动等待异步操作完成,同时触发完成例程:DWORD bytesWritten; if (GetOverlappedResultEx(my_hid, over, &bytesWritten, INFINITE, TRUE)) { // 操作完成,这里也能手动释放OVERLAPPED delete over; }但这只是临时方案,长期来看还是要让完成例程自动触发。
额外建议
如果修改线程等待逻辑有困难(比如不想影响游戏主线程的运行),可以考虑改用**IOCP(完成端口)**处理异步HID写入。IOCP的完成通知不依赖线程的可警告等待,更适合这种被第三方框架(DirectInput)托管线程的场景。
内容的提问来源于stack exchange,提问作者ElSnowman

