Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 663
  • Last Modified:

Screen capture causes short mouse freeze

I'm having trouble doing a screen capture on Win 2000. (I have not tried Win 98, etc.) I need to do several captures at half-second intervals, but each capture involves the mouse cursor pausing or freezing for a fraction of a second.

I orginally did something like this:

  hScreen := GetDC(0);
  BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, hScreen, 0, 0, SRCCOPY);
  ReleaseDC(0, hScreen);
  Bmp.SaveToFile(.....);

The above code causes the mouse to freeze for a fraction of a second. After playing around a bit, I tried the following:

  hScrDC := CreateDC('DISPLAY', nil, nil, nil);
  hMemDC := CreateCompatibleDC(hScrDC);
  hBmp := CreateCompatibleBitmap(hScrDC, Screen.Width, Screen.Height);
  hOldBmp := SelectObject(hMemDC, hBmp);
  BitBlt(hMemDC, 0, 0, Screen.Width, Screen.Height, hScrDC, 0, 0, SRCCOPY);
  hBmp := SelectObject(hMemDC, hOldBmp);
  Bmp.Handle := hBmp;
  DeleteDC(hScrDC);
  DeleteDC(hMemDC);

Surprise! No mouse-freeze. But for my application I need the bitmap in both 8- and 24-bit color. As soon as I do Bmp.PixelFormat := pf8bit (or pf24bit) the mouse pauses briefly while the conversion is being done. The pause is short (< 100ms) when converting to 8-bit, and longer (around 300ms) when converting to 24-bit. I find that when converting to a JPEG or calling Bmp.SaveToFile that the mouse also pauses - might be related to PixelFormat???

Therefore, my question is: Does anyone know how to do both 8-bit and 24-bit screen captures on Win 2000, including saving the BMP to disk, WITHOUT the mouse "freezing" briefly?

Regards,
JB

(P.S. I'm running 16-bit color.)

0
JimBob091197
Asked:
JimBob091197
  • 15
  • 5
  • 4
  • +3
1 Solution
 
ITugayCommented:
Hi JimBob,

just an idea. Try to play with thread priority.

-------
Igor.
0
 
JimBob091197Author Commented:
Hi Igor

I have already tried thread priority, tpLowest and even tpIdle. It doesn't make any difference. It seems to be "deep" down in the Windows GDI that when a pixel format conversion occurs the mouse freezes briefly.

Thanks,
JB
0
 
AvonWyssCommented:
I suppose that the freeze will only occur when the conversion is done while tranferring the data from video memory. Therefore, why not using one more step: capute using a compatible DC (no freeze), and convert the captured bitmap afterwards to the needed pixel format. I believe that, like this, you should have no problem. Another possibility would be to grab the image in several parts and put it into one bitmap after that.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
JimBob091197Author Commented:
Thanks, Avon Wyss.

> I suppose that the freeze will only occur when the conversion is done while tranferring the data from video memory.
   
Could be, but I'm not 100% sure.
   
> Therefore, why not using one more step: capute using a compatible DC (no freeze), and convert the captured bitmap afterwards to the needed pixel format.
   
Have you got any code for me to try?? I can load a bitmap from a file, and as soon as I try to change the pixel format I get the same result, even though I never try to display it on the screen.

For example:
  Bmp.LoadFromFile(.....);
  Bmp.PixelFormat := pf24bit;  <--- mouse pauses here

Also, the code I gave in my original question (starting with "hScrDC := ....." does not cause the mouse to pause, UNTIL I try to change the pixel format. Therefore I need to know another method of changing the p/format - perhaps with some Win API calls???

> Another possibility would be to grab the image in several parts and put it into one bitmap after that.
   
I have tried this too, but the result is the same. For example, if I grab the screen in 4 sections then the "freeze" delay of each section is about 1/4 of the total delay. I need to capture every 500ms, and the total delay is still noticable. In other words, the "freeze" is still about 300ms for every complete capture, even if I do it in sections.

Thanks,
JB
0
 
robert_marquardtCommented:
The mouse cursor may be stored in video memory. So accessing the video memory may influence the cursor.
0
 
JimBob091197Author Commented:
Hi Robert

I'm not sure I understand. When doing a scr capture the mouse cursor doesn't appear on the bitmap - I have to manually draw it on afterwards if I want it.

Also, how would that explain the example I gave to AvonWyss:
   
  Bmp := TBitmap.Create;
  Bmp.LoadFromFile(.....);
  Bmp.PixelFormat := pf24bit;  <<< mouse pauses here
   
Thanks,
JB
0
 
robert_marquardtCommented:
The mouse cursor is handled by the video driver and often even handled by video hardware. It is stored in video memory so accessing video hardware may cause the cursor to stop.

Best check in the VCL sources what happens when setting PixelFormat. Maybe a Windows API function into the GDI is called which causes the delays.
0
 
JimBob091197Author Commented:
Thanks, Robert, for your pearls of wisdom. I've looked through the VCL, but I haven't stepped thru the VCL code. If you would be so kind as to let me know what API call(s) are causing my problem, and how to get around it, then the points are yours!!  :-)

JB
0
 
ITugayCommented:
Hi JimBob,

just make some investigation, and here is a sample code. Not very sure that it is exactly what you need, but may be it will be usefull for you.  I hope you do not need any comments :-)

