Вы не учитываете шаг / выравнивание. Каждая строка должна быть выровнена по DWORD.
Расчет шага поверхности
В несжатом растровом изображении шаг - это количество байтов, необходимое для перехода от начала одной строки пикселей к началу следующей строки. Формат изображения определяет минимальный шаг для изображения. Кроме того, графическое оборудование может потребовать большего шага для поверхности, содержащей изображение.
Для несжатых форматов RGB минимальным шагом всегда является ширина изображения в байтах, округленная до ближайшего DWORD. Вы можете использовать следующую формулу для расчета шага:
stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3)
Вам необходимо исправить способ доступа к RGBTRIPLE в буфере.
Перед "x loop" вы должны сделать что-то вроде q = (RGBTRIPLE*) (((char*)bitmap_bits) + (y * bitmap.bmWidthBytes));
CreateBitmapIndirect
создает DDB, который, возможно, не лучший выбор, вместо этого создайте DIB:
#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
static void SetPixel24(UINT w, void*bits, UINT x, UINT y, COLORREF cr)
{
RGBTRIPLE*p = ((RGBTRIPLE*) ( ((char*)bits) + (y * CalcStride(w, 24)) )) + x;
p->rgbtRed = GetRValue(cr);
p->rgbtGreen = GetGValue(cr);
p->rgbtBlue = GetBValue(cr);
}
void Silly24BPPExample()
{
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, WC_STATIC, 0, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_OVERLAPPEDWINDOW|SS_BITMAP|SS_REALSIZECONTROL, 0, 0, 99, 99, 0, 0, 0, 0);
const INT w = 4, h = 4, bpp = 24;
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
BITMAPINFOHEADER&bih = bi.bmiHeader;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = w, bih.biHeight = -h;
bih.biPlanes = 1, bih.biBitCount = bpp;
bih.biCompression = BI_RGB;
void*bits;
HBITMAP hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &bits, NULL, 0);
for (UINT x = 0; x < w; ++x)
for (UINT y = 0; y < h; ++y)
SetPixel24(w, bits, x, y, RGB(255, 0, 0)); // All red
SetPixel24(w, bits, 0, 0, RGB(0, 0, 255)); // except one blue
SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBmp);
for (MSG msg; IsWindow(hWnd) && GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
// DeleteObject(...)
}