Link to home
Start Free TrialLog in
Avatar of Mamouri
Mamouri

asked on

Minimize and Hide an application without animations?

Hello Experts!
I use following code for taking capture from screen:
var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin
  Hide;
  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;
  Show;

As you see in First Line I hided main window to prevent of capturing my program itself.

But Because Hiding a window in taskbar in Windows XP (that have special animation) take long, a picture of my program in task bar also captured.

you can try yourself, this code. the program itself (in taskbar) also included in final program.

Does somebody know a way to disable effects of minimize and hiding JUST FOR MY PROGRAM?

Or Does somebody can suggest other solution to preventig that?

Thankx
Avatar of Ivanov_G
Ivanov_G
Flag of Bulgaria image


  minimize it to the systray
Avatar of Amir Azhdari
some changes to your code :

procedure TForm1.Button1Click(Sender: TObject);
var
  ScreenDC: HDC;
  ABitmap: TBitmap;
   H : HWND;
begin
// Hide Taskbar
  H := FindWindow('Shell_TrayWnd', nil);
  if H <> 0 then
    ShowWindow(H, SW_HIDE);
// ****************


  Hide;
  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;

// Show taskbar
  H := FindWindow('Shell_TrayWnd', nil);
  if H <> 0 then
    ShowWindow(H, SW_SHOW);


  Show;

end;


Regards
Azhdari
oh it'll capture the project again


NOW
try your code just place sleep func. after hide , it'll resolve the problem
this is here :

procedure TForm1.Button1Click(Sender: TObject);
var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin

  Hide;
  sleep(300);  // <----

  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;

 show;

end;



or try this if you don't want to capture the taskbar :

procedure TForm1.Button1Click(Sender: TObject);
var
  ScreenDC: HDC;
  ABitmap: TBitmap;
   H : HWND;
begin
// Hide Taskbar
  H := FindWindow('Shell_TrayWnd', nil);
  if H <> 0 then
    ShowWindow(H, SW_HIDE);
// ****************

  Hide;
  sleep(300);

  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;

// Show taskbar
 H := FindWindow('Shell_TrayWnd', nil);
  if H <> 0 then
    ShowWindow(H, SW_SHOW);

 show;

end;



or try this if you want to capture the taskbar just without showing your project menu :

procedure TForm1.Button1Click(Sender: TObject);
var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin


  Application.mainform.hide;
  sleep(300);

  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;

// Show taskbar
 H := FindWindow('Shell_TrayWnd', nil);
  if H <> 0 then
    ShowWindow(H, SW_SHOW);

  Application.mainform.show;

end;


Regards
Azhdari
Avatar of Mamouri
Mamouri

ASKER

Hello Ivanov
Can you please give me more details?
And If i minize it to tray icon of my program in tray will also captureded. nothing changed.

Hello Amir
I dont think sleep function is good idea. my program must be as fast as it possible. I know 300 mili secound is not as long as watching a movie from Hitchkok, but because later I show the picture in new form and then user can select a rectangle for capturing, it must be very fast. So user dosn't understand my trick and think that he/she is selecting in real screen not the fake one.

BTW, If Nobody else give me better answer then I will accept your own's.

I increase points to 199

Thankx
hello Mamouri, I would try to Hide and show the Application Winndow

var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin
  ShowWindow(Application.Handle, SW_HIDE); // should Hide All  Forms in your app
  ABitmap := TBitmap.Create;
  ScreenDC := 0;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
    Image1.Picture.Bitmap := ABitmap;
  finally
    ABitmap.Free;
  end;
  ShowWindow(Application.Handle, SW_SHOW);
end;
Avatar of Mamouri

ASKER

Hello Slick
Using ShowWindow function also dosen't affect. And still title of program in taskbar apear in final picture.
I think u use an OS other than Win XP. It work well in Win 2K but it dosen't work in Windows XP.

Because there are special effects and new animations in Win XP. Hide of a program from taskbar do with special roll animation. window rolled from right to left.

This animation take time (almost 250 milisecounds).

I need a way for hiding window without animation. I dont know exactly how?

I Increased point to 222.

Regards
listening ...
one example how to minimize in systray.

unit frMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, Menus, ImgList, Inifiles;

const
  WM_SYSTRAYCLICK        = WM_USER + 1;

