LRESULT _etk_grab_window(EWin32GraphicsEngine *win32Engine, etk_win32_gdi_callback_t *callback)
{
	if(win32Engine == NULL || callback == NULL ||
	   callback->command != WM_ETK_MESSAGE_GRAB_WINDOW || callback->win == NULL ||
	   callback->win->win32Window == NULL) return FALSE;

	EAutolock <EWin32GraphicsEngine> autolock(win32Engine);
	if(autolock.IsLocked() == false || win32Engine->InitCheck() != E_OK) return FALSE;

	// TODO: keyboard grab
	if(callback->grab_mouse == false) return FALSE;

	if(callback->grab_state)
	{
		SetCapture(callback->win->win32Window);

		GUITHREADINFO info;
		info.cbSize = sizeof(GUITHREADINFO);
		GetGUIThreadInfo(win32Engine->win32ThreadID, &info);

		if(info.hwndCapture != callback->win->win32Window) return FALSE;
	}
	else
	{
		GUITHREADINFO info;
		info.cbSize = sizeof(GUITHREADINFO);
		GetGUIThreadInfo(win32Engine->win32ThreadID, &info);

		if(info.hwndCapture != callback->win->win32Window) return FALSE;

		if(ReleaseCapture() == 0) return FALSE;
	}

	return TRUE;
}
// Determine if the mouse is presently being captured. This call can be
// made outside of the GUI thread
bool isMouseCaptured(HWND hWnd, HWND &hCaptureWnd)
{
    bool bIsCaptured = false;

    DWORD processId = GetWindowThreadProcessId(hWnd, NULL);

    GUITHREADINFO threadInfo;
    threadInfo.cbSize = sizeof GUITHREADINFO;

    if (GetGUIThreadInfo(processId, &threadInfo))
    {
        bIsCaptured = bIsCaptured || (threadInfo.hwndCapture != 0);

        bIsCaptured = bIsCaptured || ((threadInfo.flags & 
            (GUI_INMENUMODE | GUI_INMOVESIZE |
            GUI_POPUPMENUMODE | GUI_SYSTEMMENUMODE)) != 0);

        hCaptureWnd = threadInfo.hwndCapture;
    }
    else
    {
        hCaptureWnd = NULL;
        //DisplayLastError("Failed to get GUITHREADINFO");
    }

    return bIsCaptured;
}
Exemple #3
0
HWND CConEmuInside::CheckInsideFocus()
{
	if (!isInsideWndSet())
	{
		//_ASSERTE(FALSE && "Inside was not initialized");
		return NULL;
	}

	wchar_t szInfo[512];
	GUITHREADINFO tif = { sizeof(tif) };
	HWND hParentWnd = GetParentRoot();
	DWORD nTID = GetWindowThreadProcessId(hParentWnd, NULL);

	if (!GetGUIThreadInfo(nTID, &tif))
	{
		_wsprintf(szInfo, SKIPCOUNT(szInfo) L"GetGUIThreadInfo(%u) failed, code=%u", nTID, GetLastError());
		LogString(szInfo);
		return NULL;
	}

	static GUITHREADINFO last_tif = {};
	if (memcmp(&last_tif, &tif, sizeof(tif)) != 0)
	{
		last_tif = tif;

		_wsprintf(szInfo, SKIPCOUNT(szInfo)
			L"ParentInputInfo: flags=x%X Active=x%X Focus=x%X Capture=x%X Menu=x%X MoveSize=x%X Caret=x%X (%i,%i)-(%i,%i)",
			tif.flags, LODWORD(tif.hwndActive), LODWORD(tif.hwndFocus), LODWORD(tif.hwndCapture), LODWORD(tif.hwndMenuOwner),
			LODWORD(tif.hwndMoveSize), LODWORD(tif.hwndCaret), LOGRECTCOORDS(tif.rcCaret));
		LogString(szInfo);
	}

	return tif.hwndFocus;
}
BOOL WindowUtil_isFocused(HWND hwnd) {
	HWND focused_hwnd;
	HWND child, parent;
	GUITHREADINFO thread_infos;
	char className[CONSOLE_WINDOW_CLASS_SIZE];

	thread_infos.cbSize = sizeof(GUITHREADINFO);
	if (! GetGUIThreadInfo(GetWindowThreadProcessId(hwnd, NULL), &thread_infos)) {
		return FALSE;
	}

	focused_hwnd = thread_infos.hwndFocus;

	if (GetClassName(hwnd, className, CONSOLE_WINDOW_CLASS_SIZE) == CONSOLE_WINDOW_CLASS_SIZE - 1)
		if (strncmp(CONSOLE_WINDOW_CLASS_NAME, className, CONSOLE_WINDOW_CLASS_SIZE) == 0)
			return (thread_infos.hwndCaret == hwnd);

	if (focused_hwnd == NULL)
		return FALSE;

	if (focused_hwnd == hwnd)
		return TRUE;

	parent = focused_hwnd;
	do {
		child = parent;

		parent = GetParent(child);
	} while(parent);

	return (child == hwnd);
}
Exemple #5
0
///////////////////////////////////////////////////////////////////////////////
// Finds out which window has the focus
HWND RemoteGetFocus()
{
	GUITHREADINFO remoteThreadInfo;
	remoteThreadInfo.cbSize = sizeof(GUITHREADINFO);
	if(!GetGUIThreadInfo(0, &remoteThreadInfo))
	{
		return NULL;
	}

	return remoteThreadInfo.hwndFocus ? remoteThreadInfo.hwndFocus : remoteThreadInfo.hwndActive;
}
bool IsInActiveWindow(HWND hwnd)
{
  GUITHREADINFO guit; guit.cbSize = sizeof(guit);
  if(GetGUIThreadInfo(NULL, &guit))
  {
    while( ::IsWindow(hwnd) )
    {
      if( hwnd == guit.hwndActive ) return true;
      hwnd = ::GetParent(hwnd);
    }
  }
  return false;
}
LRESULT _etk_hide_window(EWin32GraphicsEngine *win32Engine, etk_win32_gdi_callback_t *callback)
{
	if(win32Engine == NULL || callback == NULL ||
	   callback->command != WM_ETK_MESSAGE_HIDE_WINDOW || callback->win == NULL ||
	   callback->win->win32Window == NULL) return FALSE;

	EAutolock <EWin32GraphicsEngine> autolock(win32Engine);
	if(autolock.IsLocked() == false || win32Engine->InitCheck() != E_OK) return FALSE;

	ShowWindowAsync(callback->win->win32Window, SW_HIDE);

	GUITHREADINFO info;
	info.cbSize = sizeof(GUITHREADINFO);
	GetGUIThreadInfo(win32Engine->win32ThreadID, &info);
	if(info.hwndCapture == callback->win->win32Window) ReleaseCapture();

	return TRUE;
}
DWORD Applet::GetCurrentActiveThread()
{
  HWND hwnd = GetForegroundWindow();
  DWORD threadId = GetWindowThreadProcessId(hwnd, NULL);

  // Get GUI thread information
  GUITHREADINFO gui;
  ZeroMemory(&gui, sizeof(GUITHREADINFO));
  gui.cbSize = sizeof(GUITHREADINFO);
  GetGUIThreadInfo(threadId, &gui);

  // Get the most interesting hwnd of an application
  HWND active = (gui.hwndCaret != NULL) ? gui.hwndCaret :
                (gui.hwndFocus != NULL) ? gui.hwndFocus :
                (gui.hwndActive != NULL) ? gui.hwndActive : hwnd;

  return (active != hwnd) ? GetWindowThreadProcessId(active, NULL) : threadId;
}
Exemple #9
0
VOID
KbdTestGetKeyNameText()
{
	WCHAR text[20];
	HWND hForegroundWnd = NULL;
	DWORD threadId = 0;
	HKL hCurrKL = NULL;
	BYTE btKeyState[256];
	UINT scanCode = 21;
	GUITHREADINFO threadInfo;
	DWORD focusThread = NULL;
	hForegroundWnd = GetForegroundWindow();
	threadId = GetWindowThreadProcessId(hForegroundWnd, NULL);

	DebugPrint(L"hForegroundWnd=%x, threadId=%x\n", hForegroundWnd, threadId);
	memset(&threadInfo, 0, sizeof(threadInfo));
	threadInfo.cbSize = sizeof(threadInfo);

	if (!GetGUIThreadInfo(threadId, &threadInfo)) {
		DebugPrint(L"GetGUIThreadInfo failed with err=%x for threadId=%x", GetLastError(), threadId);
	}

	DebugPrint(L"thread.hwndFocus=%x\n", threadInfo.hwndFocus);
	focusThread = GetWindowThreadProcessId(threadInfo.hwndFocus, NULL);
	DebugPrint(L"focusThread=%x\n", focusThread);

	hCurrKL = GetKeyboardLayout(threadId);
	DebugPrint(L"Thread hKL=%x\n", hCurrKL);

	for (int i = 0; i < 10; i++) {
		hCurrKL = ActivateKeyboardLayout((HKL)HKL_NEXT, 0);
		DebugPrint(L"ActivateKeyboardLayout:prevHKL=%x\n", hCurrKL);
		hCurrKL = GetKeyboardLayout(0);
		DebugPrint(L"Curr thread hKL=%x\n", hCurrKL);

		//GetKeyboardState(btKeyState);
		memset(btKeyState, 0, sizeof(btKeyState));
		memset(text, 0, sizeof(text));
		ToUnicodeEx(MapVirtualKey(scanCode, MAPVK_VSC_TO_VK_EX), scanCode, btKeyState, text, RTL_NUMBER_OF(text), 0, hCurrKL);
		DebugPrint(L"ToUnicodeEx text is=%ws, unicode=%x\n", text, (USHORT)text[0]);
	}
}
Exemple #10
0
//---------------------------------------------------------------------------
// 函数:	g_MessageBox
// 功能:	Display a System Message Box
// 参数:	char* lpMsg, ...
//---------------------------------------------------------------------------
C_ENGINE_API
void g_MessageBox(const char* lpMsg, ...)
{
    char szMsg[1024];
    va_list va;
    va_start(va, lpMsg);
    vsprintf(szMsg, lpMsg, va);
    va_end(va);
    g_DebugLog(szMsg);

#ifndef __linux
    HWND	hWnd = NULL;
    GUITHREADINFO	info;
    memset(&info, 0, sizeof(info));
    info.cbSize = sizeof(info);
    if (GetGUIThreadInfo(NULL, &info))
        hWnd = info.hwndActive;
    MessageBox(hWnd, szMsg, 0, MB_OK | MB_ICONINFORMATION);
#endif
}
LRESULT _etk_get_window_activate_state(EWin32GraphicsEngine *win32Engine, etk_win32_gdi_callback_t *callback)
{
	if(win32Engine == NULL || callback == NULL ||
	   callback->command != WM_ETK_MESSAGE_GET_WINDOW_ACTIVATE_STATE || callback->win == NULL ||
	   callback->win->win32Window == NULL) return FALSE;

	EAutolock <EWin32GraphicsEngine> autolock(win32Engine);
	if(autolock.IsLocked() == false || win32Engine->InitCheck() != E_OK) return FALSE;

	bool activate_state = false;

	GUITHREADINFO info;
	info.cbSize = sizeof(GUITHREADINFO);
	if(!(GetGUIThreadInfo(win32Engine->win32ThreadID, &info) == 0 ||
	     info.hwndActive != callback->win->win32Window ||
	     GetForegroundWindow() != callback->win->win32Window)) activate_state = true;

	callback->activate_state = activate_state;

	return TRUE;
}
LRESULT _etk_activate_window(EWin32GraphicsEngine *win32Engine, etk_win32_gdi_callback_t *callback)
{
	if(win32Engine == NULL || callback == NULL ||
	   callback->command != WM_ETK_MESSAGE_ACTIVATE_WINDOW || callback->win == NULL ||
	   callback->win->win32Window == NULL) return FALSE;

	EAutolock <EWin32GraphicsEngine> autolock(win32Engine);
	if(autolock.IsLocked() == false || win32Engine->InitCheck() != E_OK) return FALSE;

	if(callback->activate_state)
	{
		if(IsWindowVisible(callback->win->win32Window) == 0)
		{
			callback->win->fActivateWhenShown = callback->activate_state;
			return TRUE;
		}
#if 0
		DWORD tidForeground = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
		eint8 otherThread = (tidForeground == win32Engine->win32ThreadID ? 0 : 1);
		BOOL retVal = FALSE;
		if(otherThread == 1) otherThread = (AttachThreadInput(tidForeground, win32Engine->win32ThreadID, TRUE) == 0 ? 2 : 1);
		if(otherThread <= 1) retVal = (SetForegroundWindow(callback->win->win32Window) == 0 ? FALSE : TRUE);
		if(otherThread == 1) AttachThreadInput(tidForeground, win32Engine->win32ThreadID, FALSE);
		if(retVal) retVal = (SetActiveWindow(callback->win->win32Window) == NULL ? (GetLastError() == 0) : TRUE);
		return retVal;
#endif
		return(SetActiveWindow(callback->win->win32Window) == NULL ? (GetLastError() == 0) : TRUE);
	}
	else
	{
		GUITHREADINFO info;
		info.cbSize = sizeof(GUITHREADINFO);
		GetGUIThreadInfo(win32Engine->win32ThreadID, &info);
		if(info.hwndCapture == callback->win->win32Window) ReleaseCapture();
		PostMessageA(callback->win->win32Window, WM_NCACTIVATE, FALSE, 0);
	}

	return TRUE;
}
/*******************************************************************
 *		set_active_window
 */
