Log in

View Full Version : API hook/programing question?


_xhp_
October 11th, 2005, 10:21
The goal:
Get the picture of a window that uses WS_EX_LAYERED and UpdateLayeredWindow to paint itself (and does not use WM_PAINT or handles WM_PRINT/WM_PRINTCLIENT).

PrintWindow API won't work at all (becouse it relies on WM_PAINT).

Any of the BitBlt's are not an option becouse I need to get a picture of a window even when it is partialy hidden.

So I tought this would solve my problems:
1) hook and redirect UpdateLayeredWindow
2) Get the contens of the srcHdc argument and copy it to my DC

Now, the only problem is it doesn't work. So the question is why?
This is more of a programming question than it is a reversing one but I tought I'll try my luck here.



BOOL __stdcall UpdateLayeredWindowInjected(HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags )
{
try
{
if (hdcSrc)
{
SIZE bmpSize;
if (psize)
{
bmpSize = *psize;
}
else
{
RECT r;
GetWindowRect(hwnd, &r);
bmpSize.cx = abs(r.right - r.left);
bmpSize.cy = abs(r.bottom - r.top);
}

HDC hCaptureDC = CreateCompatibleDC(hdcSrc);
if (hCaptureDC)
{
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hdcSrc,
bmpSize.cx, bmpSize.cy);

if(hCaptureBitmap )
{
HGDIOBJ oldObj = SelectObject(hCaptureDC,hCaptureBitmap);

BitBlt(hCaptureDC,0,0,bmpSize.cx, bmpSize.cy,hdcSrc,0,0,SRCCOPY);

//::OpenClipboard(hwnd);
::OpenClipboard(NULL);
::EmptyClipboard() ;
::SetClipboardData (CF_BITMAP, hCaptureBitmap) ;
::CloseClipboard () ;
}
DeleteDC(hCaptureDC);
}
}
}
catch(...)
{
}

BOOL ret = UpdateLayeredWindowOriginal(hwnd,hdcDst,pptDst,psize,hdcSrc,pptSrc,crKey,pblend,dwFlags );
return ret;
}