type
  TfrmMain = class(TForm)
    mnuPopup: TPopupMenu;
    mnuMonitor: TMenuItem;
    urnOff1: TMenuItem;
    mnuScreenSaver: TMenuItem;
    mnuAbout: TMenuItem;
    mnuExit: TMenuItem;
    mnuControlPanel: TMenuItem;
    mnuMain: TMainMenu;
    imgMenu: TImageList;
    mnuAdministrativeTools: TMenuItem;
    mnuShow: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    NotifyIcon           : TNotifyIconData;
    procedure InitNotifyIcon;
  protected
    procedure WMSysTrayClick(var Msg : TMessage); message WM_SYSTRAYCLICK;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

{ TfrmMain }

procedure TfrmMain.InitNotifyIcon;
begin
  // initialize NotifyIcon which will be placed
  // in SysTray.
  with NotifyIcon do
    begin
      cbSize            := SizeOf(NotifyIcon);
      Wnd               := Handle;
      uID               := 1;
      uFlags            := NIF_TIP + NIF_MESSAGE + NIF_ICON;
      uCallbackMessage  := WM_SYSTRAYCLICK;
      hIcon             := Application.Icon.Handle;
      StrPCopy(szTip, Application.Title);
    end;
end;

procedure TfrmMain.WMSysTrayClick(var Msg: TMessage);
var
  crs_pos                : TPoint;
begin
  // event handler for systray icon click
  case Msg.LParam of
    WM_LBUTTONDBLCLK     : begin
                             // double click with left mouse button
                             frmMain.Show;
                           end;
    WM_RBUTTONDOWN       : begin
                             // right button
                             GetCursorPos(crs_pos);
                             mnuPopup.Popup(crs_pos.X, crs_pos.Y);
                           end;
    else
      inherited;
    end;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  // init the systray icon and minimize
  InitNotifyIcon;
  Shell_NotifyIcon(NIM_ADD, Addr(NotifyIcon));

  // check for Start_Minimized option
  if GetOption('Options', 'Start_Minimized', vtBoolean) then
    begin
      //Self.Hide;
      Application.ShowMainForm := False;
    end;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  // remove the systray icon
  Shell_NotifyIcon(NIM_DELETE, Addr(NotifyIcon));
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Self.Hide;
end;

end.
Hi,

Have you tried that:

begin
  Hide;
  Application.ProcessMessages;
  ABitmap := TBitmap.Create;
  ...

Regards, Geo
And don't forget to release the DC:

var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin
  Hide;
  Application.ProcessMessages;
  ABitmap := TBitmap.Create;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    try
      BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
      Image1.Picture.Bitmap := ABitmap;
    finally
      ReleaseDC(0,ScreenDC);
    end;
  finally
    ABitmap.Free;
  end;
  Show;
end;

Regards, Geo
Avatar of Mamouri

ASKER

Hello guys
Ivanov_G, I tried your solution but it dosen't change anything. I dont think tray Icon is good idea. because as I said before, icon of program also will be apear in final picture and also if I want to minimize the application the window in taskbar will also become apear in result picture.

geobul I tried that but it dosen't work.

I thought about InvalidRect function. I tried to get Desktop Window handle using GetDesktopWindow function and put it in InvalidRect. But nothing changed. I also tries to refresh taskbar but I dont succesed.

Does somebody have new idea, please?

Regards

   then in the DPR file write

   Application.ShowMainForm := False;

   and use Timer to trigger some event on specified interval.
Avatar of Mamouri

ASKER

Ivanov, It is not answer of my question. Inside of the program user must be able to minize application and take picture. not only at start of project.

Regards.

   1) put button "Hide and Shot"
   2) when pressed - it activate the timer and hide the form
   3) OnTimer you take the shot and after that show the form...
Hi,

Try this one:

var
  ScreenDC: HDC;
  ABitmap: TBitmap;
begin
 while IsWindowVisible(Handle) do begin
   ShowWindow(Handle, SW_HIDE);
   Application.ProcessMessages;
   Sleep(100);
 end;
 try
  // Application.ProcessMessages;
  ABitmap := TBitmap.Create;
  try
    ABitmap.PixelFormat := pf24bit;

    ABitmap.Width := Screen.Width;
    ABitmap.Height := Screen.Height;
    ScreenDC := GetDC(0);
    try
      BitBlt(ABitmap.Canvas.Handle, 0, 0, ABitmap.Width, ABitmap.Height, ScreenDC, 0, 0, SRCCOPY);
      Image1.Picture.Bitmap := ABitmap;
    finally
      ReleaseDC(0,ScreenDC);
    end;
  finally
    ABitmap.Free;
  end;
 finally
  Application.ProcessMessages;
  ShowWindow(Handle, SW_SHOW);
 end;