-----
Igor.


type
 
  TConvertThread = class(TThread)
    SRC, DST: TBitmap;
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
    B: TBitmap;
    B1: TBitmap;
    procedure  ConvertDone(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  with TConvertThread.Create(True) do
  begin
    SRC := B;
    DST := B1;
    OnTerminate := ConvertDone;
    FreeOnTerminate := True;
    Resume;
  end;
end;


procedure TConvertThread.Execute;
var
  I: Integer;
begin
  DST.Width := SRC.Width;
  DST.Height := SRC.Height;
  for I := 0 to SRC.Height - 1 do
    BitBlt(DST.Canvas.Handle, 0, I, DST.Width, 1, SRC.Canvas.Handle, 0, I, SRCCOPY);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  B := TBitmap.Create;
  B.PixelFormat := pf24Bit;
  B.Width := 2048;
  B.Height := 1024;

  B1 := TBitmap.Create;
  B1.PixelFormat := pf8Bit;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  B1.Free;
  B.Free;
end;

procedure  TForm1.ConvertDone(Sender: TObject);
begin
   Windows.Beep(400, 40);
end;

end.
0
 
JimBob091197Author Commented:
Hi Igor

Thanks for your suggestions. The main problem I have is setting PixelFormat before bmp.width and height. (See your FormCreate method.)

The following code works, but causes the dreaded "freeze" when pix/format is changed:

  Bmp.Width := MyWidth;
  Bmp.Height := MyHeight;
  Bmp.PixelFormat := pf8bit;   <<< Mouse freezes here.

The code below causes EOutOfResources (on Win 2000 - don't know about Win 9x) when you try to save the bmp. It could be because of the way I capture the screen???

  // Set p/format BEFORE setting width and height.
  Bmp.PixelFormat := pf8bit;
  Bmp.Width := MyWidth;
  Bmp.Height := MyHeight;

  // Capture screen.
  hScrDC := GetDC(0);

  // *** BitBlt goes here.
  // Either use original method or Igor's one-row-at-a-time method.
  BitBlt(........);

  ReleaseDC(0, hScrDC);

  // Get exception (EOutOfResources) when try to save to file.
  Bmp.SaveToFile('c:\temp.bmp');


Igor, referring back to your example with the thread, at some point I have to capture the screen, then convert it to 8-bit (or 24-bit), then save to file. Your method of BitBlt one row at a time works fine IF both bmp's are already in the same pixelformat. Actually, once both BMPs are in the same format I can BitBlt entire image without mouse freeze, even without using a thread. But the problem comes in when setting the p/format. When changing a bmp's p/format AFTER setting width & height everything works fine EXCEPT that there is the mouse freeze problem. When changing a bmp's p/format BEFORE setting width & height I get EOutOfResources when I call Bmp.SaveToFile.

Using a thread doesn't seem to have any effect on the mouse freeze problem (MFP!!).

Regards,
JB
0
 
ITugayCommented:
Hi JimBob,

I think that "out of resources" is regarding processor productivity. Seems converting BMP by this way takes more time then timer's event. And  when timer forces next event, previous conversion still in progress.

Ok, I will think about another way, but I still see no other way then to split image by parts and use threads, really.

btw, pixel format should be assigned before BMP's dimensions. To tell you trust, I can't understand why you have to set Width & Height  AFTER pixel's format assigned. May be the problem is there?

------
Igor.

0
 
JimBob091197Author Commented:
Hi Igor

> I think that "out of resources" is regarding processor productivity. Seems converting BMP by this way takes more time then timer's event.

Actually in my demo I did not use a timer. I tried only 1 capture.

> btw, pixel format should be assigned before BMP's dimensions. To tell you trust, I can't understand why you have to set Width & Height  AFTER pixel's format assigned. May be the problem is there?

I have only experienced this problem regarding setting pixel format before width/height when I use GetDC and BitBlt. If I load a bitmap, then draw it onto another's canvas, it seems to work fine no matter where I set pixelformat, although I still get the mouse freezing, but not the out-of-resource problem.

> ..... but I still see no other way then to split image by parts and use threads, really.

I'm not convinced of that.  :-)   My reason is that changing p/format in a thread still causes the same delay when the mouse freezes. So I think it must be "deep" in the Windows API/GDI.

Thanks again,
JB
0
 
SteveWaiteCommented:
If the mouse is freezing then there may be a point in your app where the main thread is pausing to wait for another thread or vice-verca. You may be using Synchronize(proc) in the other thread and too much happens in proc.
or logic dictates always pausing in loop.

Regards,
Steve
0
 
JimBob091197Author Commented:
Hi Steve

Thanks for the comments. I don't think it has anything to do with threads. In my original app I didn't have any threads (except main of course). At Igor's suggestion I played with threads & thread priorities. I've tried everything from tpIdle to tpTimeCritical - it doesn't make any diff. And I'm not using Synchronize anywhere.

My opinion at this stage is that the thread is running when PixelFormat is changed does not matter. Windows is doing *something* that causes the mouse to freeze briefly. Perhaps the screen update is delayed, so that it's not just the mouse that "freezes" but actually the entire screen???

Has anybody got access to a Win 98 PC? I would be interested to see if this problem occurs on Win 98. A simple way to test the problem is to do this:

  Bmp := TBitmap.Create;
  Bmp.Width := Screen.Width;
  Bmp.Height := Screen.Height;

  // Assuming you are running 16-bit color:
  Bmp.PixelFormat := pf24bit;  <<< Mouse freezes here.

  // Calling Bmp.SaveToFile(...) also causes freezing.

  Bmp.Free;

Thanks,
JB
0
 
MadshiCommented:
Try this:

  Bmp.Width := xxx;
  Bmp.Height := yyy;
  Bmp.PixelFormat := pf16bit;
  hScreen := GetDC(0);
  BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, hScreen, 0, 0, SRCCOPY);
  ReleaseDC(0, hScreen);

Now you have done the screen capture without any color conversion, so the mouse should not freeze. Now the next task is to do the color conversion:

  Bmp.PixelFormat := pf24bit;

Does this work without freeze? If not, just try this:

procedure ConvertPixelDepthThread(bmp: TBitmap) : integer; stdcall;
begin
  bmp.PixelFormat := pf24bit;
end;

procedure ConvertPixelDepthInAThread(bmp: TBitmap);
var th, tid : dword;
begin
  th := CreateThread(nil, 0, @ConvertPixelDepthThread, bmp, CREATE_SUSPENDED, tid);
  SetThreadPriority(th, THREAD_PRIORITY_IDLE);
  WaitForSingleObject(th, INFINITE);
  CloseHandle(th);
end;

Regards, Madshi.
0
 
MadshiCommented:
I mean this, of course:

 Bmp.Width := xxx;
 Bmp.Height := yyy;
 Bmp.PixelFormat := pf16bit;
 hScreen := GetDC(0);
 BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, hScreen, 0, 0, SRCCOPY);
 ReleaseDC(0, hScreen);
 ConvertPixelDepthInAThread(Bmp);

