How to display raw array of pixels to the screen?

1

I am new to windows programming. I want to display the raw pixel array to the screen without using SetPixel function because it's too slow in my standards. I am using this question as my reference.

I made a small program below to fill the pixel array with random RGB values and display it to the screen. The result wasn't what I anticipated, I got the white canvas. I tried to change this line ptr++ = (b << 16) | (g << 8) | r; to ptr++ = 0x000000FF; expecting red canvas but I got the same result.

#include <stdlib.h>
#include <time.h>
#include <windows.h>

const int win_width = 500;
const int win_height = 450;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    RECT rect;
    int width, height;
    COLORREF *display;

    switch (msg)
    {
    case WM_CREATE:
        srand((unsigned int) time(NULL));
        GetClientRect(hWnd, &rect);
        width = rect.right - rect.left;
        height = rect.bottom - rect.top;
        display = (COLORREF *) malloc(sizeof(COLORREF) * width * height);
        COLORREF *ptr = display;

        for (int y = 0; y < height; ++y)
        {
            for (int x = 0; x < width; ++x)
            {
                int r = rand() % 256;
                int g = rand() % 256;
                int b = rand() % 256;

                *ptr++ = (b << 16) | (g << 8) | r;
            }
        }

        break;
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hDC, memDC;
        HBITMAP hBmp, hOldBmp;

        hDC = BeginPaint(hWnd, &ps);
        memDC = CreateCompatibleDC(hDC);
        hBmp = CreateBitmap(width, height, 1, 32, (void *) display);
        hOldBmp = (HBITMAP) SelectObject(memDC, hBmp);

        BitBlt(hDC, rect.left, rect.top, width, height, memDC, 0, 0, SRCCOPY);

        SelectObject(memDC, hOldBmp);
        DeleteObject(hBmp);
        DeleteDC(memDC);

        EndPaint(hWnd, &ps);

        break;
    }
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }

    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    const TCHAR szClassName[] = TEXT("MyClass");

    WNDCLASS wc;
    HWND hWnd;
    MSG msg;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = szClassName;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClass(&wc))
    {
        MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hWnd = CreateWindow(szClassName,
        TEXT("Random Pixels"),
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, win_width, win_height,
        NULL, NULL, hInstance, NULL);

    if (hWnd == NULL)
    {
        MessageBox(NULL, TEXT("Window Creation Failed!"), TEXT("Error!"),
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

I know there's something wrong with my code inside WM_PAINT but I don't know how to fix it. I will appreciate any form of assistance. Thanks in advance.

c
winapi
asked on Stack Overflow Jun 2, 2020 by Jimmy Yang

1 Answer

2

The variable display that holds the pixel data has automatic lifetime. Its lifetime ends whenever control leaves WndProc. A consequence is, that every invocation of WndProc starts out with a new (indeterminate) value for display.

To solve this, display needs to have static storage duration. The easiest way to accomplish this is to replace

COLORREF *display;

with

static COLORREF *display;

This has 2 consequences:

  1. The value stored in display survives separate invocations of WndProc.
  2. The value stored in display is now properly zero-initialized.
answered on Stack Overflow Jun 2, 2020 by IInspectable

User contributions licensed under CC BY-SA 3.0