Hello Roland,
Excellent results and a very clean coding style!
1. WM_KEYDOWN, WM_KEYUP, and WM_CHAR can't be intercepted in a DlgProc() because the Dialog window that this callback belongs to never gets keyboard focus itself. These messages are present only in a generic non-dialog frame window's WndProc() callback. So you strategy of preprocessing these messages in WinMain() is perfectly correct.
2. If you make your toolbar button strip a 256-color bitmap and use a system color COLOR_BTNFACE for the bitmap background, then you can get the toolbar button bitmap backgrounds recolored automatically to the current Windows theme on bmp load. Just use a LR_LOADMAP3DCOLORS flag in your LoadImage() call. I'm using custom themes on all my Windows platforms and your buttons don't look elegant enough to me on anything but the default theme background.
3. BS_PUSHBUTTON, BS_DEFPUSHBUTTON, or BS_PUSHLIKE styles are always drawn with the default system colors no matter what you do. WM_CTLCOLORBTN's return value (a brush handle) is ignored by these button styles.
4. The BS_OWNERDRAW style will use the brush returned by WM_CTLCOLORBTN for the custom-drawn button's background beneath the text. Everything else including borders that would reflect the button's current states and text itself will have to be drawn manually. Use WM_CTLCOLORBTN's wParam as the hDC to draw on. Use DrawFrameControl() to draw the button's borders. The context foreground and background colors refer to the button text. Use SetTextColor() and SetBkColor() calls for that. The text background color may be overridden with SetBkMode(hDC, TRANSPARENT). Use SelectObject() to select your own custom logfont (or system default GUI font from the GetStockObject() palette of objects) instead of the hDC's ugly default font.
Store this default font's handle that SelectObject() returns! Use DrawText() or TextOut() to draw the button's text.
Reselect the previously stored default font's handle back into hDC with another call to SelectObject() after the text is drawn! Failure to do so will lead to heavy GDI memory leaks.
In some themes, Windows might use the background brush returned by WM_CTLCOLORBTN incorrectly and cover your entire painting with that color on top of it. In this case, use FloodFill() to paint your hDC's background beneath the text manually and sumply return a system stock HOLLOW_BRUSH (a.k.a. NULL_BRUSH) instead. A hollow brush doesn't produce any visible effect on any painted device context.
5. Use SendMessage(hControl, WM_SETFONT, hLogFont, MakeLong(TRUE, 0)) to permanently select a stock font (or your own logfont) into any control that would exibit an ugly default font on creation. This however doesn't work for user-drawn controls similar to item 4 above.
6. Use SendDlgItemMessage(hDlg, ID_button, BM_SETIMAGE, IMAGE_BITMAP, hBmp) to set a bitmap to the button. Note well that the function uses button ID's rather than handles to identify specific buttons.
Hope this helps.