Powrót do strony głównej

Ochrona okien przed zrzutami ekranu: Windows, macOS, Linux

Artykuł wyjaśnia, jak aplikacje chronią swoje okna przed przechwytywaniem ekranu w Windows, macOS i Linux. Omawiane są API SetWindowDisplayAffinity, sharingType i specyfika serwerów wyświetlania. Szczególna uwaga — regresje w macOS 15 Sequoia.

Ukryte okna: jak aplikacje chronią się przed zrzutami ekranu
Advertisement 728x90

# Jak aplikacje chronią okna przed zrzutami ekranu: Windows, macOS i Linux w szczegółach

Podczas próby zrobienia zrzutu ekranu Netflix lub Spotify zamiast wideo zobaczysz czarny prostokąt — to nie błąd, a celowa ochrona za pomocą systemowych API. Deweloperzy używają flag takich jak SetWindowDisplayAffinity w Windows lub sharingType w macOS, aby wykluczyć okno ze strumieni przechwytywania ekranu. Ale w macOS 15 Sequoia Apple zepsuła kompatybilność, a w Linux wszystko zależy od serwera wyświetlania. Przyjrzyjmy się, jak działa ochrona na każdej platformie, gdzie się psuje i jakie są obejścia.

Mechanizmy przechwytywania ekranu w Windows: trzy główne API

Gdy aplikacja taka jak Zoom żąda dostępu do demonstracji ekranu, subskrybuje strumień klatek od systemu operacyjnego. W Windows istnieją trzy główne sposoby uzyskania tego strumienia, każdy z własnymi cechami:

  • GDI BitBlt od desktopowego DC — najstarsza metoda, działająca od Windows 2000. Używa wywołania BitBlt z GetDC(NULL), kopiując piksele z powierzchni DWM (Desktop Window Manager) do dowolnego HDC. Wolna, bez przyspieszenia sprzętowego, ale uniwersalna. Stosowana w przestarzałych aplikacjach i narzędziach monitorujących.
  • Desktop Duplication API (DXGI) — pojawiła się w Windows 8. Poprzez IDXGIOutputDuplication::AcquireNextFrame zwraca teksturę GPU z już zkomponowaną klatką pulpitu. Szybka, przyspieszona sprzętowo, ale przechwytywany jest tylko cały monitor. Używana w klasycznych wersjach Zoom, TeamViewer, AnyDesk i Teams.
  • Windows.Graphics.Capture (WGC) — nowoczesny standard, wprowadzony w Windows 10 1803. Obsługuje przechwytywanie całego monitora lub konkretnego okna po HWND. Używany w aktualnych wersjach OBS, Microsoft Teams, Chromium, Zoom i systemowym Snipping Tool.

Wszystkie trzy metody ostatecznie czytają dane z DWM — jedynego miejsca, gdzie formuje się ostateczny obraz ekranu. To właśnie tutaj stosowane są mechanizmy ochrony.

Google AdInline article slot

SetWindowDisplayAffinity: tryby i ich zachowanie

DWM pozwala każdemu oknu ustawić atrybut display affinity za pomocą funkcji SetWindowDisplayAffinity. Ten atrybut określa, czy okno trafia do strumieni przechwytywania. Dostępne są trzy wartości:

  • WDA_NONE (0x00) — okno widoczne we wszystkich przechwytywaniach (domyślnie).
  • WDA_MONITOR (0x01) — okno wyświetlane na monitorze, ale w przechwytywaniu zastępowane czarnym prostokątem. Działa od Windows Vista. Właśnie to używa Netflix do ochrony treści.
  • WDA_EXCLUDEFROMCAPTURE (0x11) — okno całkowicie wykluczone ze strumienia przechwytywania, jakby nie istniało. Pojawiło się w Windows 10 May 2020 Update (build 19041). Przez nie widać zawartości leżących pod nim okien — bardziej eleganckie rozwiązanie.

Przykład w C++:

#include <windows.h>
#include <cstdio>

int main() {
    HWND hwnd = GetConsoleWindow();
    if (!SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE)) {
        printf("SetWindowDisplayAffinity failed: %lu\n", GetLastError());
        return 1;
    }
    printf("Okno teper nevidimo for zakhvata. Poprobuy sdelat skrinshot.\n");
    Sleep(60000);
    return 0;
}

Podobnie działa w C# przez P/Invoke, w Electron przez setContentProtection(true), w Tauri — przez with_content_protection(true).

Google AdInline article slot

Pod maską DWM oddziela potoki kompozycji: okno z WDA_EXCLUDEFROMCAPTURE trafia tylko do potoku dla fizycznego monitora, ale nie do potoków dla klientów przechwytywania. Objąć to na poziomie odczytu pikseli jest niemożliwe.

Kompatybilność i ograniczenia w Windows

Testy na Windows 11 23H2 pokazały, że WDA_EXCLUDEFROMCAPTURE poprawnie działa przeciwko wszystkim głównym metodom przechwytywania:

  • GDI BitBlt — okno nieobecne.
  • Desktop Duplication (DXGI) — okno nieobecne (w Windows 11 24H2 jest szczególność z budzeniem AcquireNextFrame przy aktualizacji ukrytego okna, ale treść nie jest przekazywana).
  • Windows.Graphics.Capture (WGC) — okno nieobecne.

