Search code examples
delphiwindowscreenshot

How to take a screenshot of the Active Window in Delphi?


For full screenshots, I use this code:

form1.Hide;
sleep(500);
bmp := TBitmap.Create;
bmp.Height := Screen.Height;
bmp.Width := Screen.Width;
DCDesk := GetWindowDC(GetDesktopWindow);
BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DCDesk, 0, 0, SRCCOPY);
form1.Show ;
FileName := 'Screenshot_'+FormatDateTime('mm-dd-yyyy-hhnnss',now());
bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName]));
ReleaseDC(GetDesktopWindow, DCDesk);
bmp.Free;

How can I convert that to take a screenshot of only the active window.


Solution

    1. First of all you have to get the right window. As sharptooth already noted you should use GetForegroundWindow instead of GetDesktopWindow. You have done it right in your improved version.
    2. But then you have to resize your bitmap to the actual size of the DC/Window. You haven't done this yet.
    3. And then make sure you don't capture some fullscreen window!

    When I executed your code, my Delphi IDE was captured and as it is on fullscreen by default, it created the illusion of a fullscreen screenshot. (Even though your code is mostly correct)

    Considering the above steps, I was successfully able to create a single-window screenshot with your code.

    Just a hint: You can GetDC instead of GetWindowDC if you are only interested in the client area. (No window borders)

    EDIT: Here's what I made with your code:

    You should not use this code! Look at the improved version below.

    procedure TForm1.Button1Click(Sender: TObject);
    const
      FullWindow = True; // Set to false if you only want the client area.
    var
      hWin: HWND;
      dc: HDC;
      bmp: TBitmap;
      FileName: string;
      r: TRect;
      w: Integer;
      h: Integer;
    begin
      form1.Hide;
      sleep(500);
      hWin := GetForegroundWindow;
    
      if FullWindow then
      begin
        GetWindowRect(hWin,r);
        dc := GetWindowDC(hWin) ;
      end else
      begin
        Windows.GetClientRect(hWin, r);
        dc := GetDC(hWin) ;
      end;
    
      w := r.Right - r.Left;
      h := r.Bottom - r.Top;
    
      bmp := TBitmap.Create;
      bmp.Height := h;
      bmp.Width := w;
      BitBlt(bmp.Canvas.Handle, 0, 0, w, h, DC, 0, 0, SRCCOPY);
      form1.Show ;
      FileName := 'Screenshot_'+FormatDateTime('mm-dd-yyyy-hhnnss',now());
      bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName]));
      ReleaseDC(hwin, DC);
      bmp.Free;
    end;
    

    EDIT 2: As requested I'm adding a better version of the code, but I'm keeping the old one as a reference. You should seriously consider using this instead of your original code. It'll behave much nicer in case of errors. (Resources are cleaned up, your form will be visible again, ...)

    procedure TForm1.Button1Click(Sender: TObject);
    const
      FullWindow = True; // Set to false if you only want the client area.
    var
      Win: HWND;
      DC: HDC;
      Bmp: TBitmap;
      FileName: string;
      WinRect: TRect;
      Width: Integer;
      Height: Integer;
    begin
      Form1.Hide;
      try
        Application.ProcessMessages; // Was Sleep(500);
        Win := GetForegroundWindow;
    
        if FullWindow then
        begin
          GetWindowRect(Win, WinRect);
          DC := GetWindowDC(Win);
        end else
        begin
          Windows.GetClientRect(Win, WinRect);
          DC := GetDC(Win);
        end;
        try
          Width := WinRect.Right - WinRect.Left;
          Height := WinRect.Bottom - WinRect.Top;
    
          Bmp := TBitmap.Create;
          try
            Bmp.Height := Height;
            Bmp.Width := Width;
            BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SRCCOPY);
            FileName := 'Screenshot_' + 
              FormatDateTime('mm-dd-yyyy-hhnnss', Now());
            Bmp.SaveToFile(Format('C:\Screenshots\%s.bmp', [FileName]));
          finally
            Bmp.Free;
          end;
        finally
          ReleaseDC(Win, DC);
        end;
      finally
        Form1.Show;
      end;
    end;