Click to See Complete Forum and Search --> : capturing an application window


dmanglik
May 20th, 1999, 06:38 AM
I try to capture the client window of an application using the following code sequence :



BOOL TakeSnapShot(HWND hWnd, long wid, long ht)
//hWnd is the window handle of the application window whose client area is to be captured
//'wid' and 'ht' are the width and height of the client area of the applicaiotn window.
{
CWnd *pWnd = new CWnd;
if (!pWnd->Attach(hWnd))
return FALSE;

CDC *dc = pWnd->GetDC(); //Get the DC of the client window of application
CDC memDC;
memDC.CreateCompatibleDC(dc);


CBitmap bitmap;
bitmap.CreateCompatibleBitmap(dc, wid, ht);

CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);

memDC.BitBlt(0, 0, wid, ht, &memDC, 0, 0, SRCCOPY);

pWnd->Detach();
delete pWnd;

memDC.SelectObject(pOldBitmap);

//Rest of the code to get the bitmap
}




The problem I am getting is that if there is any other window (such as Task Manager) sitting on top of the client area of the application window (whose snapshot is to be taken), the final snapshot bitmap shows these other windows as well.
Does this problem occur because of some limitaion of 'BitBlt' ??
How can I prevent these other windows from coming into the way ??

Any help would be highly appreciated.

Thanks,
Deep

Jason Teagle
May 20th, 1999, 08:23 AM
I'm afraid it's BitBlt(). It's a bit of a crap function. I wish I could suggest an alternative, but I can't.

There is one dirty trick I can think of you could try, although I doubt if it would work:

1) Create a bitmap compatible with that window, and with the same size as its client area.
2) Get a DC to that window, and attempt to select your bitmap into it; remember the bitmap pointer / handle that pops out of it.
3) Send that window a WM_PAINT message which tells it to paint everything, and then force it to repaint now (InvalidateRect(NULL) might work on it, or send the message manually - then call UpdateWindow() on it). This should cause it to paint while your bitmap is in there, thus painting on your bitmap.
4) Select your bitmap out again (replacing the original bitmap) (you might need to cause another full repaint to make sure the other window's contents are intact). Now, you should have a copy.

If that works, let me know - it'll be a good trick to add to my arsenal (which currently consists of 0 dirty tricks!).

dmanglik
May 24th, 1999, 04:42 AM
Hi Jason,

I think you suggested a very good workaround. Only thing is that I am not able to get it working.
Maybe I'm missing something which you can see. I'm reproducing the code that I wrote following the steps suggested by you.



BOOL TakeSnapShot(HWND hWnd, long wid, long ht)
//hWnd is the window handle of the application window whose client area is to be captured
//'wid' and 'ht' are the width and height of the client area of the applicaiotn window.
{
CWnd *pWnd = new CWnd;
if (!pWnd->Attach(hWnd))
return FALSE;

CDC *dc = pWnd->GetDC(); //Get the DC of the client window of application
CBitmap bmp;
bmp.CreateCompatibleBitmap(dc, wid, ht);
CBitmap* pOldBitmap =dc->SelectObject(&bmp);

pWnd->SendMessage(WM_PAINT);
pWnd->UpdateWindow();

dc->SelectObject(pOldBitmap);

pWnd->Detach();
delete pWnd;

//Rest of the code to get the bitmap from 'bmp' (use of GetDIBits function).
}





When I use "GetDIBits" to obtain the bitmap information from 'bmp', though it gives me height, width, bit count, etc,. it fails to give me the the actual bits. As a result, I get a black bitmap.

Can you tell what may be going wrong ??

Thanks a lot for helping me.

Deep

Jason Teagle
May 25th, 1999, 02:37 AM
I owe you an apology. There was a fundamental flaw in my plan. I intended to put our own bitmap into that window, get it to paint, and then pull the bitmap out again. The problem is, I was trying to select a bitmap into a WINDOW DC, not a memory DC - and this is not possible. So, this code was, unfortunately, useless.

I have tried a couple of other methods to achieve the result you want, and they have all failed. I have not given up yet, but it looks like BitBlt() was the only way. You will have to ensure that the window is at the the top of the Z-order before doing the BitBlt() to get over the problem of other windows appearing in the picture.

When I find a better solution, I will let you know.