static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
{
    HWND previous = GetActiveWindow();
    BOOL ret;
    DWORD old_thread, new_thread;
    CBTACTIVATESTRUCT cbt;

    if (previous == hwnd)
    {
        if (prev) *prev = hwnd;
        return TRUE;
    }

    /* call CBT hook chain */
    cbt.fMouse     = mouse;
    cbt.hWndActive = previous;
    if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;

    if (IsWindow(previous))
    {
        SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
        SendMessageW( previous, WM_ACTIVATE,
                      MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
    }

    SERVER_START_REQ( set_active_window )
    {
        req->handle = wine_server_user_handle( hwnd );
        if ((ret = !wine_server_call_err( req )))
            previous = wine_server_ptr_handle( reply->previous );
    }
    SERVER_END_REQ;
    if (!ret) return FALSE;
    if (prev) *prev = previous;
    if (previous == hwnd) return TRUE;

    if (hwnd)
    {
        /* send palette messages */
        if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
            SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
                                 SMTO_ABORTIFHUNG, 2000, NULL );
        if (!IsWindow(hwnd)) return FALSE;
    }

    old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
    new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;

    if (old_thread != new_thread)
    {
        HWND *list, *phwnd;

        if ((list = WIN_ListChildren( GetDesktopWindow() )))
        {
            if (old_thread)
            {
                for (phwnd = list; *phwnd; phwnd++)
                {
                    if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
                        SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
                }
            }
            if (new_thread)
            {
                for (phwnd = list; *phwnd; phwnd++)
                {
                    if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
                        SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
                }
            }
            HeapFree( GetProcessHeap(), 0, list );
        }
    }

    if (IsWindow(hwnd))
    {
        SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
        SendMessageW( hwnd, WM_ACTIVATE,
                      MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
                      (LPARAM)previous );
        if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
            PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );

        if (hwnd == GetForegroundWindow() && !IsIconic( hwnd ))
            USER_Driver->pSetActiveWindow( hwnd );
    }

    /* now change focus if necessary */
    if (focus)
    {
        GUITHREADINFO info;

        info.cbSize = sizeof(info);
        GetGUIThreadInfo( GetCurrentThreadId(), &info );
        /* Do not change focus if the window is no more active */
        if (hwnd == info.hwndActive)
        {
            if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
                set_focus_window( hwnd );
        }
    }

    return TRUE;
}
Exemple #14
0
static bool OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
  if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false;

  GUITHREADINFO info;
  memset(&info, 0, sizeof(GUITHREADINFO));
  info.cbSize = sizeof(GUITHREADINFO);
  GetGUIThreadInfo(GetCurrentThreadId(), &info);
  Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
  if(object == nullptr) return false;

  if(dynamic_cast<Window*>(object)) {
    Window &window = (Window&)*object;
    if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false;
    Keyboard::Keycode keysym = Keysym(wparam, lparam);
    if(keysym != Keyboard::Keycode::None) {
      if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym);
      if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym);
    }
    return false;
  }

  if(msg == WM_KEYDOWN) {
    if(dynamic_cast<ListView*>(object)) {
      ListView &listView = (ListView&)*object;
      if(wparam == VK_RETURN) {
        if(listView.onActivate) listView.onActivate();
      }
    } else if(dynamic_cast<LineEdit*>(object)) {
      LineEdit &lineEdit = (LineEdit&)*object;
      if(wparam == VK_RETURN) {
        if(lineEdit.onActivate) lineEdit.onActivate();
      }
    } else if(dynamic_cast<TextEdit*>(object)) {
      TextEdit &textEdit = (TextEdit&)*object;
      if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) {
        //Ctrl+A = select all text
        //note: this is not a standard accelerator on Windows
        Edit_SetSel(textEdit.p.hwnd, 0, ~0);
        return true;
      } else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) {
        //Ctrl+V = paste text
        //note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings
        //this is necessary as the EDIT control only supports Windows line-endings
        OpenClipboard(hwnd);
        HANDLE handle = GetClipboardData(CF_UNICODETEXT);
        if(handle) {
          wchar_t *text = (wchar_t*)GlobalLock(handle);
          if(text) {
            string data = (const char*)utf8_t(text);
            data.replace("\r\n", "\n");
            data.replace("\r", "\n");
            data.replace("\n", "\r\n");
            GlobalUnlock(handle);
            utf16_t output(data);
            HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t));
            if(resource) {
              wchar_t *write = (wchar_t*)GlobalLock(resource);
              if(write) {
                wcscpy(write, output);
                GlobalUnlock(write);
                if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) {
                  GlobalFree(resource);
                }
              }
            }
          }
        }
        CloseClipboard();
        return false;
      }
    }
  }

  return false;
}
Exemple #15
0
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId;

    switch (message)
    {
        case WM_TIMER:
        {
            BOOL hasMoved = FALSE;

            GUITHREADINFO guiInfo;
            guiInfo.cbSize = sizeof(guiInfo);

            GetGUIThreadInfo(0, &guiInfo);

            if (bFollowMouse)
            {
                POINT pNewMouse;

                //Get current mouse position
                GetCursorPos (&pNewMouse);

#define PointsAreEqual(pt1, pt2) (((pt1).x == (pt2).x) && ((pt1).y == (pt2).y))

                //If mouse has moved ...
                if (!PointsAreEqual(pMouse, pNewMouse))
                {
                    //Update to new position
                    pMouse = pNewMouse;
                    cp = pNewMouse;
                    hasMoved = TRUE;
                }
            }

            if(guiInfo.hwndActive != hMainWnd)
            {
                if (bFollowCaret)
                {
                    if (guiInfo.hwndCaret)
                    {
                        POINT ptCaret;
                        ptCaret.x = (guiInfo.rcCaret.left + guiInfo.rcCaret.right) / 2;
                        ptCaret.y = (guiInfo.rcCaret.top + guiInfo.rcCaret.bottom) / 2;

                        if ((pCaretWnd != guiInfo.hwndCaret) || !PointsAreEqual(pCaret, ptCaret))
                        {
                            //Update to new position
                            pCaret = ptCaret;
                            pCaretWnd = guiInfo.hwndCaret;
                            if(!hasMoved)
                            {
                                ClientToScreen (guiInfo.hwndCaret, (LPPOINT) &ptCaret);
                                cp = ptCaret;
                                hasMoved = TRUE;
                            }
                        }
                    }
                    else
                    {
                        pCaretWnd = NULL;
                    }
                }

                if (bFollowFocus)
                {
                    if(guiInfo.hwndFocus && !guiInfo.hwndCaret)
                    {
                        POINT ptFocus;
                        RECT activeRect;

                        //Get current control focus
                        GetWindowRect(guiInfo.hwndFocus, &activeRect);
                        ptFocus.x = (activeRect.left + activeRect.right) / 2;
                        ptFocus.y = (activeRect.top + activeRect.bottom) / 2;

                        if((guiInfo.hwndFocus != pFocusWnd) || !PointsAreEqual(pFocus, ptFocus))
                        {
                            //Update to new position
                            pFocus = ptFocus;
                            pFocusWnd = guiInfo.hwndFocus;
                            if(!hasMoved)
                            {
                                cp = ptFocus;
                                hasMoved = TRUE;
                            }
                        }
                    }
                    else
                    {
                        pFocusWnd = NULL;
                    }
                }
            }

            if(!hasMoved)
            {
                DWORD newTicks = GetTickCount();
                DWORD elapsed = (newTicks - lastTicks);
                if(elapsed > REPAINT_SPEED)
                {
                    hasMoved = TRUE;
                }
            }

            if(hasMoved)
            {
                lastTicks = GetTickCount();
                Refresh();
            }

            return 0;
        }

        case WM_COMMAND:
        {
            wmId = LOWORD(wParam);
            /* Parse the menu selections */
            switch (wmId)
            {
                case IDM_OPTIONS:
                    if(bOptionsDialog)
                    {
                        ShowWindow(hOptionsDialog, SW_HIDE);
                    }
                    else
                    {
                        ShowWindow(hOptionsDialog, SW_SHOW);
                    }
                    break;
                case IDM_ABOUT:
                    DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutProc);
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
            }
            return 0;
        }

        case WM_PAINT:
        {
            PAINTSTRUCT PaintStruct;
            HDC dc;
            dc = BeginPaint(hWnd, &PaintStruct);
            Draw(dc);
            EndPaint(hWnd, &PaintStruct);
            return 0;
        }

        case WM_CONTEXTMENU:
            TrackPopupMenu(notifyMenu, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hWnd, NULL);
            return 0;

        case WM_LBUTTONDOWN:
        {
            RECT rc;
            POINT pt;
            SetCapture(hWnd);

            GetCursorPos(&pt);
            GetWindowRect(hWnd, &rc);
            ptDragOffset.x = pt.x - rc.left;
            ptDragOffset.y = pt.y - rc.top;

            nearEdge = AppBarConfig.uEdge;

            break;
        }
        case WM_MOUSEMOVE:
            if(GetCapture() == hWnd)
            {
                RECT rc;
                POINT pt;
                RECT rcWorkArea;
                SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
                GetCursorPos(&pt);
                GetWindowRect(hWnd, &rc);

                if(AppBarConfig.uEdge>=0)
                {
                    if (pt.x >= rcWorkArea.left && pt.x <= rcWorkArea.right &&
                        pt.y >= rcWorkArea.top && pt.y <= rcWorkArea.bottom)
                    {
                        AttachAppBar(-2);

                        // Fixup offset
                        GetWindowRect(hWnd, &rc);
                        ptDragOffset.x = (rc.right-rc.left)/2;
                        ptDragOffset.y = 2;

                        rc.left = pt.x - ptDragOffset.x;
                        rc.top = pt.y - ptDragOffset.y;

                        SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
                    }
                }
                else
                {
                    if(pt.x <= rcWorkArea.left+8 && nearEdge != ABE_LEFT)
                    {
                        AttachAppBar(ABE_LEFT);
                        nearEdge = ABE_LEFT;
                    }
                    else if(pt.y <= rcWorkArea.top+8 && nearEdge != ABE_TOP)
                    {
                        AttachAppBar(ABE_TOP);
                        nearEdge = ABE_TOP;
                    }
                    else if(pt.x >= rcWorkArea.right-8 && nearEdge != ABE_RIGHT)
                    {
                        AttachAppBar(ABE_RIGHT);
                        nearEdge = ABE_RIGHT;
                    }
                    else if(pt.y >= rcWorkArea.bottom-8 && nearEdge != ABE_BOTTOM)
                    {
                        AttachAppBar(ABE_BOTTOM);
                        nearEdge = ABE_BOTTOM;
                    }
                    else
                    {
                        rc.left = pt.x - ptDragOffset.x;
                        rc.top = pt.y - ptDragOffset.y;

                        SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
                        nearEdge = -1;
                    }
                }

                pMouse = pt;
                Refresh();
            }
            break;
        case WM_LBUTTONUP:
            if(GetCapture() == hWnd)
            {
                if (AppBarConfig.uEdge>=0)
                    DoAppBarStuff(ABM_GETSTATE);
                else
                    SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
                ReleaseCapture();
            }
            break;

        case WM_SIZE:
            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_SETPOS);
            /* fallthrough */
        case WM_DISPLAYCHANGE:
            bRecreateOffscreenDC = TRUE;
            Refresh();
            break;

        case WM_ERASEBKGND:
            // handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
            return 0;

        case WM_DESTROY:
        {
            if (AppBarConfig.uEdge >= 0)
                DoAppBarStuff(ABM_REMOVE);

            KillTimer(hWnd, 1);

            /* Save settings to registry */
            SaveSettings();

            /* Cleanup notification icon */
            ZeroMemory(&nid, sizeof(nid));
            nid.cbSize = sizeof(nid);
            nid.uFlags = NIF_MESSAGE;
            nid.hWnd = hWnd;
            nid.uCallbackMessage = APPMSG_NOTIFYICON;
            Shell_NotifyIcon(NIM_DELETE, &nid);
            DestroyIcon(notifyIcon);

            DestroyWindow(hOptionsDialog);

            PostQuitMessage(0);
            return 0;
        }

        case WM_CREATE:
        {
            HMENU tempMenu;

            /* Get the desktop window */
            hDesktopWindow = GetDesktopWindow();

            /* Set the timer */
            SetTimer(hWnd, 1, TIMER_SPEED, NULL);

            /* Notification icon */
            notifyIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);

            ZeroMemory(&nid, sizeof(nid));
            nid.cbSize = sizeof(nid);
            nid.uFlags = NIF_ICON | NIF_MESSAGE;
            nid.hWnd = hWnd;
            nid.uCallbackMessage = APPMSG_NOTIFYICON;
            nid.hIcon = notifyIcon;
            Shell_NotifyIcon(NIM_ADD, &nid);

            tempMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_MAGNIFIER));
            notifyMenu = GetSubMenu(tempMenu, 0);
            RemoveMenu(tempMenu, 0, MF_BYPOSITION);
            DestroyMenu(tempMenu);
            return 0;
        }

        case APPMSG_APPBAR:
        {
            switch (wParam)
            {
                case ABN_STATECHANGE:
                    DoAppBarStuff(ABM_GETSTATE);
                    break;
                case ABN_POSCHANGED:
                    DoAppBarStuff(ABM_SETPOS);
                    break;
                case ABN_FULLSCREENAPP:
                {
                    if(!lParam)
                    {
                        DoAppBarStuff(ABM_GETSTATE);
                        break;
                    }

                    SetWindowPos(hMainWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
                    break;
                }
               case ABN_WINDOWARRANGE:
                    if(lParam)
                        ShowWindow(hMainWnd, SW_HIDE);
                    else
                        ShowWindow(hMainWnd, SW_SHOW);
                    break;
            }
            return 0;
        }

        case APPMSG_NOTIFYICON:
            HandleNotifyIconMessage(hWnd, wParam, lParam);
            return 0;

        case WM_ACTIVATE:
            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_ACTIVATE);
            break;

        case WM_WINDOWPOSCHANGED:
            if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_WINDOWPOSCHANGED);
            Refresh();
            break;

        default:
            break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}