Jedyny wyjątek to PrintWindow. Ta metoda omija DWM i prosi okno o narysowanie się bezpośrednio do wskazanego DC, ignorując flagę. Jednak większość aplikacji do demonstracji ekranu (Zoom, Teams, Discord, OBS) nie używa PrintWindow.

Google AdInline article slot

Ważne ograniczenie: WDA_EXCLUDEFROMCAPTURE jest obsługiwane dopiero od Windows 10 20H1 (May 2020 Update). Na starszych wersjach, w tym LTSC, funkcja zwróci błąd ERROR_INVALID_PARAMETER. W takich przypadkach można użyć WDA_MONITOR, ale wtedy w przechwytywaniu będzie czarny prostokąt.

Istnieje też niedokumentowany atrybut WCA_EXCLUDED_FROM_DDA przez SetWindowCompositionAttribute, który wyklucza okno tylko z Desktop Duplication API. W praktyce nie jest potrzebny, bo WDA_EXCLUDEFROMCAPTURE rozwiązuje problem pełniej.

macOS do 15: sharingType jako niezawodny mechanizm

W macOS do wersji 15 używano właściwości sharingType u NSWindow:

window.sharingType = .none

Dostępne wartości:

  • .readWrite — okno dostępne do odczytu i modyfikacji z innych procesów (rzadko używane).
  • .readOnly — okno przechwytywalne (domyślnie).
  • .none — okno wykluczone z przechwytywania.

Ta flaga działała przez WindowServer, który zarządza kompozycją przez Core Graphics. Do macOS 14 Sonoma włącznie sharingType = .none skutecznie blokowało przechwytywanie zarówno przez legacy-API (CGWindowListCreateImage), jak i przez nowy ScreenCaptureKit (wprowadzony w macOS 12.3).

Electron i Tauri używały tego mechanizmu pod maską swoich metod setContentProtection(true).

macOS 15 Sequoia: regresja w ScreenCaptureKit

Po wydaniu macOS 15 Sequoia Apple zmieniła architekturę WindowServer: teraz kompozycja zbiera wszystkie widoczne okna do jednego framebuffera, a ScreenCaptureKit przechwytywuje właśnie go. W rezultacie sharingType = .none przestało wpływać na strumień SCStream.

Oficjalny przedstawiciel Apple potwierdził na Developer Forums: «At this time there are no public APIs for preventing screen capture».

Ważna niuans: legacy-API (CGWindowListCreateImage) nadal szanuje sharingType = .none. To powoduje rozłam w zachowaniu różnych aplikacji:

  • Zoom (aktualny), Teams, QuickTime, systemowe zrzuty (Cmd+Shift+3/4/5), nowe wersje OBS — używają ScreenCaptureKit → okno widoczne.
  • Google Chrome (getDisplayMedia), Google Meet w Chrome, stare wersje OBS — używają CoreGraphics → okno ukryte.

To zasadnicza regresja dla produktów wymagających ochrony przed przechwytywaniem ekranu. Bez prywatnych API nie ma rozwiązania, a ich użycie gwarantuje odmowę w App Store review i ryzyko zepsucia przy aktualizacjach OS. Alternatywy — ograniczenie wsparcia do macOS 14 i wcześniejszych lub metody behawioralne: automatyczne zwijanie okna na początku demonstracji, wykrywanie aktywności SCStream przez sygnały systemowe.

Linux: X11 vs Wayland — dwa światy

W Linux sytuacja radykalnie różni się w zależności od serwera wyświetlania.

X11 — architektonicznie nie wspiera ochrony okien przed przechwytywaniem. Każdy klient z dostępem do wyświetlacza może wywołać XGetImage lub XCompositeNameWindowPixmap i pobrać piksele dowolnego okna. Kompozytowe rozszerzenia (Picom, KWin, Mutter) mogą dodawać częściową ochronę, ale nie ma rozwiązań cross-WM.

Wayland — oparty na zasadzie izolacji: klient nie może czytać cudzych surface. Przechwytywanie ekranu możliwe tylko przez xdg-desktop-portal + PipeWire i tylko za wyraźną zgodą użytkownika. Ochrona okien realizowana jest na poziomie protokołu — jeśli okno nie udostępnia dostępu, nie trafi do przechwytywania. To czyni Wayland znacznie bezpieczniejszym od X11, ale wymaga od aplikacji poprawnej implementacji protokołów.

Co ważne

  • SetWindowDisplayAffinity z WDA_EXCLUDEFROMCAPTURE — de facto standard w Windows do całkowitego wykluczenia okna z przechwytywania. Działa od Windows 10 May 2020 Update.
  • W macOS 15 Sequoia sharingType = .none nie działa już przeciwko ScreenCaptureKit — to zmiana architektoniczna Apple bez publicznego obejścia.
  • W Linux na X11 ochrona okien niemożliwa z powodu projektu protokołu; na Wayland — zapewniana na poziomie protokołu.
  • PrintWindow w Windows omija ochronę, ale nie jest używane w popularnych aplikacjach do demonstracji ekranu.
  • Electron i Tauri używają tych API pod maską — ich zachowanie zależy od platformy i wersji OS.

— Editorial Team

Advertisement 728x90

Czytaj dalej