end;

Regards, Geo
I used the XP OS and this code works for me


procedure TForm1.Timer1Timer(Sender: TObject);
const
CAPTUREBLT = $40000000; // if in XP you should include CAPTUREBLT

var
ScreenBmp: TBitmap;
sDC: Integer;

begin
Timer1.Enabled := False;
ScreenBmp := TBitmap.Create;
try
  Hide;
  ShowWindow(Application.Handle, SW_HIDE);
  //SwitchToThread; // works in XP, not in other OS, ? ?
  Sleep(0); // works in XP and other OS
  ScreenBmp.Width := Screen.Width;
  ScreenBmp.Height := Screen.Height;
  sDC := GetDC(0);
  BitBlt(ScreenBmp.Canvas.Handle, 0, 0, ScreenBmp.width, ScreenBmp.height,
         sDC, 0,0, SRCCOPY OR CAPTUREBLT);
  ReleaseDC(0, sDC);

  ShowWindow(Application.Handle, SW_SHOW);
  Show;
  //Application.ProcessMessages; // not really needed
  ScreenBmp.SaveToFile('C:\zzScreen.bmp');
  finally
  FreeAndNil(ScreenBmp);
  end;
end;

- - - - - - - - - - - - - - -

The SwitchToThread  worked in the XP system, but not in some other systems, so I used Sleep(0);  which seemed to work in many systems
this got the Screen in SAcreenBmp, ,  without the Form1 or Taskbar application Button showing at all
Slick812's code work fine , but CAPTUREBLT is useless constant
also it's no need to try that in a timer

same code :

procedure TForm1.Button1Click(Sender: TObject);
var
ScreenBmp: TBitmap;
sDC: Integer;
begin
try
  ScreenBmp := TBitmap.Create;
  Hide;
  Sleep(0);
  ScreenBmp.Width := Screen.Width;
  ScreenBmp.Height := Screen.Height;
  screenbmp.PixelFormat := pf24bit;
  sDC := GetDC(0);
  BitBlt(ScreenBmp.Canvas.Handle, 0, 0, ScreenBmp.width, ScreenBmp.height,
         sDC, 0,0, SRCCOPY );
 ReleaseDC(0, sDC);
  Show;
  image1.Picture.Bitmap:=screenbmp;
  finally
  FreeAndNil(ScreenBmp);
  end;

end;
Mamouri
anyway i think this is a system lag for hiding a form and only way is using a delay after hide

sleep(...);
or
do application.processmessage/application.handlemessages in a loop (ex. 1...2000)
instead of sleep func.
Avatar of Mamouri

ASKER

Hello Slick

Your code work well, but it have a little bug.

Open Project file and then open anothor window. The TaskBar should become like this:

[START] | Delphi 7 | Project | Untitled - Notepad |

3 Programs is runing. now activate Notepad window, then active Project window and press capture button (I place code that you said in Button.OnClick event except of Timer.OnTimer event).

See the result.
TaskBar is like this:
[START] | Delphi 7 | !!!!HERE IS NOTHING!!!! | Untitled - Notepad |

Window of Project.exe disapear and it also disapear from taskbar but windows in taskbar dont arrange correctly.

Of course if Project run as last program there is not problem.

and also slick can you please say what is mean of this number: $40000000

Where do you find that? Is it an undocumented API?

Regards
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mamouri

ASKER

Hello All and thankx for your answers.
Slick You solution work but as you said too It's impossible without using sleep function.

Geobul your solution dosent work on my computer. I have to increase Sleep interval into 300.

But anyway thankx all

If somebody find a better solution for disableing animations in winows XP, please let me know.
mamouri-AT-msn-DOT-com

Regards
Avatar of Mamouri

ASKER

Hello Friends again

Take a look here (In classic view)
Control Panel > System > Advanced > Visual Effects

There are two options that I intersted to them:

-> Animate windows when minimizing and miximizing
-> Slide taskbar buttons

Does somebody have a idea for using these two options for disableing animations for a specified window.

I can open new question and specify good point if sombody have the answer.

Let me know mamouri-AT-msn-DOT-com

Mamouri
>Take a look here (In classic view)

see the SystemParametersInfo-api-function
and use the option
SPI_SETANIMATION
to toggle animation on/off

>for disableing animations for a specified window.
this setting is systemwide/not for a specific window,
but you could it toggle off before your window gets minimized,
and toggle on, when your window is minimized

meikl ;-)