SetWindowDisplayAffinity вызывает черный экран в программах для записи экрана

Вопрос или проблема

Я использую инъекцию DLL для выполнения функции SetWindowDisplayAffinity в других процессах. Я использую WDA_EXCLUDEFROMCAPTURE, чтобы полностью скрыть окна от программ записи экрана.

Сначала это работает нормально. Но если я скрываю целевую программу в трей и затем отображаю её окно, программы записи экрана увидят черное окно (так же, как и WDA_MONITOR).

Система: Windows 11 Pro 23H2

Мой код:

#include "library.h"

#include <vector>
#include <windows.h>

auto createdWindows = std::vector<HWND>();

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    DWORD windowPID = 0;
    GetWindowThreadProcessId(hwnd, &windowPID);

    DWORD currentPID = GetCurrentProcessId();

    if (windowPID == currentPID) {
        SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE);
    }

    return TRUE;
}

VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) {
    for (auto hWnd : createdWindows) {
        SetWindowDisplayAffinity(hWnd, WDA_EXCLUDEFROMCAPTURE);
    }

    createdWindows.clear();
}

void StartTimer() {
    SetTimer(nullptr, 0, 1000, reinterpret_cast<TIMERPROC>(TimerProc));
}

LRESULT CALLBACK WindowProcHook(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HCBT_CREATEWND) {
        HWND hwnd = (HWND)wParam;
        SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE);
    }

    return CallNextHookEx(nullptr, nCode, wParam, lParam);
}

void SetWindowHook() {
    SetWindowsHookExA(WH_CBT, WindowProcHook, nullptr, GetCurrentThreadId());
}

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // дескриптор модуля DLL
    DWORD fdwReason,     // причина вызова функции
    LPVOID lpvReserved )  // резерв
{
    EnumWindows(EnumWindowsProc, 0);
    SetWindowHook();
    StartTimer();

    return TRUE;
}

Ответ или решение

Проблема, с которой вы столкнулись, возникает из-за особенностей работы функции SetWindowDisplayAffinity в сочетании с изменением состояния окна (минимизация, восстановление) во время записи экрана.

Возможные причины и решения

  1. Поведение WDA_EXCLUDEFROMCAPTURE:
    Использование параметра WDA_EXCLUDEFROMCAPTURE заставляет систему не отображать окно в захвате с помощью экранных рекордеров. Однако, если окно сворачивается в трей и затем восстанавливается, это может приводить к тому, что системные вызовы инициализации его отображения не работают корректно, и окно может отображаться черным.

  2. Проблемы с контекстом окна:
    Когда окно скрыто, и оно восстанавливается, возможно, контекст устройства (DC) не инициализируется должным образом, что может вызывать черный экран. В этом случае стоит попробовать сбросить или переустановить атрибуты окна после его отображения.

Рекомендованные изменения в коде

  1. Переустановка SetWindowDisplayAffinity:
    Поскольку окно меняет свое состояние, вероятно, стоит добавить дополнительный вызов SetWindowDisplayAffinity после восстановления окна. Это можно сделать в обработчике изменений состояния окна.

  2. Использование WM_SHOWWINDOW:
    Добавьте обработчик для сообщений Windows. При показе окна (WM_SHOWWINDOW) вы можете снова вызовите SetWindowDisplayAffinity.

  3. Пример кода:
#define WM_MY_RESTORE   (WM_USER + 1)

LRESULT CALLBACK WindowProcHook(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HCBT_CREATEWND) {
        HWND hwnd = (HWND)wParam;
        SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE);
    } else if (nCode == HCBT_ACTIVATE) {
        HWND hwnd = (HWND)wParam;
        // Убедитесь, что окно вновь настроено
        SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE);
    }

    return CallNextHookEx(nullptr, nCode, wParam, lParam);
}
  1. Поддержка многопоточности:
    Если вы работаете с несколькими потоками, убедитесь, что ваши изменяемые данные (например, createdWindows) защищены мьютексами или другими средствами синхронизации, чтобы избежать гонок и непредсказуемого поведения.

  2. Тестирование:
    После внесенных изменений придерживайтесь методов тестирования, чтобы удостовериться, что функционал так работает, как ожидается. Протестируйте, как ваше приложение реагирует на изменение состояния окна и при этом записывается ли это корректно экранным рекордером.

Заключение

Ваш вопрос достаточно специфичен, и несмотря на простоту решения, подводные камни могут усложнять лечение. Дважды проверьте, какие события происходят при сворачивании и восстановлении ваших окон, и используйте соответствующие обработчики для выполнения нужных операций. Если потребуется дополнительная помощь или уточнения, не стесняйтесь обращаться.

Оцените материал
Добавить комментарий

Капча загружается...