#include HINSTANCE g_hInstance; typedef void(*fill_colortable)(RGBQUAD*); struct image_info { BITMAPINFO* pbmi; HBITMAP hBitmap; PVOID pData; int cx; int cy; UINT uUsage; fill_colortable colortable; const char* desc; }; void grayscale(RGBQUAD* bmiColors) { for (int i = 0; i < 256; i++) { bmiColors[i].rgbRed = i; bmiColors[i].rgbGreen = i; bmiColors[i].rgbBlue = i; bmiColors[i].rgbReserved = 0; } } void red(RGBQUAD* bmiColors) { for (int i = 0; i < 256; i++) { bmiColors[i].rgbRed = i; bmiColors[i].rgbGreen = 0; bmiColors[i].rgbBlue = 0; bmiColors[i].rgbReserved = 0; } } void gradient(RGBQUAD* bmiColors) { for (int i = 0; i < 256; i++) { int scale = i * 4; int px = scale % 256; switch (scale / 256) { case 0: bmiColors[i].rgbRed = 255; bmiColors[i].rgbGreen = px; bmiColors[i].rgbBlue = 0; break; case 1: bmiColors[i].rgbRed = 255 - px; bmiColors[i].rgbGreen = 255; bmiColors[i].rgbBlue = 0; break; case 2: bmiColors[i].rgbRed = 0; bmiColors[i].rgbGreen = 255; bmiColors[i].rgbBlue = px; break; case 3: bmiColors[i].rgbRed = 0; bmiColors[i].rgbGreen = 255 - px; bmiColors[i].rgbBlue = 255; break; } bmiColors[i].rgbReserved = 0; } } #define kImageDimension 256 struct image_info g_Images[] = { { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_RGB_COLORS, grayscale, "RGB" }, { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_RGB_COLORS, red, "RGB" }, { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_RGB_COLORS, gradient, "RGB" }, { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_PAL_COLORS, grayscale, "PAL" }, { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_PAL_COLORS, red, "PAL" }, { NULL, NULL, NULL, kImageDimension, kImageDimension, DIB_PAL_COLORS, gradient, "PAL" }, }; void CreateDIBBitmap(struct image_info* image) { DIBSECTION ds; HDC hdcMem; UCHAR* pData; int x, y; BITMAPINFO* pbmi = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); memset(pbmi, 0, sizeof(BITMAPINFO)); pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader); pbmi->bmiHeader.biWidth = image->cx; pbmi->bmiHeader.biHeight = image->cy; pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biBitCount = 8; pbmi->bmiHeader.biCompression = BI_RGB; pbmi->bmiHeader.biSizeImage = image->cx * image->cy; image->pbmi = pbmi; image->colortable(pbmi->bmiColors); hdcMem = CreateCompatibleDC(NULL); image->hBitmap = CreateDIBSection(hdcMem, pbmi, image->uUsage, &image->pData, NULL, 0); GetObject(image->hBitmap, sizeof(DIBSECTION), &ds); DeleteDC(hdcMem); pData = (UCHAR*)image->pData; for (x = 0; x < ds.dsBm.bmWidth; ++x) { for (y = 0; y < ds.dsBm.bmHeight; ++y) { pData[x + y * ds.dsBm.bmWidthBytes] = (UCHAR)x; } } } void OnInit(HWND hWnd) { for (size_t n = 0; n < _countof(g_Images); ++n) { CreateDIBBitmap(g_Images + n); } } const int kNumImagesPerRow = 3; void OnPaint(HWND hWnd) { char buf[100]; PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); { HDC hMemoryDC = CreateCompatibleDC(hdc); int window = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); int memory = GetDeviceCaps(hMemoryDC, BITSPIXEL) * GetDeviceCaps(hMemoryDC, PLANES); sprintf(buf, "Wnd: %d bpp, mem: %d bpp", window, memory); SetWindowTextA(hWnd, buf); for (size_t n = 0; n < _countof(g_Images); ++n) { int x = (n % kNumImagesPerRow) * kImageDimension; int y = (n / kNumImagesPerRow) * kImageDimension; HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, g_Images[n].hBitmap); UINT num = SetDIBColorTable(hMemoryDC, 0, 256, g_Images[n].pbmi->bmiColors); sprintf(buf, "entries: %d (%s)", num, g_Images[n].desc); BitBlt(hdc, x, y, kImageDimension, kImageDimension, hMemoryDC, 0, 0, SRCCOPY); TextOutA(hdc, x, y, buf, strlen(buf)); SelectObject(hMemoryDC, hOldBitmap); } DeleteDC(hMemoryDC); } EndPaint(hWnd, &ps); } LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_NCCREATE: OnInit(hWnd); break; case WM_PAINT: OnPaint(hWnd); return 0L; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, message, wParam, lParam); } ATOM registerClass(const TCHAR* className) { WNDCLASSEX wcex; memset(&wcex, 0, sizeof(wcex)); wcex.cbSize = sizeof(wcex); wcex.lpszClassName = className; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = MainWndProc; wcex.hInstance = g_hInstance; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); return RegisterClassEx(&wcex); } int main() { MSG msg = { NULL }; RECT work; LONG ww, wh, wx, wy; HWND window; ATOM wndClass = registerClass(TEXT("Test_wnd_cls")); DWORD dwStyle = WS_POPUPWINDOW | WS_CAPTION; DWORD dwExStyle = 0; LONG remainder = _countof(g_Images) % kNumImagesPerRow; LONG width = (_countof(g_Images) > kNumImagesPerRow ? kNumImagesPerRow : remainder) * kImageDimension; LONG height = _countof(g_Images) / kNumImagesPerRow * kImageDimension + (remainder ? 1 : 0) * kImageDimension; RECT rc = { 0, 0, width, height }; AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); SystemParametersInfo(SPI_GETWORKAREA, 0, &work, 0); ww = rc.right - rc.left; wh = rc.bottom - rc.top; wx = ((work.right - work.left - ww) >> 1) + work.left; wy = ((work.bottom - work.top - wh) >> 1) + work.top; window = CreateWindowEx(dwExStyle, TEXT("Test_wnd_cls"), TEXT("test"), dwStyle, wx, wy, ww, wh, NULL, NULL, g_hInstance, NULL); ShowWindow(window, SW_SHOW); while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } ExitProcess(0); }