Regards, Madshi.

P.S: Jim, you might want to look here (as long as you're still in the top15 :-)

http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=delphi&qid=20161508
0
 
JimBob091197Author Commented:
Hi Madshi

Thanks for your comments. 3 things:

1 - Regarding your code:

  Bmp.Width := xxx;
  Bmp.Height := yyy;
  Bmp.PixelFormat := pf16bit;
  hScreen := GetDC(0);
  BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, hScreen, 0, 0, SRCCOPY);
  ReleaseDC(0, hScreen);

The "freeze" occurs at the line "Bmp.P/format := pf16bit". At this point the p/f is pfDevice. Converting to 16-bit (although my display is already set to 16-bit!!!) causes the freeze.

2 - Once the p/f has been changed from pfDevice to something else (such as pf16bit) then the thread is NOT needed to convert to pf24bit (or 8-bit, etc.). As I said above, using threads does not appear to make any difference to the mouse freezing. I have tried this on both my PCs (both running Win 2000, different video cards) and both PCs give this problem.

3 - Your thread code needs "ResumeThread(th);" before "WaitForSingleObject" (You wanting me to wait for INFINITE to finish??? :-)


> P.S: Jim, you might want to look here (as long as you're still in the top15 :-)

Ah, somebody noticed I'm still in there!! (I wonder for how long?? :-)  I'm actually surprised I'm still there. I joined at the end of 1997 and got to #1 in 1998 but then I seem to have stopped spending so much time here as I was concentrating on other things. I have not contributed much recently on EE (probably haven't answered many questions in the last 3 years - sorry about that) but if your top-15 offer is still open then I shall make use of it. :-)

