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

Delphi 11中SetWindowDisplayAffinity使用异常问题求助

问题分析与修正:Delphi中SetWindowDisplayAffinity无法阻止截图的问题

问题背景

我之前在提问寻求Delphi Alexandria中阻止截图的方案,找到一段代码测试后,无法实现阻止页面被捕获的效果,也无法让截图时页面变为黑屏。我仅希望学习SetWindowDisplayAffinity的正确用法,并非开发安全软件,清楚该方法存在绕过方式,且需要兼容Windows 7至11系统(此前尝试DirectX SDK方案未成功)。

测试代码如下:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Menus, Vcl.ExtCtrls, Vcl.FileCtrl, 
  System.IOUtils, System.Types, System.UITypes, Forms, Math, ShellAPI, Vcl.Imaging.jpeg, 
  Winapi.TlHelp32, PsAPI, System.StrUtils;


type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;


implementation

{$R *.dfm}

uses Unit2;

function SetWindowDisplayAffinity(hWnd: HWND; dwAffinity: DWORD): BOOL; stdcall; external 'user32.dll' name 'SetWindowDisplayAffinity';
function ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL; stdcall; external 'user32.dll' name 'ShowWindow';


procedure TForm1.FormCreate(Sender: TObject);
var
 Handle: Winapi.Windows.HWND;
begin
  // Get the handle of the main form window
  Handle := Self.Handle;

  // Set the display affinity of the window to monitor
  SetWindowDisplayAffinity(Handle, WDA_MONITOR);

  // Call SetWindowDisplayAffinity
  if not SetWindowDisplayAffinity(Handle, WDA_MONITOR) then
  begin
    ShowMessage(SysErrorMessage(GetLastError));
  end else
  begin
    ShowMessage('OK');
  end;


  // Show the window
  ShowWindow(Handle, SW_NORMAL);
end;

代码存在的问题

  1. API兼容性限制:SetWindowDisplayAffinity是Windows 8.1及以上系统才提供的API,Windows 7完全不支持,这是该代码在Win7上无效的核心原因。
  2. 常量未定义:代码中直接使用WDA_MONITOR,但Delphi的Winapi.Windows单元可能未包含该常量定义(尤其是针对低版本Windows编译时),导致实际传递的参数值错误,API调用失效。
  3. 重复调用API:连续两次调用SetWindowDisplayAffinity,第一次无错误检查,属于冗余操作,可能干扰后续执行。
  4. 调用时机不当:在FormCreate中调用时,窗口尚未完全初始化完成,此时设置窗口属性可能无法生效。
  5. 冗余的ShowWindow调用:VCL框架会自动处理窗口显示逻辑,额外调用ShowWindow(Handle, SW_NORMAL)无意义,甚至可能引发异常。

修正后的代码

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

// 手动定义SetWindowDisplayAffinity所需常量
const
  WDA_MONITOR = $00000001;  // 仅允许在显示器显示,禁止截图捕获
  WDA_NONE = $00000000;     // 取消限制

implementation

{$R *.dfm}

// 声明API(仅Windows 8.1+支持)
function SetWindowDisplayAffinity(hWnd: HWND; dwAffinity: DWORD): BOOL; stdcall; external 'user32.dll' name 'SetWindowDisplayAffinity';

procedure TForm1.FormShow(Sender: TObject);
begin
  // 在窗口显示后设置属性
  if not SetWindowDisplayAffinity(Self.Handle, WDA_MONITOR) then
  begin
    ShowMessage('设置失败: ' + SysErrorMessage(GetLastError));
  end
  else
  begin
    ShowMessage('设置成功,窗口已禁止常规截图捕获');
  end;
end;

end.

额外说明

  • 若需兼容Windows 7,SetWindowDisplayAffinity无法使用,需采用其他方案(如GDI消息拦截或DirectX渲染保护),但这类实现复杂度较高。
  • 该API仅能阻止常规截图工具(如PrintScreen、系统截图工具),无法防范摄像头拍摄、虚拟机截图等绕过方式。

内容的提问来源于Stack Exchange,提问作者John

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:22:32