Getting HBITMAP from a DC

Started by
7 comments, last by Evil Steve 16 years, 5 months ago
I thought this'd be a trivial matter, but for some reason Microsoft seems to have made this overly complicated. This is my code:

	BITMAPINFO bi;
	ZeroMemory(&bi, sizeof(bi));
	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	
	HBITMAP rbmp = (HBITMAP)SelectObject(rdc, (HGDIOBJ)NULL);

        // 100 is an arbitrary value - I don't know the precise
        // measurements of rbmp; I just want to get the size/format
	GetDIBits(rdc, rbmp, 0, 100, NULL, &bi, DIB_RGB_COLORS);

I also tried replacing HBITMAP rbmp = (HBITMAP)SelectObject(rdc, (HGDIOBJ)NULL); with HBITMAP new_bmp = CreateCompatibleBitmap(rdc, 1, 1); HBITMAP rbmp = (HBITMAP)SelectObject(rdc, (HGDIOBJ)new_bmp); SelectObject() always returns NULL and bi remains unchanged. Is there a simpler way of accomplishing this? A way that works, maybe? If there is, I certainly cannot find it on MSDN. PS - I tried calling this code after and between calls to BeginPaint() / EndPaint().
Advertisement
If SelectObject() returns NULL then an error occurred. Are you sure that rdc is a valid DC?
From the MSDN for SelectObject:
Quote:
The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.

What type of object is NULL? Is a BITMAP, a BRUSH, a PEN, a FONT or anything else that can be selected into a DC? To get the current contents of a portion of the thing a DC is drawing on you need to do the following:
1. Create a new bitmap2. Create a new DC3. Select new bitmap into new DC4. BitBlt from DC of interest into new DC

But if all you want is the dimensions and/or the format of the thing the DC is drawing to then you need to use GetDeviceCaps (link to MSDN information).

Skizz
Colin - yeah, as far as I can tell, the DC is valid and GetLastError() returns no error.


Skizz - erm, call GetDeviceCaps() with which arguments? As far as I can tell, the following seems to be the most reliable way:

	HWND hwnd = WindowFromDC(rdc);	RECT rc;	GetClientRect(hwnd, &rc);	int wd = rc.right - rc.left;	int ht = rc.bottom - rc.top;		HDC tDC = CreateCompatibleDC(rdc);	HBITMAP tBMP = CreateCompatibleBitmap(rdc, width, height);	SelectObject(tDC, tBMP);	BitBlt(tDC, 0, 0, width, height, rdc, x, y, SRCCOPY);	DeleteDC(tDC);	DeleteObject(tBMP);
GetCurrentObject is what you want:
HBITMAP hBmp = GetCurrentObject(rdc, OBJ_BITMAP);
Thanks! Unfortunately in this case, thinking about it a little, it's not really of too much use unless there's a function equivalent of GetDIBits() that'd allow me to get a subsection of rdc into a buffer (eg a width x height patch at coordinates x, y).

But it is kind of criminal that this function isn't more actively cross-referenced in MSDN as I've felt need for it before and done some quite extensive Googling and still not found it.
Quote:Original post by irreversible
equivalent of GetDIBits() that'd allow me to get a subsection of rdc into a buffer (eg a width x height patch at coordinates x, y).

See my previous post, i.e. BitBlt.

Skizz
What I meant is that GetCurrentObject() would be useful if I could get a subsection of the HBITMAP returned by it as a regular data buffer without having to allocate an intermediate HDC/HBITMAP, which would mean I could skip the blitting bit altogether.

Currently I can just as well just allocate the new HDC/HBITMAP, blit the section I need directly from the other DC and then retrieve the data buffer with GetDIBits(), making the GetCurrentObject() call obsolete.
Quote:Original post by irreversible
What I meant is that GetCurrentObject() would be useful if I could get a subsection of the HBITMAP returned by it as a regular data buffer without having to allocate an intermediate HDC/HBITMAP, which would mean I could skip the blitting bit altogether.

Currently I can just as well just allocate the new HDC/HBITMAP, blit the section I need directly from the other DC and then retrieve the data buffer with GetDIBits(), making the GetCurrentObject() call obsolete.
There's nothing like this built into the Win32 API, it's a pretty specialised thing you want to do, and you can't get direct access to the bits, because they're in a device dependant format. BitBlt()int to a scratch surface seems the best choice here.

This topic is closed to new replies.

Advertisement