//------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // The loop the thread uses to wait for queue items to process private void WaitForWork() { SafeWaitHandle handle = _ev.SafeWaitHandle; UnsafeNativeMethods.MSG msg = new UnsafeNativeMethods.MSG(); while (!_quitting) { // pump any messages while (UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.HWND.NULL, 0, 0, UnsafeNativeMethods.PM_REMOVE)) { if (msg.message == UnsafeNativeMethods.WM_QUIT) { break; } // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.DispatchMessage(ref msg); } // do any work items in the queue DrainQueue(); int lastWin32Error = 0; int result = Misc.TryMsgWaitForMultipleObjects(handle, false, UnsafeNativeMethods.INFINITE, UnsafeNativeMethods.QS_ALLINPUT, ref lastWin32Error); if (result == UnsafeNativeMethods.WAIT_FAILED || result == UnsafeNativeMethods.WAIT_TIMEOUT) { DrainQueue(); Debug.Assert(_quitting, "MsgWaitForMultipleObjects failed while WaitForWork"); break; } } DrainQueue(); }
// Set focus to specified HWND private static bool SetFocus( NativeMethods.HWND hwnd ) { // If already focused, leave as-is. Calling SetForegroundWindow // on an already focused HWND will remove focus! if( GetFocusedWindow() == hwnd ) { return true; } // If this is an MDI Child window, send WM_MDIACTIVATE message int exStyle = GetWindowExStyle(hwnd); if (IsBitSet(exStyle, SafeNativeMethods.WS_EX_MDICHILD)) { NativeMethods.HWND parent = SafeNativeMethods.GetAncestor(hwnd, SafeNativeMethods.GA_PARENT); if (parent == IntPtr.Zero) { return false; } IntPtr lresult = Misc.SendMessageTimeout(parent, UnsafeNativeMethods.WM_MDIACTIVATE, (IntPtr)hwnd, IntPtr.Zero); return lresult == IntPtr.Zero; } // Use the hotkey technique: // Register a hotkey and send it to ourselves - this gives us the // input, and allows us to call SetForegroundWindow. short atom = Misc.GlobalAddAtom("FocusHotKey"); if (atom == 0) { return false; } byte vk = 0xB9; bool gotHotkey = false; for( int tries = 0 ; tries < 10 ; tries++ ) { if( Misc.RegisterHotKey( NativeMethods.HWND.NULL, atom, 0, vk ) ) { gotHotkey = true; break; } vk++; // try another key } if( gotHotkey ) { // Get state of modifiers - and temporarilly release them... bool fShiftDown = ( UnsafeNativeMethods.GetAsyncKeyState( UnsafeNativeMethods.VK_SHIFT ) & unchecked((int)0x80000000) ) != 0; bool fAltDown = ( UnsafeNativeMethods.GetAsyncKeyState( UnsafeNativeMethods.VK_MENU ) & unchecked((int)0x80000000) ) != 0; bool fCtrlDown = ( UnsafeNativeMethods.GetAsyncKeyState( UnsafeNativeMethods.VK_CONTROL ) & unchecked((int)0x80000000) ) != 0; if( fShiftDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_SHIFT, false ); if( fAltDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_MENU, false ); if( fCtrlDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_CONTROL, false ); Input.SendKeyboardInputVK( vk, true ); Input.SendKeyboardInputVK( vk, false ); // Restore release modifier keys... if( fShiftDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_SHIFT, true ); if( fAltDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_MENU, true ); if( fCtrlDown ) Input.SendKeyboardInputVK( UnsafeNativeMethods.VK_CONTROL, true ); // Spin in this message loop until we get the hot key while (true) { // If the hotkey input gets lost (eg due to desktop switch), GetMessage may not return - // so use MsgWait first so we can timeout if there's no message present instead of blocking. int result = Misc.MsgWaitForMultipleObjects(null, false, 2000, UnsafeNativeMethods.QS_ALLINPUT); if (result == UnsafeNativeMethods.WAIT_FAILED || result == UnsafeNativeMethods.WAIT_TIMEOUT) break; UnsafeNativeMethods.MSG msg = new UnsafeNativeMethods.MSG(); if (Misc.GetMessage(ref msg, NativeMethods.HWND.NULL, 0, 0) == 0) break; // TranslateMessage() will not set an error to be retrieved with GetLastError, // so set the pragma to ignore the PERSHARP warning. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.TranslateMessage(ref msg); // From the Windows SDK documentation: // The return value specifies the value returned by the window procedure. // Although its meaning depends on the message being dispatched, the return // value generally is ignored. #pragma warning suppress 6031, 6523 UnsafeNativeMethods.DispatchMessage(ref msg); if (msg.message == UnsafeNativeMethods.WM_HOTKEY && msg.wParam == (IntPtr) atom) { break; } } Misc.UnregisterHotKey(NativeMethods.HWND.NULL, atom); } Misc.GlobalDeleteAtom(atom); // Using this method uses the actual codepath the Alt+Tab uses UnsafeNativeMethods.SwitchToThisWindow(hwnd, true); return true; }