Holy cow, I wrote a book!
A number of stock GDI objects are made available by the
GetStockObject function, but one stock GDI object
that is mysteriously missing is the stock bitmap.
You can't summon the stock bitmap, but it manages to show up in
some of them perhaps unexpected.
The stock bitmap is a monochrome 1×1 bitmap which GDI uses
in various places where it has to produce a HBITMAP
even though there really isn't any bitmap worth speaking of.
In other words, it's used when GDI has to return something
but would rather return nothing.
Every DC and metafile has a current bitmap (which you can retrieve
with GetCurrentObject), but when GDI creates a brand
new DC or metafile, it doesn't know what bitmap the program is
going to pass to SelectObject—after all,
predicting the future has yet to be perfected.
As a placeholder, it sticks in the dummy static bitmap.
There has to be a bitmap (as opposed to just leaving it NULL),
because the SelectObject function returns the previous
object or NULL on failure,
so there needs to be a way to tell the difference between
"I wasn't able to select the bitmap you requested"
"I was able to select the bitmap you requested, but there was no
Returning NULL would also break the common coding pattern:
// select the new bitmap and save the old one
HBITMAP hbmPrev = SelectObject(hdc, hbmNew);
... do something with hdc ...
// all done - restore the original bitmap
If SelectObject had returned NULL
when there was no bitmap previously selected into the DC,
then the attempt to restore the original bitmap would fail.
(Because GDI can't tell whether you passed it a
(HBITMAP)NULL or a
(HBRUSH)NULL or a
Normally, a single bitmap cannot be selected into more than one DC,
but the stock bitmap has the magical power that
it can be selected into multiple DCs at once.
Without this magical power, GDI would have to create a different
dummy bitmap to select into each newly-created DC and carry it
around so that it can be selected back into the DC just before it
Seems awful wasteful to allocate an extra bitmap per DC just for
especially back in the days of 16-bit Windows when GDI heap space
was extremely limited.
There is one more place (that comes to mind) where the stock
bitmap appears, and it's somewhat unexpected:
In other words, if you ask for a nothing-bitmap,
you get the dummy bitmap back.
This is analogous to the case of calling malloc(0),
where the implementation is permitted to return a pointer to zero bytes.
In other words, malloc(0)
can return a non-NULL value which
you can't dereference; the only things you can do with it is
free() it or realloc() it to something bigger.
In the same way that allowing zero-byte allocations simplifies boundary cases
of certain algorithms,
allowing impossibly thin bitmaps (and returning a dummy handle)
may simplify certain graphical algorithms.
Note however that this behavior of returning the stock bitmap handle
when asked to create an impossibly thin bitmap
does not apply to the CreateDIBSection function!
If you ask CreateDIBSection for an impossibly thin
bitmap, it returns NULL.
So much for consistency.