Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save aont/d6121f6318fcdf427244bb21ebd727b2 to your computer and use it in GitHub Desktop.

Select an option

Save aont/d6121f6318fcdf427244bb21ebd727b2 to your computer and use it in GitHub Desktop.

ActivateHwnd: A Tiny Utility to Focus Any Window by Handle

This small C++ program, ActivateHwnd.exe, brings an existing Windows GUI window to the foreground when you provide its window handle (an HWND) on the command line. It accepts either hexadecimal (e.g., 0xABC) or decimal (e.g., 12345) formats and uses several Win32 APIs to restore, raise, and focus that window as reliably as possible.

What the Program Does

  1. Parses the handle you pass in. The function ParseHwnd trims whitespace, detects whether the input is hex or decimal (by checking for 0x/0X or A–F digits), and converts it to an integer. It then casts that value to an HWND. Invalid formats are rejected early with a clear error.

  2. Validates the target window. IsWindow(target) ensures the handle really belongs to a live window. If not, the program exits with an error.

  3. Temporarily links input queues (if needed). Foreground activation can fail if threads don’t share input. The code gets:

    • the current thread (GetCurrentThreadId()),
    • the current foreground window and its GUI thread (GetForegroundWindow() / GetWindowThreadProcessId()), then calls AttachThreadInput(TRUE) to link the threads when they differ. This increases the chance that focus changes will succeed.
  4. Attempts several activation strategies. The program tries a sequence of gentle-to-strong nudges:

    • If minimized, restore: ShowWindow(target, SW_RESTORE).
    • Raise and show: SetWindowPos(target, HWND_TOP, …, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_ASYNCWINDOWPOS).
    • Set as foreground: SetForegroundWindow(target).
    • Bring to top: BringWindowToTop(target).
    • Ensure visible: ShowWindow(target, SW_SHOW).
    • Give keyboard focus: SetFocus(target) (not all windows accept focus).

    Each step logs a descriptive error with PrintLastError if it fails, but the program keeps going—another step might succeed.

  5. Detaches input queues. If it attached earlier, it calls AttachThreadInput(FALSE) to restore the original state.

  6. Verifies success. Finally, it checks whether the target actually became the foreground window. If yes, it prints [OK]; otherwise, it warns that activation couldn’t be guaranteed.

Usage

ActivateHwnd.exe <HWND>
  e.g. ActivateHwnd.exe 0xABC
       ActivateHwnd.exe 12345

The handle can be copied from tools like Spy++, WinDbg, or your own diagnostics.

Error Reporting

PrintLastError uses FormatMessageA to display the failing API call, the numeric error code, and the system-provided message. This makes troubleshooting straightforward when activation is blocked by focus rules or window state.

Why It Uses Multiple APIs

Windows enforces rules to prevent apps from stealing focus. Depending on the current foreground window, thread relationships, and the target’s state (minimized, hidden, not focusable), a single call like SetForegroundWindow may fail. By:

  • optionally attaching input to the foreground thread,
  • restoring a minimized window,
  • raising it in Z-order,
  • and showing then focusing it,

the tool maximizes the odds of success without resorting to intrusive techniques.

Limitations and Notes

  • You must already know the correct HWND. If the window has closed or the handle is stale, IsWindow will fail.
  • Foreground protection policies may still prevent activation in some scenarios (the program reports this clearly).
  • Not all windows are focusable (e.g., tool windows without focus styles).

Takeaway

ActivateHwnd is a pragmatic, minimal utility: feed it a window handle, and it does everything reasonable—and cleanly reversible—to bring that window to the front and give it focus, with helpful diagnostics when Windows says “no.”

// ActivateHwnd.cpp
// Usage: ActivateHwnd.exe 0xABC or ActivateHwnd.exe 12345
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <iostream>
#include <string>
static bool ParseHwnd(const char* s, HWND& out)
{
if (!s) return false;
std::string t = s;
// Trim leading/trailing whitespace
auto l = t.find_first_not_of(" \t\r\n");
auto r = t.find_last_not_of(" \t\r\n");
if (l == std::string::npos) return false;
t = t.substr(l, r - l + 1);
if (t.empty()) return false;
// Decide between hex/decimal
bool hasHexPrefix = (t.size() >= 2 && (t[0] == '0') && (t[1] == 'x' || t[1] == 'X'));
bool hasHexLetter = false;
if (!hasHexPrefix) {
for (char c : t) {
if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { hasHexLetter = true; break; }
}
}
unsigned long long val = 0ull;
int scanned = 0;
if (hasHexPrefix) {
// Strip 0x/0X and read as hex
scanned = std::sscanf(t.c_str() + 2, "%llx", &val);
} else if (hasHexLetter) {
// Contains A-F -> treat as hex
scanned = std::sscanf(t.c_str(), "%llx", &val);
} else {
// Otherwise treat as decimal
scanned = std::sscanf(t.c_str(), "%llu", &val);
}
if (scanned != 1) return false;
out = reinterpret_cast<HWND>(static_cast<ULONG_PTR>(val));
return true;
}
static void PrintLastError(const char* api)
{
DWORD e = GetLastError();
if (e == 0) return;
LPSTR buf = nullptr;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPSTR>(&buf), 0, nullptr);
if (buf) {
std::cerr << "[!] " << api << " failed: (" << e << ") " << buf;
LocalFree(buf);
} else {
std::cerr << "[!] " << api << " failed: (" << e << ")\n";
}
}
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <HWND>\n"
<< " e.g. " << argv[0] << " 0xABC or " << argv[0] << " 12345\n";
return 1;
}
HWND target = nullptr;
if (!ParseHwnd(argv[1], target)) {
std::cerr << "[!] Invalid HWND format: " << argv[1] << "\n";
return 1;
}
if (!IsWindow(target)) {
std::cerr << "[!] Not a valid window: " << argv[1] << "\n";
return 2;
}
// 1) If needed, attach this thread to the GUI thread of the current foreground window
DWORD curTid = GetCurrentThreadId();
HWND fg = GetForegroundWindow();
DWORD fgTid = fg ? GetWindowThreadProcessId(fg, nullptr) : 0;
bool attached = false;
if (fg && fgTid != 0 && fgTid != curTid) {
if (AttachThreadInput(curTid, fgTid, TRUE)) {
attached = true;
} else {
PrintLastError("AttachThreadInput(TRUE)");
}
}
// 2) Bring to front / show / focus (apply fallbacks if some steps fail)
if (IsIconic(target)) {
ShowWindow(target, SW_RESTORE); // Continue even if this fails
}
if (!SetWindowPos(target, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS)) {
PrintLastError("SetWindowPos(HWND_TOP)");
}
if (!SetForegroundWindow(target)) {
PrintLastError("SetForegroundWindow");
}
if (!BringWindowToTop(target)) {
PrintLastError("BringWindowToTop");
}
ShowWindow(target, SW_SHOW); // false is not fatal (depends on previous visibility)
SetFocus(target); // May return NULL (not fatal if not focusable)
// 3) Detach if we attached earlier
if (attached) {
if (!AttachThreadInput(curTid, fgTid, FALSE)) {
PrintLastError("AttachThreadInput(FALSE)");
}
}
// Final check: did we actually become the foreground window?
HWND nowFg = GetForegroundWindow();
if (nowFg == target) {
std::cout << "[OK] Activated window: " << argv[1] << "\n";
return 0;
} else {
std::cerr << "[!] Could not guarantee activation (foreground differs).\n";
return 3;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment