Можно ли на C++ программно сделать снимок активного окна, эквивалентный нажатию Alt+PrtSc?

Я пытаюсь сделать скриншот определённого окна по его HWND. Если приложение использует видеопамять (GPU), прямой захват окна даёт чёрный экран. При захвате всего рабочего стола и последующем вырезании нужной области результат корректный. Встроенное сочетание Alt+PrtSc снимает активное окно независимо от того, использует ли приложение видеопамять.
  • 8 июля 2026 г. 7:01
Ответы на вопрос 2
Короткий ответ — да, самый простой и надёжный способ получить именно то же изображение, что и Alt+PrtSc — программно смоделировать нажатие клавиш Alt+PrintScreen для активного окна, а затем взять картинку из буфера обмена. Это повторит поведение системного обработчика (DWM/композитинга) и обычно корректно снимает окна, которые рендерятся на GPU.

Ниже — примерная реализация на Win32/C++ и разбор альтернатив/ограничений.

Пример (схематично):

- привести окно в foreground (AttachThreadInput/SetForegroundWindow);
- использовать SendInput для Alt down, PrintScreen, PrintScreen up, Alt up;
- подождать и открыть буфер обмена, получить HBITMAP и скопировать его.

Пример кода (упрощённый — добавьте проверку ошибок, очистку ресурсов и синхронизацию в реальном приложении):

#include <windows.h>

HBITMAP CaptureWindowByAltPrintScreen(HWND hwnd)
{
    if (!IsWindow(hwnd)) return NULL;

    // Убедиться, что окно видно/восстановлено
    ShowWindow(hwnd, SW_RESTORE);

    // Попытка сделать окно активным/передним
    DWORD curThread = GetCurrentThreadId();
    DWORD wndThread = GetWindowThreadProcessId(hwnd, NULL);
    AttachThreadInput(curThread, wndThread, TRUE);
    SetForegroundWindow(hwnd);
    SetFocus(hwnd);
    AttachThreadInput(curThread, wndThread, FALSE);

    // Смоделировать Alt+PrintScreen
    INPUT inputs[4] = {};
    // Alt down
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = VK_MENU;
    // PrtSc down
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = VK_SNAPSHOT;
    // PrtSc up
    inputs[2] = inputs[1];
    inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
    // Alt up
    inputs[3].type = INPUT_KEYBOARD;
    inputs[3].ki.wVk = VK_MENU;
    inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;

    SendInput(4, inputs, sizeof(INPUT));

    // Небольшая пауза, чтобы система успела поместить картинку в буфер обмена
    Sleep(100);

    HBITMAP result = NULL;
    if (OpenClipboard(NULL)) {
        HBITMAP hb = (HBITMAP)GetClipboardData(CF_BITMAP); // handle, принадлежит буферу обмена
        if (hb) {
            // Сделаем копию, чтобы можно было закрыть буфер обмена
            result = (HBITMAP)CopyImage(hb, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
        }
        CloseClipboard();
    }

    return result; // caller должен удалить HBITMAP
}

Ключевые замечания и ограничения

- Права и фокус: SetForegroundWindow/AttachThreadInput не всегда срабатывают (ограничения по безопасности/фокусу в Windows). Если процесс имеет другой уровень привилегий (elevated vs non-elevated) — управление фокусом может быть заблокировано.
- Требуется интерактивный рабочий стол: метод не работает в службах, в другой сессии/дисплее или если пользователь не в интерактивном сеансе.
- Воздействие на пользователя: окно станет передним — это видно пользователю.
- SendInput/симуляция клавиатуры может быть перехвачена клавиатурными хуками и античитами; некоторые приложения/среды могут блокировать или реагировать на синтетический ввод по-разному.
- Альтернатива PrintWindow: есть Win32-функция PrintWindow(hwnd, hdc, flags) (с флагом PW_RENDERFULLCONTENT). Она иногда работает и даёт bitmap без переключения фокуса, но для многих GPU-рендерящих приложений (Direct3D, аппаратные поверхности, некоторые оконные поверхности) PrintWindow возвращает чёрный фон или пустое содержимое.
- Desktop Duplication API (DXGI) позволяет получить содержимое всего монитора/выхода с GPU с высокой скоростью, и затем вырезать область окна — это то, что вы уже делаете и что надёжно работает для всех GPU-рендеренных приложений. Но это «захват экрана» + кроп, а не прямой захват окна.
- DWM: системный compositor знает, как рендерить GPU-окна, но публичного простого API «получить готовый растеризованный фрейм конкретного окна» (как делает Alt+PrtSc) нет. Потому эмуляция клавиши — самый прямой путь, если вам нужно именно то же поведение.

Вывод
Если вам важно именно поведение Alt+PrtSc и вы готовы, чтобы окно стало активным, — симуляция нажатия клавиш + чтение буфера обмена — практичный и рабочий путь. Если нужно нефоновое, бессимптомное для пользователя решение, остаются менее универсальные методы (PrintWindow — иногда работает, Desktop Duplication + кроп — всегда работает для GPU, но это снимок всего монитора).
PrintWindow() с флагом PW_RENDERFULLCONTENT, доступен с Win8.1. Ровно то что Alt+PrtSc делает под капотом — DWM рисует DirectX-слой без хуков в видеопамять: <br/> <code>PrintWindow(hWnd, hdc, PW_RENDERFULLCONTENT);</code> <br/> p.s. и rect.right+8 в CreateCompatibleBitmap у тебя не ширина, а координата, размер будет кривой.
Похожие вопросы