我的应用程序中的某个地方(以及第三方代码库)是一个阻止
Windows的窗口过程:
我在我的代码中找到了一个位置,我在调用DefWindowProc时犯了一个非常常见的错误,但调用错误:
FBroadcastListenerHwnd := AllocateHWnd(BroadcastListenerWindowProc); procedure TGrobber.BroadcastListenerWindowProc(var msg: TMessage); begin DefWindowProc(FBroadcastListenerHwnd,msg.msg,msg.wparam,msg.lparam); end;
我修复了那个bug,而我的test program不再停止关机了.
但完整的应用程序
我现在面临着不得不撕掉一个程序,直到我的计算机终于重新启动.
在我的应用程序内部的某个地方是一个附加到HWND的Window过程,它返回零到WM_QUERYENDSESSION
.如果我只知道HWND,我可以使用Spy找到Window.
但我怎么能找到那个人呢?
Windows应用程序事件日志记录了停止关闭的过程:
并且在更详细的应用程序和服务日志中有更详细的日志.但那些没有证件.
我怎样才能找到有问题的hwnd?
尝试
我尝试使用EnumThreadWindows来获取我的“主”线程的所有窗口,并想要手动向它们发送WM_QUERYENDSESSION以查看谁返回false:
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个hwnds.戳他们:
var window: HWND; res: LRESULT; for window in wnds do begin res := SendMessage(window,WM_QUERYENDSESSION,0); if res = 0 then begin ShowMessage('Window: '+IntToHex(window,8)+' returned false to WM_QUERYENDSESSION'); end; end;
但没有人确实归零.
所以这是排水管的一个管.
EnumThreadWindows只枚举一个特定线程的窗口.可能是在一个线程中创建了违规窗口.因此,我建议您使用EnumWindows在您的应用程序中枚举所有顶级窗口以进行测试.
它足以在一个线程中初始化COM,你将拥有一个你不知道的窗口.这样在线程中调用WaitForSingleObject可能是你的罪魁祸首:
Debugging an application that would not behave with WM_QUERYENDSESSION