__SetForegroundWindow DarkKaiser, 2009년 8월 24일2023년 9월 5일 출처 : Application Hacking ::SetForegroundWindow(), ::SetFocus()아 같은 API를 호출해서 프로그램 상에서 간단하게 상위 윈도우를 변경하거나 입력 포커스를 지정할 수 있지만, 이는 사용자가 마우스로 윈도우를 선택하거나 Alt+TAB, Alt+ESC를 입력해서 상위 윈도우를 지정하는 경우와는 다르게 동작한다.::SetForegroundWindow(), ::SetFocus()등의 API를 호출하는 스레드가 현재 입력을 처리하고 있는 상위 스레드가 아니라면, API에 의해서 설정된 윈도우는 작업 표시줄을 통해서 활성화 상태만 표시되고 사용자의 입력은 여전히 이전에 입력을 처리하던 윈도우로 전달된다. 하지만 ::AttachThreadInput() API를 사용해서 현재 입력을 처리하고 있는 스레드와 입력 상태를 공유할 수 있다. 이를 이용해서 사용자의 입력을 처리하는 스레드가 아니더라도 사용자의 입력 윈도우를 강제적으로 변경할 수 있다. BOOL __SetForegroundWindow(const HWND hWndTarget) { ASSERT(hWndTarget != NULL); BOOL bRet = FALSE; if (::IsWindow(hWndTarget) == FALSE) return bRet; BOOL bThreadAttached = FALSE; DWORD dwSourceTID = 0, dwSourcePID = 0; DWORD dwTargetTID = 0, dwTargetPID = 0; __try { HWND hwndForeground = ::GetForegroundWindow(); if (hwndForeground == NULL) __leave; // 입력 윈도우를 소유한 스레드를 구한다. dwSourceTID = ::GetWindowThreadProcessId(hwndForeground, &dwSourcePID); { if (::GetCurrentThreadId() == dwSourceTID) __leave; } // 새롭게 입력을 받을 윈도우를 소유한 스레드를 구한다. dwTargetTID = ::GetWindowThreadProcessId(hWndTarget, &dwTargetPID); bThreadAttached = ::AttachThreadInput(dwTargetTID, dwSourceTID, TRUE); if (bThreadAttached == FALSE) __leave; } __finally { bRet = ::SetForegroundWindow(hWndTarget); if (bThreadAttached == TRUE) { if (::AttachThreadInput(dwTargetTID, dwSourceTID, FALSE)) { ::OutputDebugString(_T("detach fail")); } } } return bRet; } BOOL __SetForegroundWindow(const HWND hWndTarget) { ASSERT(hWndTarget != NULL); BOOL bRet = FALSE; if (::IsWindow(hWndTarget) == FALSE) return bRet; BOOL bThreadAttached = FALSE; DWORD dwSourceTID = 0, dwSourcePID = 0; DWORD dwTargetTID = 0, dwTargetPID = 0; __try { HWND hwndForeground = ::GetForegroundWindow(); if (hwndForeground == NULL) __leave; // 입력 윈도우를 소유한 스레드를 구한다. dwSourceTID = ::GetWindowThreadProcessId(hwndForeground, &dwSourcePID); { if (::GetCurrentThreadId() == dwSourceTID) __leave; } // 새롭게 입력을 받을 윈도우를 소유한 스레드를 구한다. dwTargetTID = ::GetWindowThreadProcessId(hWndTarget, &dwTargetPID); bThreadAttached = ::AttachThreadInput(dwTargetTID, dwSourceTID, TRUE); if (bThreadAttached == FALSE) __leave; } __finally { bRet = ::SetForegroundWindow(hWndTarget); if (bThreadAttached == TRUE) { if (::AttachThreadInput(dwTargetTID, dwSourceTID, FALSE)) { ::OutputDebugString(_T("detach fail")); } } } return bRet; } C/C++/VC++