VOID PhpThreadProviderUpdate(
    _In_ PPH_THREAD_PROVIDER ThreadProvider,
    _In_ PVOID ProcessInformation
    )
{
    PPH_THREAD_PROVIDER threadProvider = ThreadProvider;
    PSYSTEM_PROCESS_INFORMATION process;
    SYSTEM_PROCESS_INFORMATION localProcess;
    PSYSTEM_THREAD_INFORMATION threads;
    ULONG numberOfThreads;
    ULONG i;

    process = PhFindProcessInformation(ProcessInformation, threadProvider->ProcessId);

    if (!process)
    {
        // The process doesn't exist anymore. Pretend it does but
        // has no threads.
        process = &localProcess;
        process->NumberOfThreads = 0;
    }

    threads = process->Threads;
    numberOfThreads = process->NumberOfThreads;

    // System Idle Process has one thread per CPU.
    // They all have a TID of 0, but we can't have
    // multiple TIDs, so we'll assign unique TIDs.
    if (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID)
    {
        for (i = 0; i < numberOfThreads; i++)
        {
            threads[i].ClientId.UniqueThread = UlongToHandle(i);
        }
    }

    // Look for dead threads.
    {
        PPH_LIST threadsToRemove = NULL;
        ULONG enumerationKey = 0;
        PPH_THREAD_ITEM *threadItem;

        while (PhEnumHashtable(threadProvider->ThreadHashtable, (PVOID *)&threadItem, &enumerationKey))
        {
            BOOLEAN found = FALSE;

            // Check if the thread still exists.
            for (i = 0; i < numberOfThreads; i++)
            {
                PSYSTEM_THREAD_INFORMATION thread = &threads[i];

                if ((*threadItem)->ThreadId == thread->ClientId.UniqueThread)
                {
                    found = TRUE;
                    break;
                }
            }

            if (!found)
            {
                // Raise the thread removed event.
                PhInvokeCallback(&threadProvider->ThreadRemovedEvent, *threadItem);

                if (!threadsToRemove)
                    threadsToRemove = PhCreateList(2);

                PhAddItemList(threadsToRemove, *threadItem);
            }
        }

        if (threadsToRemove)
        {
            PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock);

            for (i = 0; i < threadsToRemove->Count; i++)
            {
                PhpRemoveThreadItem(
                    threadProvider,
                    (PPH_THREAD_ITEM)threadsToRemove->Items[i]
                    );
            }

            PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock);
            PhDereferenceObject(threadsToRemove);
        }
    }

    // Go through the queued thread query data.
    {
        PSLIST_ENTRY entry;
        PPH_THREAD_QUERY_DATA data;

        entry = RtlInterlockedFlushSList(&threadProvider->QueryListHead);

        while (entry)
        {
            data = CONTAINING_RECORD(entry, PH_THREAD_QUERY_DATA, ListEntry);
            entry = entry->Next;

            if (data->StartAddressResolveLevel == PhsrlFunction && data->StartAddressString)
            {
                PhSwapReference(&data->ThreadItem->StartAddressString, data->StartAddressString);
                data->ThreadItem->StartAddressResolveLevel = data->StartAddressResolveLevel;
            }

            PhMoveReference(&data->ThreadItem->ServiceName, data->ServiceName);

            data->ThreadItem->JustResolved = TRUE;

            if (data->StartAddressString) PhDereferenceObject(data->StartAddressString);
            PhDereferenceObject(data->ThreadItem);
            PhFree(data);
        }
    }

    // Look for new threads and update existing ones.
    for (i = 0; i < numberOfThreads; i++)
    {
        PSYSTEM_THREAD_INFORMATION thread = &threads[i];
        PPH_THREAD_ITEM threadItem;

        threadItem = PhReferenceThreadItem(threadProvider, thread->ClientId.UniqueThread);

        if (!threadItem)
        {
            PVOID startAddress = NULL;

            threadItem = PhCreateThreadItem(thread->ClientId.UniqueThread);

            threadItem->CreateTime = thread->CreateTime;
            threadItem->KernelTime = thread->KernelTime;
            threadItem->UserTime = thread->UserTime;

            PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches);
            threadItem->Priority = thread->Priority;
            threadItem->BasePriority = thread->BasePriority;
            threadItem->State = (KTHREAD_STATE)thread->ThreadState;
            threadItem->WaitReason = thread->WaitReason;

            // Try to open a handle to the thread.
            if (!NT_SUCCESS(PhOpenThread(
                &threadItem->ThreadHandle,
                THREAD_QUERY_INFORMATION,
                threadItem->ThreadId
                )))
            {
                PhOpenThread(
                    &threadItem->ThreadHandle,
                    ThreadQueryAccess,
                    threadItem->ThreadId
                    );
            }

            // Get the cycle count.
            if (WINDOWS_HAS_CYCLE_TIME)
            {
                ULONG64 cycles;

                if (NT_SUCCESS(PhpGetThreadCycleTime(
                    threadProvider,
                    threadItem,
                    &cycles
                    )))
                {
                    PhUpdateDelta(&threadItem->CyclesDelta, cycles);
                }
            }

            // Initialize the CPU time deltas.
            PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);
            PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);

            // Try to get the start address.

            if (threadItem->ThreadHandle)
            {
                NtQueryInformationThread(
                    threadItem->ThreadHandle,
                    ThreadQuerySetWin32StartAddress,
                    &startAddress,
                    sizeof(PVOID),
                    NULL
                    );
            }

            if (!startAddress)
                startAddress = thread->StartAddress;

            threadItem->StartAddress = (ULONG64)startAddress;

            // Get the Win32 priority.
            threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle);

            if (threadProvider->SymbolsLoadedRunId != 0)
            {
                threadItem->StartAddressString = PhpGetThreadBasicStartAddress(
                    threadProvider,
                    threadItem->StartAddress,
                    &threadItem->StartAddressResolveLevel
                    );
            }

            if (!threadItem->StartAddressString)
            {
                threadItem->StartAddressResolveLevel = PhsrlAddress;
                threadItem->StartAddressString = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2);
                PhPrintPointer(
                    threadItem->StartAddressString->Buffer,
                    (PVOID)threadItem->StartAddress
                    );
                PhTrimToNullTerminatorString(threadItem->StartAddressString);
            }

            PhpQueueThreadQuery(threadProvider, threadItem);

            // Is it a GUI thread?

            if (threadItem->ThreadHandle && KphIsConnected())
            {
                PVOID win32Thread;

                if (NT_SUCCESS(KphQueryInformationThread(
                    threadItem->ThreadHandle,
                    KphThreadWin32Thread,
                    &win32Thread,
                    sizeof(PVOID),
                    NULL
                    )))
                {
                    threadItem->IsGuiThread = win32Thread != NULL;
                }
            }
            else
            {
                GUITHREADINFO info = { sizeof(GUITHREADINFO) };

                threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info);
            }

            // Add the thread item to the hashtable.
            PhAcquireFastLockExclusive(&threadProvider->ThreadHashtableLock);
            PhAddEntryHashtable(threadProvider->ThreadHashtable, &threadItem);
            PhReleaseFastLockExclusive(&threadProvider->ThreadHashtableLock);

            // Raise the thread added event.
            PhInvokeCallback(&threadProvider->ThreadAddedEvent, threadItem);
        }
        else
        {
            BOOLEAN modified = FALSE;

            if (threadItem->JustResolved)
                modified = TRUE;

            threadItem->KernelTime = thread->KernelTime;
            threadItem->UserTime = thread->UserTime;

            threadItem->Priority = thread->Priority;
            threadItem->BasePriority = thread->BasePriority;

            threadItem->State = (KTHREAD_STATE)thread->ThreadState;

            if (threadItem->WaitReason != thread->WaitReason)
            {
                threadItem->WaitReason = thread->WaitReason;
                modified = TRUE;
            }

            // If the resolve level is only at address, it probably
            // means symbols weren't loaded the last time we
            // tried to get the start address. Try again.
            if (threadItem->StartAddressResolveLevel == PhsrlAddress)
            {
                if (threadProvider->SymbolsLoadedRunId != 0)
                {
                    PPH_STRING newStartAddressString;

                    newStartAddressString = PhpGetThreadBasicStartAddress(
                        threadProvider,
                        threadItem->StartAddress,
                        &threadItem->StartAddressResolveLevel
                        );

                    PhMoveReference(
                        &threadItem->StartAddressString,
                        newStartAddressString
                        );

                    modified = TRUE;
                }
            }

            // If we couldn't resolve the start address to a
            // module+offset, use the StartAddress instead
            // of the Win32StartAddress and try again.
            // Note that we check the resolve level again
            // because we may have changed it in the previous
            // block.
            if (threadItem->JustResolved &&
                threadItem->StartAddressResolveLevel == PhsrlAddress)
            {
                if (threadItem->StartAddress != (ULONG64)thread->StartAddress)
                {
                    threadItem->StartAddress = (ULONG64)thread->StartAddress;
                    PhpQueueThreadQuery(threadProvider, threadItem);
                }
            }

            // Update the context switch count.
            {
                ULONG oldDelta;

                oldDelta = threadItem->ContextSwitchesDelta.Delta;
                PhUpdateDelta(&threadItem->ContextSwitchesDelta, thread->ContextSwitches);

                if (threadItem->ContextSwitchesDelta.Delta != oldDelta)
                {
                    modified = TRUE;
                }
            }

            // Update the cycle count.
            if (WINDOWS_HAS_CYCLE_TIME)
            {
                ULONG64 cycles;
                ULONG64 oldDelta;

                oldDelta = threadItem->CyclesDelta.Delta;

                if (NT_SUCCESS(PhpGetThreadCycleTime(
                    threadProvider,
                    threadItem,
                    &cycles
                    )))
                {
                    PhUpdateDelta(&threadItem->CyclesDelta, cycles);

                    if (threadItem->CyclesDelta.Delta != oldDelta)
                    {
                        modified = TRUE;
                    }
                }
            }

            // Update the CPU time deltas.
            PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);
            PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);

            // Update the CPU usage.
            // If the cycle time isn't available, we'll fall back to using the CPU time.
            if (WINDOWS_HAS_CYCLE_TIME && PhEnableCycleCpuUsage && (threadProvider->ProcessId == SYSTEM_IDLE_PROCESS_ID || threadItem->ThreadHandle))
            {
                threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta;
            }
            else
            {
                threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) /
                    (PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta);
            }

            // Update the Win32 priority.
            {
                LONG oldPriorityWin32 = threadItem->PriorityWin32;

                threadItem->PriorityWin32 = GetThreadPriority(threadItem->ThreadHandle);

                if (threadItem->PriorityWin32 != oldPriorityWin32)
                {
                    modified = TRUE;
                }
            }

            // Update the GUI thread status.

            if (threadItem->ThreadHandle && KphIsConnected())
            {
                PVOID win32Thread;

                if (NT_SUCCESS(KphQueryInformationThread(
                    threadItem->ThreadHandle,
                    KphThreadWin32Thread,
                    &win32Thread,
                    sizeof(PVOID),
                    NULL
                    )))
                {
                    BOOLEAN oldIsGuiThread = threadItem->IsGuiThread;

                    threadItem->IsGuiThread = win32Thread != NULL;

                    if (threadItem->IsGuiThread != oldIsGuiThread)
                        modified = TRUE;
                }
            }
            else
            {
                GUITHREADINFO info = { sizeof(GUITHREADINFO) };
                BOOLEAN oldIsGuiThread = threadItem->IsGuiThread;

                threadItem->IsGuiThread = !!GetGUIThreadInfo(HandleToUlong(threadItem->ThreadId), &info);

                if (threadItem->IsGuiThread != oldIsGuiThread)
                    modified = TRUE;
            }

            threadItem->JustResolved = FALSE;

            if (modified)
            {
                // Raise the thread modified event.
                PhInvokeCallback(&threadProvider->ThreadModifiedEvent, threadItem);
            }

            PhDereferenceObject(threadItem);
        }
    }

    PhInvokeCallback(&threadProvider->UpdatedEvent, NULL);
    threadProvider->RunId++;
}