Вопрос или проблема
Я использую инъекцию 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 в сочетании с изменением состояния окна (минимизация, восстановление) во время записи экрана.
Возможные причины и решения
-
Поведение WDA_EXCLUDEFROMCAPTURE:
Использование параметраWDA_EXCLUDEFROMCAPTURE
заставляет систему не отображать окно в захвате с помощью экранных рекордеров. Однако, если окно сворачивается в трей и затем восстанавливается, это может приводить к тому, что системные вызовы инициализации его отображения не работают корректно, и окно может отображаться черным. - Проблемы с контекстом окна:
Когда окно скрыто, и оно восстанавливается, возможно, контекст устройства (DC) не инициализируется должным образом, что может вызывать черный экран. В этом случае стоит попробовать сбросить или переустановить атрибуты окна после его отображения.
Рекомендованные изменения в коде
-
Переустановка
SetWindowDisplayAffinity
:
Поскольку окно меняет свое состояние, вероятно, стоит добавить дополнительный вызовSetWindowDisplayAffinity
после восстановления окна. Это можно сделать в обработчике изменений состояния окна. -
Использование
WM_SHOWWINDOW
:
Добавьте обработчик для сообщений Windows. При показе окна (WM_SHOWWINDOW
) вы можете снова вызовитеSetWindowDisplayAffinity
. - Пример кода:
#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);
}
-
Поддержка многопоточности:
Если вы работаете с несколькими потоками, убедитесь, что ваши изменяемые данные (например,createdWindows
) защищены мьютексами или другими средствами синхронизации, чтобы избежать гонок и непредсказуемого поведения. - Тестирование:
После внесенных изменений придерживайтесь методов тестирования, чтобы удостовериться, что функционал так работает, как ожидается. Протестируйте, как ваше приложение реагирует на изменение состояния окна и при этом записывается ли это корректно экранным рекордером.
Заключение
Ваш вопрос достаточно специфичен, и несмотря на простоту решения, подводные камни могут усложнять лечение. Дважды проверьте, какие события происходят при сворачивании и восстановлении ваших окон, и используйте соответствующие обработчики для выполнения нужных операций. Если потребуется дополнительная помощь или уточнения, не стесняйтесь обращаться.