Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Bob Swart (aka Dr.Bob) - Medical Officer Delphi in a Nutshell
 Under The Hood #10 - How to Shoot the Screen
See Also: Delphi Papers and Dr.Bob's Examines Columns

One of the question that I often hear is how I make these incredible screenshots in my articles. Actually, I just hit PrintScrn for the entire desktop or Alt+PrintScrn for the active Window. But you can write a little bit of Delphi code to do the same thing programmatically as well...

The first solution (Delphi 1.x only) is to emulate a print screen keypress from within your 16-bits Windows program using the undocumented KeyboardEvent API:

  unit Shot;
  interface

    procedure ScreenShot;

  implementation
  uses
    WinTypes;

    procedure KeyboardEvent; far; external 'USER' index 289;

    procedure ScreenShot; assembler;
    asm
         mov   ax, VK_SNAPSHOT
         sub   bx, bx
         call  KeyboardEvent
    end {ScreenShot};
  end.
This works in Windows 3.x/Delphi 1.x (you get the bitmap in the Clipboard) but needs to be rewritten completely for Win32, since KeyboardEvent is now a documented API function with different parameters.

In fact, the Delphi-Way to do the same would be to get a handle to the entire DeskTopWindow using GetDeskTopWindow, and just BitBlt the contents of the corresponding DC to a TBitmap component. The result is copied to the Clipboard using Clipboard.Assign:

  unit Shot;
  interface

    procedure ScreenShot;

  implementation
  uses
  {$IFDEF WIN32}
    Windows,
  {$ELSE}
    WinTypes, WinProcs,
  {$ENDIF}
    Forms, Graphics, Clipbrd;

    procedure ScreenShot;
    var
      ScreenDC: HDC;
      ScreenHandle: HWnd;
      ScreenBitmap: TBitmap;
    begin
      ScreenHandle := GetDeskTopWindow;
      ScreenDC := GetDC(ScreenHandle);
      try
        ScreenBitmap := TBitMap.Create;
        try
          ScreenBitmap.Width := Screen.Width;
          ScreenBitmap.Height := Screen.Height;
          BitBlt(ScreenBitmap.Canvas.Handle, 0, 0,
              Screen.Width, Screen.Height, ScreenDC, 0, 0, SRCCOPY);
          Clipboard.Assign(ScreenBitmap)
        finally
          ScreenBitmap.Free
        end
      finally
        ReleaseDC(ScreenHandle, ScreenDC)
      end
    end {ScreenShot};
  end.
The last method works fine in both versions of Delphi, of course.

Both methods result in a bitmap inside the Clipboard, which can be pasted in WinWord, PaintShop Pro or any other professional image processing application.

Of course, we can also use the bitmap image in the Clipboard to play a little further. For example by placing it inside a small image (102x77) that shows the entire screen in "stamp" format. All we need to do for this is to have a TImage on a Form, and execute Image1.Picture.Assign(Clipboard), as we can see in the following example program (a form with one button and one image only);

  unit Unit1;
  interface
  uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    ExtCtrls, StdCtrls;

  type
    TForm1 = class(TForm)
      Button1: TButton;
      Image1: TImage;
      procedure Button1Click(Sender: TObject);
    private
      { Private declarations }
    public
      { Public declarations }
    end;

  var
    Form1: TForm1;

  implementation
  uses
    Shot, Clipbrd;
  {$R *.DFM}

  procedure TForm1.Button1Click(Sender: TObject);
  begin
    ScreenShot;
    Image1.Picture.Assign(Clipboard)
  end;

  end.
The following hood10.dpr is used as main program:

  program hood10;
  uses
    Forms,
    unit1 in 'unit1.pas' {Form1};

  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end.
As you can see, the shooting program is also included in the screenshot above.
So, this little program effectively demonstrates that it's in fact very easy to shoot yourself with Delphi...


This webpage © 1996-2017 by Bob Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.