Search code examples
delphiscreenshotdelphi-2009

How to make a screen shot of my actual window


I defined a Tactionlist which contains all actions to show/hide my forms. This could be modal (showmodal) or non modal (visible:=true). I found some code to catch the screen shots by this:

procedure GetScreenShot(shotType: TScreenShotType; var img: TJpegImage);
var
  w,h: integer;
  DC: HDC;
  hWin: Cardinal;
  r: TRect;
  tmpBmp: TBitmap;
begin
  hWin := 0;
  case shotType of
    sstActiveWindow:
      begin  //This is what I use
        //only the active window
        hWin := GetForegroundWindow;
        dc := GetWindowDC(hWin);
        GetWindowRect(hWin,r);
        w := r.Right - r.Left;
        h := r.Bottom - r.Top;
      end;  //sstActiveWindow
    sstActiveClientArea:
      begin
      end;  //sstActiveClientArea
    sstPrimaryMonitor:
      begin
      end;  //sstPrimaryMonitor
    sstDesktop:
      begin
      end;  //sstDesktop
    else begin
      Exit;
    end;  //case else
  end;  //case

  //convert to jpg
  tmpBmp := TBitmap.Create;
  try
    tmpBmp.Width := w;
    tmpBmp.Height := h;
    BitBlt(tmpBmp.Canvas.Handle,0,0,tmpBmp.Width,
      tmpBmp.Height,DC,0,0,SRCCOPY);
    img.Assign(tmpBmp);
  finally
    ReleaseDC(hWin,DC);
    FreeAndNil(tmpBmp);
  end;  //try-finally
end;

My "scan" routine is as follows:

for ACnt := 0 to GenActions.ActionCount - 1 do
    begin
    try
    LogBook.ML(Format('%d. Aktion %s gestartet',[ACnt,quotedstr(GenActions.Actions[ACnt].Name)]));
    if GenActions.Actions[ACnt].Tag > 0 then
         begin  // Action is ready for test
         TAction(GenActions.Actions[ACnt]).checked:=true;
         if GenActions.Actions[ACnt].Execute then
              begin
              LogBook.ML(Format('%d. Aktion %s erfolgreich ausgeführt',[ACnt,quotedstr(GenActions.Actions[ACnt].Name)]));
              if SaveScreens then   // var boolean
                   begin
                   img:=TJPEGImage.Create;
                   try
                   GetScreenShot(sstActiveWindow,img);         
                   img.SaveToFile(IncludeTrailingBackslash(Optionen.PictPfad.Text)+inttostr(ACnt)+'.jpg');
                   finally
                        img.Free;
                        end;
                   end;
              repeat
              sleep(100);
              Application.ProcessMessages;
              until not DM_Gen.TestTimer.Enabled ;  //for modal windows a timer sends modalresult:=mrcancel
              end;
         end
    else
         begin
         LogBook.ML(Format('%d Aktion %s nicht getestet',[ACnt,quotedstr(GenActions.Actions[ACnt].Name)]));
         end;
    except
         on E: Exception do
         LogBook.ML(Format('%d. Aktion hat Fehler %s gemeldet',[ACnt,E.Message]));
         end;
    end;
finally
    LogBook.ML('Testlauf beendet');
    end;

When I run this code I get for about the first 150 actions the mainform, then some other forms like the logbook or the browser or ... Nearly never the form I want.

I found some posts which recommended the use of "findwindow". Here is my problem that I don't know the exact caption of the window, because in all windows the caption is modified in the onshow event in order to show actual information.

Any ideas how can catch my actual opened window?

So a problem is to understand how my actions work. Here two typical examples:

procedure TDM_Gen.VALstVisActExecute(Sender: TObject);
begin
if Sender is TAction then
    begin   // set some properties
    end;
ListeVeranst_2.Visible:=VALstVisAct.Checked;
end;

procedure TDM_Gen.NewVAActExecute(Sender: TObject);
var
NewVA : TNewVeranstaltung;
begin
if Sender <> nil then
    begin
    if Sender is TButton then
         begin   //do something depending on who fired
         end;
    end;
try
NewVA:=TNewVeranstaltung.Create(nil);
case NewVA.ShowModal of
mrOk:
    begin    // e.g. refresh some lists
    end;
mrCancel:    
    begin    // clean up
    end;
end;

finally
    NewVA.Free;
    end;
end;

The caption of the window is set during the onshow event by:

caption:=Format('This is window %s %s',[Param1, Param2]);

Solution

  • Problem you are facing is due to ShowModal method that is blocking call. That means that all subsequent code after that call will start executing after the form is closed.

    Code flow in following simplified example:

      MyAction.Execute;
      CaptureScreen;
    
    procedure TSomeForm.MyActionExecute(Sender: TObject);
    var frm: TForm;
    begin
      frm := TForm.Create(nil);
      try
        frm.ShowModal; // this call blocks execution of subsequent code in this method until form is closed
      finally
        frm.Free;
      end;
    end;
    

    will be MyAction.Execute -> frm.ShowModal -> frm.Close -> frm.Free -> CaptureScreen

    You will have to initiate screen capturing from within your modal form in order to capture its screen.