Here's a snippet I put together from pieces of working code. The main difference I see is setting the mask bits and using memsection.
// assumes height and width passed in
int bpp = 32; // Bits per pixel
int stride = (width * (bpp / 8));
unsigned int byteCount = (unsigned int)(stride * height);
HANDLE hMemSection = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, byteCount, NULL );
if (hMemSection == NULL)
return false;
BITMAPV5HEADER bmh;
memset( &bmh, 0, sizeof( BITMAPV5HEADER ) );
bmh.bV5Size = sizeof( BITMAPV5HEADER );
bmh.bV5Width = width;
bmh.bV5Height = -height;
bmh.bV5Planes = 1;
bmh.bV5BitCount = 32;
bmh.bV5Compression = BI_RGB;
bmh.bV5AlphaMask = 0xFF000000;
bmh.bV5RedMask = 0x00FF0000;
bmh.bV5GreenMask = 0x0000FF00;
bmh.bV5BlueMask = 0x000000FF;
HDC hdc = ::GetDC( NULL );
HBITMAP hDIB = ::CreateDIBSection( hdc, (BITMAPINFO *) &bmh, DIB_RGB_COLORS,
&pBits, hMemSection, (DWORD) 0 );
::ReleaseDC( NULL, hdc );
// Much later when done manipulating the bitmap
::CloseHandle( hMemSection );