Thanks,
JB
0
 
ITugayCommented:
Hi all,

strange... "out of resources" produced by SaveToFile. Moreover, mouse should be over the application form,  in other cases all seems fine. Can't understand what's wrong.

Here is last what I get, and now my "F:\" drive a full of screen images in pf8it format. No any mouse freeze noticed. Timer interval = 200..500 ms. Form1.WindowState = wsMinimized to avoiod of "out of resources" effect.. Screen resolution 1024 x 768 - 24bit., PII-400Mhz NT4 SP5.

------
Igor.


type

  TConvertThread = class(TThread)
    DST: TBitmap;
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
    B: TBitmap;

    // be sure that only one thread running at the same time
    InProgress: Boolean;  
 
    procedure  ConvertDone(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if InProgress then
    exit;
  InProgress := True;

  with TConvertThread.Create(True) do
  begin
    DST := B;
    OnTerminate := ConvertDone;
    FreeOnTerminate := True;
    Resume;
  end;
end;

procedure TConvertThread.Execute;
var
  I: Integer;
  H: HDC;
begin
  H := GetDC(0);
  for I := 0 to Screen.Height - 1 do
    BitBlt(DST.Canvas.Handle, 0, I, DST.Width, 1, H, 0, I, SRCCOPY);
  ReleaseDC(0, H);
  DST.SaveToFile('F:\SCR'+IntToHex(GetTickCount, 8)+'.BMP');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  B := TBitmap.Create;
  B.PixelFormat := pf8Bit;
  B.Width := Screen.Width;
  B.Height := Screen.Height;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  B.Free;
end;

procedure  TForm1.ConvertDone(Sender: TObject);
begin
  InProgress := False;
end;

end.
0
 
MadshiCommented:
>> The "freeze" occurs at the line "Bmp.P/format := pf16bit".

Even *before* you do the screen shot??? Are you sure? Look, in my code the screen shot is done *after* that pixel format change!

>> if your top-15 offer is still open then I shall make use of it. :-)

It is still open. You didn't get into the top15 by accident...   (-:

Regards, Madshi.
0
 
JimBob091197Author Commented:
Igor, I think we might be getting somewhere here. I copied your example and it works fine.

However, I insist again that the thread is NOT necessary. The following code (for the timer event) works 100% WITHOUT using any threads:

procedure TForm1.tmrTestTimer(Sender: TObject);
var
  I: Integer;
  H: HDC;
begin
  H := GetDC(0);
  for I := 0 to Screen.Height - 1 do
    BitBlt(B.Canvas.Handle, 0, I, B.Width, 1, H, 0, I, SRCCOPY);
  ReleaseDC(0, H);
  B.SaveToFile('c:\'+IntToHex(GetTickCount, 8)+'.bmp');
end;

BUT why must the form be minimized to avoid the out of resources problem? This is very strange and defeats my purposes, as I need to capture the whole screen, including my form. (I could put the capture in another app, but what is going wrong here???)

Thanks,
JB
0
 
JimBob091197Author Commented:
Madshi, yes even BEFORE the scr shot.

Take this example, in a timer event:

  Bmp := TBitmap.Create;
  try
    Bmp.Width := 1024;
    Bmp.Height := 768;
    Bmp.PixelFormat := pf24bit;
  finally
    Bmp.Free;
  end;

The code above causes the mouse freeze.

But the code below does NOT cause the mouse to freeze:

  Bmp := TBitmap.Create;
  try
    Bmp.PixelFormat := pf24bit;
    Bmp.Width := 1024;
    Bmp.Height := 768;
  finally
    Bmp.Free;
  end;

BUT the 2nd code above (changing p/f BEFORE setting width and height) causes strange things to happen when using BitBlt (e.g. EOutOfResources when calling Bmp.SaveToFile()) - See my discussion with Igor.


> It is still open. You didn't get into the top15 by accident...   (-:

Right, then I will e-mail you shortly!  ;-)

