There should really be a tutorial on this somewhere, since most people just want a canvas to write on that doesn't disappear when the window is covered and then uncovered by another window, or minimized and maximized. It doesn't take that much code to do this, and it's way easier than jumping into DirectDraw. If there is enough demand for this, then I will write one.
I learned the code from Programming Windows, Fifth Edition by Charles Petzold
, which is highly recommended, as it has over 300 pages on dealing with bitmaps, BUT if you do not care about modes < 24 bit, then you needn't know 90% of it. Basically, this is what I do:
Call CreateDIBSection() like so:
hBitmap = CreateDIBSection (
1st param is NULL, you don't need a hdc.
Notice the 2nd parameter can just be a BITMAPINFOHEADER struct, and is type cast into the type required. This is the first field of the structure it is expecting, as it doesn't need the second field for 24 or 32 bit bitmaps. Look into the structs, and you'll know what I mean.
After the call, pBits BECOMES a pointer to the raw data. This is what you use to modify the pixels.
The rest of the parameters are 0, as they are not needed.
Fill in this data of this struct before the above call:
bmih.biSize = sizeof (BITMAPINFOHEADER);
bmih.biWidth = cx;
bmih.biHeight = cy;
bmih.biPlanes = 1;
bmih.biBitCount = BitCount;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
cx,cy = size of image. bitcount = 24 or 32. Pretty simple.
Each row of the bitmap is a multiple of 4 bytes. So, it is appended with blanks to make it a multiple of 4 if it is not already.
Most bitmaps are upsidedown. Unless you specify a negative height, this one will be as well.
Basically, use the pBits pointer to modify the data. Petzold makes an array of pointers, so that you have the pointer to the first byte of every row, and can access the array (and thus the row) from 0..height-1, and you can forget about the bitmap being upside down if you set them this way. This is what I use, as well.
Also, if you use GDI functions on this bitmap, check into the GdiFlush() function.
To draw the bitmap, make a memory DC with CreateCompatibleDC() passing it the DC from the client area obtained with GetDC() or BeginPaint(). Select the bitmap into the memory DC with SelectObject(). BitBlt() it to the screen. Delete the memory DC. (As far as I know there is no memory leak, as you need not remove the bitmap from the memory DC by calling SelectObject() again.)
This should be enough info to get you started.