How to Color Pixels in a Windows Application Using C

When I first started out programming in C, I could not find any examples for simply using a window as a canvas. I just wanted to color pixels, shoundn't such a thing be a basic demand of programmers and thus tons of examples exist? The only thing I could find then was the SetPixel() function which was too slow. I finally found an example for displaying a ".bmp" file and modified the code for use as a canvas application. This is under Windows so in order to color pixels, one must go through the bureaucratic process of filling out the forms (data structures) before the canvas can be used.

Here's the code...


//Use dev-c++ to compile.

#include <windows.h>

int pBitsAllocated = 0;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
TCHAR szAppName[] = TEXT("paint");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

RegisterClass(&wndclass);
hwnd = CreateWindow(szAppName, TEXT("Drawing a Line"), WS_OVERLAPPEDWINDOW, 0, 0, 480, 320, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BITMAPINFO pbmi[40];
static BYTE *pBits;
HDC hdc;
PAINTSTRUCT ps;

int y, x, i, xCenter, yCenter;
static int winByteWidth = 480*3+480%4, winWidth = 480, winHeight = 320;

if (WM_CREATE == message)
{
pbmi->bmiHeader.biSize = 40;
pbmi->bmiHeader.biWidth = winWidth;
pbmi->bmiHeader.biHeight = winHeight;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 24;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = winWidth * winHeight;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
return 0;
}

if (WM_SIZE == message)
{
winWidth = LOWORD(lParam);
winHeight = HIWORD(lParam);
winByteWidth = winWidth * 3 + winWidth % 4;
xCenter = winWidth / 2;
yCenter = winHeight / 2;

pbmi->bmiHeader.biWidth = winWidth;
pbmi->bmiHeader.biHeight = winHeight;
pbmi->bmiHeader.biSizeImage = winWidth * winHeight;

/*Allocate memory for canvas*/
if (pBitsAllocated){free(pBits);}
pBits = malloc(winByteWidth * winHeight);
pBitsAllocated = 1;

/*Make background black*/
for (i=0; i < winByteWidth * winHeight; ++i)
{
pBits[i] = 0;
}

/*Draw a green line*/
for (i=0; i < 60; ++i)
{
x = i + xCenter;
y = -i + yCenter;
if ((x >= 0) && (x < winWidth) && (y >= 0) && (y < winHeight))
{
pBits[0+x*3+winByteWidth*y] = 0;
pBits[1+x*3+winByteWidth*y] = 0xFF;
pBits[2+x*3+winByteWidth*y] = 0;
}
}

InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);

hdc = GetDC(hwnd);
SetDIBitsToDevice(hdc, 0, 0, winWidth, winHeight, 0, 0, 0, winHeight, pBits, pbmi, DIB_RGB_COLORS);
ReleaseDC(hwnd, hdc);
return 0;
}

if (WM_PAINT == message)
{
hdc = BeginPaint(hwnd, &ps);
SetDIBitsToDevice(hdc, 0, 0, winWidth, winHeight, 0, 0, 0, winHeight, pBits, pbmi, DIB_RGB_COLORS);
EndPaint(hwnd, &ps);
return 0;
}

if (WM_DESTROY == message)
{
if ( pBitsAllocated ){free(pBits);}
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}