Search code examples
delphiwinapiscreenshot

Problem with using SetWindowDisplayAffinity in Delphi


I received various feedback and assistance in my previous question (prevents screenshots or screen capturing in delphi (alexandria)), and after some searching and research, I came across the following source code:

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;

However, I still don't have the ability to replace the black screen or blank page with my software page, or prevent capturing my software page.

Is there an issue with my source code?

I do not intend to write security software, so please do not give repetitive answers like this method is not effective, outdated, not practical, etc. I want to learn the method and process, and surely anyone with minimal technology knowledge knows that it is possible to capture or record the screen using a digital camera or mobile camera, and these methods cannot be prevented. Or by other methods, such as reverse engineering, etc., these limitations can be bypassed.

My goal is only to learn, and I do not intend to write flawless software!

These answers were very helpful, but I still couldn't succeed in using this method in Delphi 11 Alexandria: "I was not successful in installing and running the DirectX SDK method in Delphi 11 Alexandria, so I preferred to use the SetWindowDisplayAffinity method instead. (If this method is compatible with most Windows systems, especially Windows 7 to 11, it is sufficient for me.)"

https://stackoverflow.com/a/22218857/4299358

How does Office 2013 implement black windows for IRM?


Solution

  • Your code is strange in a number of ways:

    1. Why do you call SetWindowDisplayAffinity two times (one time without error checking and one time with error checking)? Surely one time is enough, no?

    2. Why do you call ShowWindow in the OnCreate handler? And why do you feel the need to declare this function yourself, when in fact it is a standard Windows API function found in Windows.pas?

    3. Why do you include a huge number of units in your example? (It is almost like you want to confuse us -- and yourself -- by creating red herrings!)

    I just now created a new VCL application in Delphi 12 with the following OnClick handler:

    procedure TForm1.FormClick(Sender: TObject);
    begin
      if not SetWindowDisplayAffinity(Handle, WDA_MONITOR) then
        RaiseLastOSError;
    end;
    

    I also added a button to the form (just to see how child windows appear in screenshots) and some GDI drawing on the form itself:

    procedure TForm1.FormPaint(Sender: TObject);
    begin
      Canvas.Brush.Color := clWhite;
      Canvas.FillRect(ClientRect);
      Canvas.Pen.Color := clRed;
      Canvas.Pen.Width := 4;
      Canvas.Ellipse(ClientRect)
    end;
    

    Now, I run the application and (immediately) create a screenshot of it and its neighbourhood:

    Screenshot of running app in front of its source code in the RAD Studio IDE. You can see a red circle and a button in the form.

    Then I click the client area of the form (NOT the button) and try to capture it in a screenshot again:

    Screenshot of running app in front of its source code in the RAD Studio IDE. The entire app window is black.

    By moving the call to SetWindowDisplayAffinity to the form's OnCreate handler, it will be "uncapturable" from the beginning. (Actually, CreateWnd is probably a better place.)

    So regarding the issue of "The problem with using SetWindowDisplayAffinity in the Delphi", I'd say the problem doesn't exist.