Comment les applications protègent leurs fenêtres contre les captures d’écran : Windows, macOS et Linux en détail
Quand vous essayez de faire une capture d’écran de Netflix ou Spotify, au lieu de la vidéo, vous verrez un rectangle noir — ce n’est pas un bug, mais une protection délibérée via les API système. Les développeurs utilisent des drapeaux comme SetWindowDisplayAffinity sur Windows ou sharingType sur macOS pour exclure la fenêtre des flux de capture d’écran. Mais dans macOS 15 Sequoia, Apple a rompu la compatibilité, et sur Linux, tout dépend du serveur d’affichage. Décomposons le fonctionnement de la protection sur chaque plateforme, ses points de défaillance et les solutions de contournement existantes.
Mécanismes de capture d’écran sur Windows : trois API principales
Quand une application comme Zoom demande l’accès au partage d’écran, elle s’abonne à un flux d’images provenant du système d’exploitation. Windows propose trois principaux moyens d’obtenir ce flux, chacun avec ses particularités :
- GDI BitBlt depuis le DC du bureau — la méthode la plus ancienne, fonctionnelle depuis Windows 2000. Elle utilise l’appel
BitBltdepuisGetDC(NULL)pour copier les pixels de la surface DWM (Desktop Window Manager) vers n’importe quel HDC. Lente, sans accélération matérielle, mais universelle. Utilisée dans les applications legacy et les outils de surveillance. - Desktop Duplication API (DXGI) — introduite dans Windows 8. Via
IDXGIOutputDuplication::AcquireNextFrame, elle renvoie une texture GPU avec l’image complète du bureau composite. Rapide, accélérée par le matériel, mais ne capture que l’écran entier. Utilisée dans les versions classiques de Zoom, TeamViewer, AnyDesk et Teams. - Windows.Graphics.Capture (WGC) — la norme moderne, introduite dans Windows 10 1803. Prend en charge la capture de l’écran entier ou d’une fenêtre spécifique par HWND. Utilisée dans les versions actuelles d’OBS, Microsoft Teams, Chromium, Zoom et l’outil de capture intégré Snipping Tool.
Les trois méthodes lisent finalement les données depuis le DWM — l’unique endroit où l’image finale de l’écran est composée. C’est là que les mécanismes de protection entrent en jeu.
SetWindowDisplayAffinity : modes et comportements
Le DWM permet à chaque fenêtre de définir un attribut display affinity via la fonction SetWindowDisplayAffinity. Cet attribut détermine si la fenêtre apparaît dans les flux de capture. Trois valeurs sont disponibles :
WDA_NONE(0x00) — la fenêtre est visible dans toutes les captures (par défaut).WDA_MONITOR(0x01) — la fenêtre s’affiche sur le moniteur mais est remplacée par un rectangle noir dans les captures. Fonctionne depuis Windows Vista. Netflix utilise cela pour protéger son contenu.WDA_EXCLUDEFROMCAPTURE(0x11) — la fenêtre est complètement exclue du flux de capture, comme si elle n’existait pas. Introduite dans Windows 10 May 2020 Update (build 19041). Le contenu des fenêtres sous-jacentes apparaît à travers — solution plus propre.
Exemple en 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;
}
Cela fonctionne de manière similaire en C# via P/Invoke, en Electron via setContentProtection(true), et en Tauri via with_content_protection(true).
En coulisses, le DWM sépare les pipelines de composition : une fenêtre avec WDA_EXCLUDEFROMCAPTURE ne va que dans le pipeline pour le moniteur physique, pas pour les clients de capture. On ne peut pas contourner cela au niveau de lecture des pixels.
Compatibilité et limitations sur Windows
Des tests sur Windows 11 23H2 ont montré que WDA_EXCLUDEFROMCAPTURE fonctionne correctement contre toutes les méthodes de capture principales :
- GDI BitBlt — la fenêtre est absente.
- Desktop Duplication (DXGI) — la fenêtre est absente (dans Windows 11 24H2, il y a une particularité où
AcquireNextFramese réveille sur les mises à jour de fenêtres cachées, mais aucun contenu n’est transmis). - Windows.Graphics.Capture (WGC) — la fenêtre est absente.
La seule exception est PrintWindow. Cette méthode contourne le DWM et demande à la fenêtre de se rendre directement dans le DC spécifié, en ignorant le drapeau. Cependant, la plupart des applications de partage d’écran (Zoom, Teams, Discord, OBS) n’utilisent pas PrintWindow.
Limitation principale : WDA_EXCLUDEFROMCAPTURE n’est pris en charge qu’à partir de Windows 10 20H1 (May 2020 Update). Sur les versions antérieures, y compris LTSC, la fonction renvoie ERROR_INVALID_PARAMETER. Dans ces cas, repasser à WDA_MONITOR, qui affiche un rectangle noir dans les captures.
Il existe aussi un attribut non documenté WCA_EXCLUDED_FROM_DDA via SetWindowCompositionAttribute, qui exclut la fenêtre uniquement de l’API Desktop Duplication. En pratique, c’est inutile car WDA_EXCLUDEFROMCAPTURE le couvre de manière plus complète.
macOS jusqu’à la version 14 : sharingType comme mécanisme fiable
Sur macOS jusqu’à la version 14, la propriété sharingType de NSWindow était utilisée :
window.sharingType = .none
Valeurs disponibles :
.readWrite— la fenêtre est lisible et modifiable par d’autres processus (rarement utilisé)..readOnly— la fenêtre est capturable (par défaut)..none— la fenêtre est exclue de la capture.
Ce drapeau fonctionnait via WindowServer, qui gère la composition via Core Graphics. Jusqu’à et y compris macOS 14 Sonoma, sharingType = .none bloquait efficacement la capture via les API legacy (CGWindowListCreateImage) et le nouveau ScreenCaptureKit (introduit dans macOS 12.3).
Electron et Tauri utilisaient ce mécanisme en coulisses pour leurs méthodes setContentProtection(true).
macOS 15 Sequoia : régression dans ScreenCaptureKit
Avec macOS 15 Sequoia, Apple a modifié l’architecture de WindowServer : désormais, la composition assemble toutes les fenêtres visibles dans un seul framebuffer, et ScreenCaptureKit le capture directement. Résultat : sharingType = .none n’affecte plus SCStream.
Un représentant officiel d’Apple l’a confirmé sur les Developer Forums : « À ce jour, il n’existe pas d’API publiques pour empêcher la capture d’écran ».
Nuance importante : les API legacy (CGWindowListCreateImage) respectent toujours sharingType = .none. Cela crée une divergence de comportement entre les applications :
- Zoom (actuel), Teams, QuickTime, captures système (Cmd+Shift+3/4/5), versions récentes d’OBS — utilisent ScreenCaptureKit → la fenêtre est visible.
- Google Chrome (
getDisplayMedia), Google Meet dans Chrome, versions anciennes d’OBS — utilisent CoreGraphics → la fenêtre est masquée.
C’est une régression fondamentale pour les produits nécessitant une protection contre la capture d’écran. Sans API privées, il n’y a pas de solution — et leur utilisation garantit un rejet en revue App Store et des pannes lors des mises à jour OS. Alternatives : limiter le support à macOS 14 et antérieur, ou méthodes comportementales : minimiser automatiquement la fenêtre au démarrage du partage d’écran, détecter l’activité SCStream via les signaux système.
Linux : X11 contre Wayland — deux mondes différents
Sur Linux, la situation varie drastiquement selon le serveur d’affichage.
X11 — architecturalement, ne prend pas en charge la protection des fenêtres contre la capture. Tout client avec accès à l’affichage peut appeler XGetImage ou XCompositeNameWindowPixmap pour saisir les pixels de n’importe quelle fenêtre. Les extensions de composition (Picom, KWin, Mutter) peuvent ajouter une protection partielle, mais il n’existe pas de solution cross-WM.
Wayland — basé sur des principes d’isolation : les clients ne peuvent pas lire les surfaces des autres. La capture d’écran n’est possible que via xdg-desktop-portal + PipeWire, et seulement avec le consentement explicite de l’utilisateur. La protection des fenêtres est gérée au niveau du protocole — si une fenêtre n’accorde pas l’accès, elle n’apparaît pas dans les captures. Cela rend Wayland bien plus sûr que X11, mais exige que les applications implémentent correctement les protocoles.
Points clés à retenir
SetWindowDisplayAffinityavecWDA_EXCLUDEFROMCAPTURE— norme de facto sur Windows pour exclure complètement une fenêtre de la capture. Fonctionne à partir de Windows 10 May 2020 Update.- Sur macOS 15 Sequoia,
sharingType = .nonene fonctionne plus contre ScreenCaptureKit — c’est un changement architectural d’Apple sans contournement public. - Sur Linux, X11 rend la protection des fenêtres impossible par conception du protocole ; Wayland la gère au niveau du protocole.
PrintWindowsur Windows contourne la protection, mais n’est pas utilisé dans les applications populaires de partage d’écran.- Electron et Tauri exploitent ces API en coulisses — leur comportement dépend de la plateforme et de la version OS.
— Editorial Team
Aucun commentaire pour le moment.