I use the upper code in a simple dll, I inject the dll using RemoteLib (http://www.codeproject.com/dll/RemoteLib.asp) and then hook the API with MS detours.
The problem is I get "Courrupted clipoard data" when I try to paste the bitmap. This could be becouse of the transparency.

nikolatesla20
October 11th, 2005, 11:51
I did notice this on MSDN:

Quote:

The window identified by the hWndNewOwner parameter does not become the clipboard owner unless the EmptyClipboard function is called.

If an application calls OpenClipboard with hwnd set to NULL, EmptyClipboard sets the clipboard owner to NULL; this causes SetClipboardData to fail.



-nt20

_xhp_
October 11th, 2005, 13:43
Thank you for the reply.

I tried using the handle of the passed window as well as the handle of the desktop. I also added some error checking - everything returns ok so it should work

Here is the new code:


BOOL __stdcall UpdateLayeredWindowInjected(HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags )
{
try
{
if (hdcSrc)
{
SIZE bmpSize;
if (psize)
{
bmpSize = *psize;
}
else
{
RECT r;
GetWindowRect(hwnd, &r);
bmpSize.cx = abs(r.right - r.left);
bmpSize.cy = abs(r.bottom - r.top);
}

HDC hCaptureDC = CreateCompatibleDC(hdcSrc);
if (hCaptureDC)
{
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hdcSrc,
bmpSize.cx, bmpSize.cy);

if(hCaptureBitmap )
{
HGDIOBJ oldObj = SelectObject(hCaptureDC,hCaptureBitmap);

BitBlt(hCaptureDC,0,0,bmpSize.cx, bmpSize.cy,hdcSrc,0,0,SRCCOPY);

//HWND clipHwnd = hwnd;
HWND clipHwnd = GetDesktopWindow();
if(::OpenClipboard(clipHwnd))
{
if(::EmptyClipboard())
{
if(::SetClipboardData (CF_BITMAP, hCaptureBitmap))
{
MessageBox(NULL, _T("Check your clipboard",_T("", MB_OK);
}
::CloseClipboard () ;
}
}
}
DeleteDC(hCaptureDC);
}
}
}
catch(...)
{
}

_xhp_
October 11th, 2005, 16:30
Well, it was the clipboard code that was causing trouble.

The following works:


BOOL __stdcall UpdateLayeredWindowInjected(HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags )
{
try
{
if (hdcSrc)
{
SIZE bmpSize;
if (psize)
{
bmpSize = *psize;
}
else
{
RECT r;
GetWindowRect(hwnd, &r);
bmpSize.cx = abs(r.right - r.left);
bmpSize.cy = abs(r.bottom - r.top);
}

HDC hCaptureDC = CreateCompatibleDC(hdcSrc);
if (hCaptureDC)
{
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hdcSrc,
bmpSize.cx, bmpSize.cy);

if(hCaptureBitmap )
{
HGDIOBJ oldObj = SelectObject(hCaptureDC,hCaptureBitmap);

BitBlt(hCaptureDC,0,0,bmpSize.cx, bmpSize.cy,hdcSrc,0,0,SRCCOPY);

// Functions from SourceCode...
HANDLE dib = DDBToDIB(hCaptureBitmap, BI_RGB, NULL, 24);
if (dib)
{
WriteDIB(_T("C:\\a.bmp", dib);
}
}
DeleteDC(hCaptureDC);
}
}
}
catch(...)
{
}

BOOL ret = UpdateLayeredWindowOriginal(hwnd,hdcDst,pptDst,psize,hdcSrc,pptSrc,crKey,pblend,dwFlags );
return ret;
}


I don't know why the clipboard code wasn't working and I don't care

Thanks.

laola
October 14th, 2005, 01:42
Using GDI+ you don't have to use the clipboard at all, instead you can save the captured image directly in a variety of supported formats (BMP, JPG, GIF, etc.) - might be worth a look.

Silver
October 14th, 2005, 05:57
For reference I believe there are 2 versions of the clipboard, the standard windows clipboard (that holds text, bitmaps etc) and the OLE object clipboard (which can hold complex objects). They do behave differently.

You may want to investigate this. I know this clipboard issue is something that crops up quite regularly in game coding...

_xhp_
October 14th, 2005, 12:39
I really don't know what was/is wrong.

The copying to the clipboard was done just to verify the bitmap grabing works (and it does work). I dont even have to save - it is just a testing code...

Things get even wierder - for instance this works nice:



BOOL __stdcall UpdateLayeredWindowInjected(HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags )
{
try
{
if (hdcSrc)
{
SIZE bmpSize;
if (psize)
{
bmpSize = *psize;
}
else
{
RECT r;
GetWindowRect(hwnd, &r);
bmpSize.cx = abs(r.right - r.left);
bmpSize.cy = abs(r.bottom - r.top);
}

HDC hCaptureDC = CreateCompatibleDC(hdcSrc);
if (hCaptureDC)
{
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hdcSrc,
bmpSize.cx, bmpSize.cy);

if(hCaptureBitmap)
{
HGDIOBJ oldObj = SelectObject(hCaptureDC,hCaptureBitmap);

BitBlt(hCaptureDC,0,0,bmpSize.cx, bmpSize.cy,hdcSrc,0,0,SRCCOPY);

HANDLE dib = DDBToDIB(hCaptureBitmap, BI_RGB, NULL, 24);

::OpenClipboard(hwnd);
::EmptyClipboard();
::SetClipboardData (CF_DIB, dib ) ;
::CloseClipboard () ;

/*if (dib)
{
WriteDIB(_T("C:\\a.bmp", dib);
}*/
}
DeleteDC(hCaptureDC);
}
}
}
catch(...)
{
}

BOOL ret = UpdateLayeredWindowOriginal(hwnd,hdcDst,pptDst,psize,hdcSrc,pptSrc,crKey,pblend,dwFlags );
return ret;
}


So it seems it works with DIBs. This is perfect for me becouse DIBs are what I need

nikolatesla20
October 14th, 2005, 15:19
Then no doubt it's because of the format of the bitmap data that was being sent to the clipboard - the clipboard pallete couldn't handle it (because it was a device dependent bitmap)

-nt20