You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测Windows平台是否有应用正在捕获屏幕?针对SetWindowDisplayAffinity存在bug的旧版本,如何通过P/Invoke手动检测并实现窗口遮挡?

Screen Capture Detection & Manual Blackout for Windows Apps

Great question—let's break this down step by step since you're dealing with a common pain point: working around SetWindowDisplayAffinity bugs in older Windows versions while maintaining anti-capture functionality.

1. Detecting Screen Capture Activity (or if a Specific App is Being Captured)

There are a few reliable approaches here, depending on the Windows version you're targeting:

For Windows 10 1809+ & Windows 11

Microsoft added official APIs to detect screen capture events, which is the most robust method:

  • Use RegisterScreenCaptureNotification to register a callback that triggers when a screen capture session starts or ends. This will notify your app whenever any process initiates capture (screenshots, screen recording, etc.).
  • To check if a specific window is being captured, combine this with SetWinEventHook listening for EVENT_SYSTEM_CAPTURESTART and EVENT_SYSTEM_CAPTUREEND events. You can map these events to the target window using GetWindowThreadProcessId.

Here's a quick P/Invoke snippet to get you started with the notification:

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr RegisterScreenCaptureNotification(IntPtr hWnd, IntPtr callback);

// Your callback method signature
private void OnScreenCaptureNotification(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
    // wParam = 1 when capture starts, 0 when it ends
    bool isCapturing = wParam != IntPtr.Zero;
    // Handle capture state changes here
}

For Older Windows Versions (Pre-1809)

Official APIs don't exist here, so you'll have to use heuristic methods:

  • Check running processes for known capture tools (OBS, Snagit, ShareX, etc.)—note this isn't foolproof, as custom capture tools won't be detected.
  • Periodically compare the target window's expected pixel data with its actual rendered pixels (a hacky approach, but works for specific use cases).

2. Manual Blackout Without System Anti-Capture APIs

If you need to bypass SetWindowDisplayAffinity bugs, creating a custom overlay window is a solid fallback. Here's how to implement it in C#:

Core Approach

Create a topmost, black, input-transparent window that perfectly overlays your target window. Capture tools will only see the black overlay, but your original window still receives user input.

Step-by-Step Implementation

  1. Set Window Styles: Use extended styles to make the overlay topmost, layered, and transparent to input.
  2. Sync with Target Window: Listen for the target window's position/size changes to update the overlay in real time.
  3. Handle State Changes: Hide the overlay when the target is minimized, close it when the target closes.

Here's a code example:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class BlackoutOverlay : Form
{
    private readonly IntPtr _targetWindowHandle;

    public BlackoutOverlay(IntPtr targetWindowHandle)
    {
        _targetWindowHandle = targetWindowHandle;
        
        // Basic window setup
        FormBorderStyle = FormBorderStyle.None;
        ShowInTaskbar = false;
        StartPosition = FormStartPosition.Manual;
        BackColor = Color.Black;
        
        // Set extended styles for topmost, layered, and input transparency
        SetWindowLongPtr(Handle, GWL_EXSTYLE,
            GetWindowLongPtr(Handle, GWL_EXSTYLE) | WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT);
        
        // Make the window fully opaque
        SetLayeredWindowAttributes(Handle, 0, 255, LWA_ALPHA);
        
        // Sync initial position and size
        UpdateOverlayPosition();
        
        // Use a timer to keep overlay synced (replace with WinEvent hooks for better performance)
        var syncTimer = new Timer { Interval = 100 };
        syncTimer.Tick += (s, e) => UpdateOverlayPosition();
        syncTimer.Start();
    }

    private void UpdateOverlayPosition()
    {
        if (!IsWindowVisible(_targetWindowHandle))
        {
            Hide();
            return;
        }
        
        Show();
        GetWindowRect(_targetWindowHandle, out RECT windowRect);
        Bounds = new Rectangle(windowRect.Left, windowRect.Top, 
            windowRect.Right - windowRect.Left, windowRect.Bottom - windowRect.Top);
    }

    // P/Invoke definitions
    private const int GWL_EXSTYLE = -20;
    private const uint WS_EX_TOPMOST = 0x00000008;
    private const uint WS_EX_LAYERED = 0x00080000;
    private const uint WS_EX_TRANSPARENT = 0x00000020;
    private const uint LWA_ALPHA = 0x00000002;

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT { public int Left, Top, Right, Bottom; }

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    private static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint crKey, byte bAlpha, uint dwFlags);

    [DllImport("user32.dll")]
    private static extern bool IsWindowVisible(IntPtr hWnd);
}

// Usage example:
// var overlay = new BlackoutOverlay(targetWindowHandle);
// overlay.Show();

Key Notes

  • This overlay blocks most screen capture tools that capture the desktop frame buffer, but won't stop tools that read directly from the GPU (like some game capture tools).
  • For better performance, replace the timer with SetWinEventHook listening for EVENT_OBJECT_LOCATIONCHANGE events on the target window—this triggers updates only when the window actually moves or resizes.

内容的提问来源于stack exchange,提问作者vkolesnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 09:09:09