MFC BitBlt and SetDIBits vs. SetBitmapBits

bitblt, bitmap, c++, dib, mfc

Solution

Ross Ridge was correct in pointing out the code order mistake. However, this didn't solve the problem.

The problem was in the parameters I was passing. I am new to C++ and MFC and often forget all the "operators" which can act on types to automatically convert them.

Previously I had this:

int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
              0, sourceImage->GetHeight(), translatedImage, 
              &info, DIB_PAL_COLORS);

The correct call is this:

int r = SetDIBits(*pDC, *dispBMP,
              0, sourceImage->GetHeight(), translatedImage, 
              &info, DIB_PAL_COLORS);

(Note I pass dereferenced pointers in the first two parameters.) Everything else was correct, including the counter-intuitive `DIB_PAL_COLORS` flag for a bitmap which has not palette.

After obviously missing some key points in the documentation I reread it and then found this which has sample code showing that I was simply passing the parameters incorrectly.

Problem

I have a bitmap stored as a BGRA array of bytes. This is the code I've been using to paint the bitmap: ``` CDC *dispDC = new CDC(); dispDC->CreateCompatibleDC(pDC); CBitmap *dispBMP = new CBitmap(); dispBMP->CreateCompatibleBitmap(pDC, sourceImage->GetWidth(), sourceImage->GetHeight()); dispDC->SelectObject(this->dispBMP); ``` The actual copying of the pixels in the `translatedImage` array happens with this: ``` dispBMP->SetBitmapBits(sourceImage->GetArea() * 4, translatedImage); ``` Then after some more processing I call `pDC->StretchBlt` with `dispDC` as the source CDC. This works fine when logged in locally because the display is also set to 32bpp. Once I log in with Remote Desktop, the display goes to 16bpp and the image is mangled. The culprit is `SetBitmapBits`; i.e. for it to work, I have to properly fill `translatedImage` with the 16bpp version of what I want to show. Rather than do this myself, I searched the documentation and found `SetDIBits` which sounds like it does what I want: The SetDIBits function sets the pixels in a compatible bitmap (DDB) using the color data found in the specified DIB. In my case, the DIB is the 32bpp RGBA array, and the DDB is `dispBMP` which I create with `CreateCompatibleBitmap`. So instead of my call to `SetBitmapBits`, this is what I did: ``` BITMAPINFO info; ZeroMemory(&info, sizeof(BITMAPINFO)); info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); info.bmiHeader.biBitCount = 32; info.bmiHeader.biPlanes = 1; info.bmiHeader.biCompression = BI_RGB; info.bmiHeader.biSizeImage = sourceImage->GetArea()*4; info.bmiHeader.biWidth = sourceImage->GetWidth(); info.bmiHeader.biHeight = sourceImage->GetHeight(); info.bmiHeader.biClrUsed = 0; int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP, 0, sourceImage->GetHeight(), translatedImage, &info, DIB_PAL_COLORS); ``` However, `r` is always zero and, naturally, I get nothing but black in my window. What is wrong with the code?

Original source