| 1286 | |
| 1287 | |
| 1288 | bool IsWindowHung(HWND aWnd) |
| 1289 | { |
| 1290 | if (!aWnd) return false; |
| 1291 | |
| 1292 | // OLD, SLOWER METHOD: |
| 1293 | // Don't want to use a long delay because then our messages wouldn't get processed |
| 1294 | // in a timely fashion. But I'm not entirely sure if the 10ms delay used below |
| 1295 | // is even used by the function in this case? Also, the docs aren't clear on whether |
| 1296 | // the function returns success or failure if the window is hung (probably failure). |
| 1297 | // If failure, perhaps you have to call GetLastError() to determine whether it failed |
| 1298 | // due to being hung or some other reason? Does the output param dwResult have any |
| 1299 | // useful info in this case? I expect what will happen is that in most cases, the OS |
| 1300 | // will already know that the window is hung. However, if the window just became hung |
| 1301 | // in the last 5 seconds, I think it may take the remainder of the 5 seconds for the OS |
| 1302 | // to notice it. However, allowing it the option of sleeping up to 5 seconds seems |
| 1303 | // really bad, since keyboard and mouse input would probably be frozen (actually it |
| 1304 | // would just be really laggy because the OS would bypass the hook during that time). |
| 1305 | // So some compromise value seems in order. 500ms seems about right. UPDATE: Some |
| 1306 | // windows might need longer than 500ms because their threads are engaged in |
| 1307 | // heavy operations. Since this method is only used as a fallback method now, |
| 1308 | // it seems best to give them the full 5000ms default, which is what (all?) Windows |
| 1309 | // OSes use as a cutoff to determine whether a window is "not responding": |
| 1310 | DWORD_PTR dwResult; |
| 1311 | #define Slow_IsWindowHung !SendMessageTimeout(aWnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 5000, &dwResult) |
| 1312 | |
| 1313 | // NEW, FASTER METHOD: |
| 1314 | // This newer method's worst-case performance is at least 30x faster than the worst-case |
| 1315 | // performance of the old method that uses SendMessageTimeout(). |
| 1316 | // And an even worse case can be envisioned which makes the use of this method |
| 1317 | // even more compelling: If the OS considers a window NOT to be hung, but the |
| 1318 | // window's message pump is sluggish about responding to the SendMessageTimeout() (perhaps |
| 1319 | // taking 2000ms or more to respond due to heavy disk I/O or other activity), the old method |
| 1320 | // will take several seconds to return, causing mouse and keyboard lag if our hook(s) |
| 1321 | // are installed; not to mention making our app's windows, tray menu, and other GUI controls |
| 1322 | // unresponsive during that time). But I believe in this case the new method will return |
| 1323 | // instantly, since the OS has been keeping track in the background, and can tell us |
| 1324 | // immediately that the window isn't hung. |
| 1325 | // Here are some seemingly contradictory statements uttered by MSDN. Perhaps they're |
| 1326 | // not contradictory if the first sentence really means "by a different thread of the same |
| 1327 | // process": |
| 1328 | // "If the specified window was created by a different thread, the system switches to that |
| 1329 | // thread and calls the appropriate window procedure. Messages sent between threads are |
| 1330 | // processed only when the receiving thread executes message retrieval code. The sending |
| 1331 | // thread is blocked until the receiving thread processes the message." |
| 1332 | |
| 1333 | // The use of IsHungAppWindow() (supported under Win2k+) is discouraged by MS, |
| 1334 | // but it's useful to prevent the script from getting hung when it tries to do something |
| 1335 | // to a hung window. |
| 1336 | typedef BOOL (WINAPI *MyIsHungAppWindow)(HWND); |
| 1337 | static MyIsHungAppWindow IsHungAppWindow = (MyIsHungAppWindow)GetProcAddress(GetModuleHandle(_T("user32")) |
| 1338 | , "IsHungAppWindow"); |
| 1339 | return IsHungAppWindow ? IsHungAppWindow(aWnd) : Slow_IsWindowHung; |
| 1340 | } |
| 1341 | |
| 1342 | |
| 1343 |
no outgoing calls
no test coverage detected