我的应用程序中的某处(连同第 3 方代码库)是一个窗口过程,它阻止 Windows:
- 注销
- 关闭
- 重新启动
我发现我的代码中有一个地方犯了一个非常常见的错误,即调用 DefWindowProc
,但调用不正确:
之前:
void Grobber.BroadcastListenerWindowProc(ref TMessage msg)
{
DefWindowProc(_broadcastListenerHwnd, msg.msg, msg.wparam, msg.lparam);
}
之后:
void Grobber.BroadcastListenerWindowProc(ref TMessage msg)
{
//20170207: Forgetting to set the result can, for example, prevent Windows from restarting
msg.Result = DefWindowProc(_broadcastListenerHwnd, msg.msg, msg.wparam, msg.lparam);
}
我修复了那个错误,我的 test program不再停止关机。
但是完整的应用程序可以
我现在面临着不得不将程序拆成零的问题,直到我的计算机最终重新启动。
在我的应用程序深处的某处是一个附加到 HWND 的 Window 过程,它向 WM_QUERYENDSESSION
返回零.如果我知道 HWND,我就可以使用 Spy++ 找到窗口。
但是我怎样才能找到那个hwnd
呢?
Windows Application 事件日志记录了停止关机的进程:
在更详细的应用程序和服务日志中很可能会有更详细的日志。但这些都没有记录。
如何找到有问题的 hwnd
?
尝试
我尝试使用 EnumThreadWindows
获取我的“主”线程的所有窗口,我想手动发送 WM_QUERYENDSESSION
给它们,看看谁返回 错误:
var
wnds: TList<HWND>;
function DoFindWindow(Window: HWnd; Param: LPARAM): Bool; stdcall;
var
wnds: TList<HWND>;
begin
wnds := TList<HWND>(Param);
wnds.Add(Window);
Result := True;
end;
wnds := TList<HWND>.Create;
enumProc := @DoFindWindow;
EnumThreadWindows(GetCurrentThreadId, EnumProc, LPARAM(wnds));
现在我有一个包含 12 个 hwnd 的列表。戳他们:
var
window: HWND;
res: LRESULT;
for window in wnds do
begin
res := SendMessage(window, WM_QUERYENDSESSION, 0, 0);
if res = 0 then
begin
ShowMessage('Window: '+IntToHex(window, 8)+' returned false to WM_QUERYENDSESSION');
end;
end;
但是没有人返回零。
所以这是一根 pipe 下水道。
最佳答案
EnumThreadWindows
仅枚举一个特定线程的窗口。可能是有问题的窗口是在线程中创建的。因此,我建议您使用 EnumWindows
枚举应用程序中的所有顶级窗口以进行测试。
在线程中初始化 COM 就足够了,您将拥有一个您不知道的窗口。这样在线程中调用 WaitForSingleObject 可能是你的罪魁祸首: Debugging an application that would not behave with WM_QUERYENDSESSION
关于windows - 如何找到阻止关机的 HWND?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42094620/