Thanks,
JB
0
 
JimBob091197Author Commented:
Hi all

I have found a temporary solution. It is not ideal, but it will have to do for now and it seems to work OK.

I have modified my code & logic to create 2 bitmaps when my app starts up (in FormCreate). I set width & height, and then set pixelformat to pf8bit and the other to pf24bit.

Then I can capture & BitBlt using these 2 bitmaps with no mouse freezes, no OutOfResources, etc. (The only delay is when my app starts when setting up the initial bitmaps' pixelformats.) Plus I don't need any threads!!  ;-)

Regards,
JB
0
 
MadshiCommented:
Try this function, it should get rid of the delays:

function NewBitmap(width, height, bpp: integer) : TBitmap;
var bi : TBitmapInfo;
    p1 : pointer;
begin
  ZeroMemory(@bi, sizeOf(bi));
  bi.bmiHeader.biSize     := sizeOf(TBitmapInfoHeader);
  bi.bmiHeader.biWidth    := width;
  bi.bmiHeader.biHeight   := height;
  bi.bmiHeader.biBitCount := bpp;
  bi.bmiHeader.biPlanes   := 1;
  result := TBitmap.Create;
  result.Handle := CreateDIBSection(0, bi, DIB_RGB_COLORS, p1, 0, 0);
end;

Regards, Madshi.
0
 
JimBob091197Author Commented:
Thanks, Madshi, but I still get the delay when using your function:

MyBmp := NewBitmap(1024, 768, 24);

Not to worry, though, my "temporary" solution above will work for now, even if it is not ideal. Still a lot of unanswered questions though, such as why this EOutOfResources problem occurs!!??

Regards,
JB

P.S. Your friend from the Camera Club says "Hi".

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

In my temporary solution, I forgot to mention that I do use one of Igor's ideas: Instead of BitBlt the entire image (causes a "mini-freeze") I use Igor's "for i := 0 to Screen.Height - 1" suggestion. It works fine. If nothing further comes of this question then I will award the points to Igor for all the effort! Thanks Igor! (And thanks to Madshi too.)

JB
0
 
AvonWyssCommented:
JimBob, I did some experiments. VNC, a remote control application, also has this kind of "mouse freeze" symptom. Since it is running as service in the background, it's very probable that this is just normal Windows NT/2000/XP behaviour (probably graphics operations, including conversions, lock a critical section or mutex to prevent concurrency issues).
0
 
JimBob091197Author Commented:
AvonWyss, I think you may be right. It was actually VNC that gave me the idea to create the temp bitmaps on startup. I noticed that VNC has a slight mouse freeze on the host machine when winvnc.exe starts up, but the mouse doesn't seem to freeze after that.

Thanks,
JB

0
 
MadshiCommented:
>> I still get the delay when using your function

Wow, I didn't think that w2k is *that* bad...   :-(

Regards, Madshi.
0
 
JimBob091197Author Commented:
Hi again all

This question appears to have reached its end. I will award the points to Igor as mentioned.

Thanks to others who contributed.

Thanks to Madshi for madCollection license!!

Regards,
JB
0
 
AvonWyssCommented:
JimBob, enable the "Poll full screen" mode and disable the "Poll foreground window only" and "Poll console windows only". VNC does also split the screen when doing snapshots (in 4 or maybe more parts), and I do have some "staggering" when it is set up like this.

In default mode, VNC hooks windows for drawing messages and then only checks for changes on the modified part of the screen. Therefore it only does very little capturing. Also note that by default, VNC does transfer the same bit depth as the screen is. The 8-Bit-Mode seems to be proprietary to VNC (fixed palette) and I suppose that they are doing the conversion themselfes instead of using WIndows.
0
 
JimBob091197Author Commented:
Thanks, AvonWyss. I have played around with VNC as you mention.

In my situation, I am satisfied with my solution mentioned above. I find that if I change the PixelFormat when my app starts then I get a slight delay at start-up. But after that I can capture (8-bit or 24-bit) with no mouse-freeze. Not ideal, but I am satisfied with the end result.

Thanks,
JB
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 15
  • 5
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now