| 150 | |
| 151 | |
| 152 | HWND SetForegroundWindowEx(HWND aTargetWindow) |
| 153 | // Caller must have ensured that aTargetWindow is a valid window or NULL, since we |
| 154 | // don't call IsWindow() here. |
| 155 | { |
| 156 | if (!aTargetWindow) |
| 157 | return NULL; // When called this way (as it is sometimes), do nothing. |
| 158 | |
| 159 | // v1.0.42.03: Calling IsWindowHung() once here rather than potentially more than once in AttemptSetForeground() |
| 160 | // solves a crash that is not fully understood, nor is it easily reproduced (it occurs only in release mode, |
| 161 | // not debug mode). It's likely a bug in the API's IsHungAppWindow(), but that is far from confirmed. |
| 162 | DWORD target_thread = GetWindowThreadProcessId(aTargetWindow, NULL); |
| 163 | if (target_thread != g_MainThreadID && IsWindowHung(aTargetWindow)) // Calls to IsWindowHung should probably be avoided if the window belongs to our thread. Relies upon short-circuit boolean order. |
| 164 | return NULL; |
| 165 | |
| 166 | #ifdef _DEBUG_WINACTIVATE |
| 167 | TCHAR win_name[64]; |
| 168 | GetWindowText(aTargetWindow, win_name, _countof(win_name)); |
| 169 | #endif |
| 170 | |
| 171 | HWND orig_foreground_wnd = GetForegroundWindow(); |
| 172 | // AutoIt3: If there is not any foreground window, then input focus is on the TaskBar. |
| 173 | // MY: It is definitely possible for GetForegroundWindow() to return NULL, even on XP. |
| 174 | // Lexikos: It can be easily reproduced by calling GetForegroundWindow() in a tight |
| 175 | // loop on Windows 10 and switching windows with Alt+Esc. In such cases the taskbar |
| 176 | // is definitely NOT active, and if our caller requested activation of the taskbar, |
| 177 | // it should not be skipped just because !orig_foreground_wnd. |
| 178 | // MSDN: "The foreground window can be NULL in certain circumstances, such as when a |
| 179 | // window is losing activation." |
| 180 | //if (!orig_foreground_wnd) |
| 181 | // orig_foreground_wnd = FindWindow(_T("Shell_TrayWnd"), NULL); |
| 182 | |
| 183 | // Fix for v1.1.28.02: Restore the window *before* checking if it is already active. |
| 184 | // This was supposed to be done in v1.1.20, but was only done for WinTitle = "A". |
| 185 | // See "IsIconic" in WinActivate() for comments. |
| 186 | if (IsIconic(aTargetWindow)) |
| 187 | // This might never return if aTargetWindow is a hung window. But it seems better |
| 188 | // to do it this way than to use the PostMessage() method, which might not work |
| 189 | // reliably with apps that don't handle such messages in a standard way. |
| 190 | // A minimized window must be restored or else SetForegroundWindow() always(?) |
| 191 | // won't work on it. UPDATE: ShowWindowAsync() would prevent a hang, but |
| 192 | // probably shouldn't use it because we rely on the fact that the message |
| 193 | // has been acted on prior to trying to activate the window (and all Async() |
| 194 | // does is post a message to its queue): |
| 195 | ShowWindow(aTargetWindow, SW_RESTORE); |
| 196 | |
| 197 | if (aTargetWindow == orig_foreground_wnd) // It's already the active window. |
| 198 | return aTargetWindow; |
| 199 | |
| 200 | // This causes more trouble than it's worth. In fact, the AutoIt author said that |
| 201 | // he didn't think it even helped with the IE 5.5 related issue it was originally |
| 202 | // intended for, so it seems a good idea to NOT to this, especially since I'm 80% |
| 203 | // sure it messes up the Z-order in certain circumstances, causing an unexpected |
| 204 | // window to pop to the foreground immediately after a modal dialog is dismissed: |
| 205 | //BringWindowToTop(aTargetWindow); // AutoIt3: IE 5.5 related hack. |
| 206 | |
| 207 | HWND new_foreground_wnd; |
| 208 | |
| 209 | if (!g_WinActivateForce) |
no test coverage detected