5
votes

I'm drawing text into a DIB section off-screen bitmap, which is 32bit deep and uses the alpha channel (ARGB). I draw pixels directly to memory. Then, I create a Gdiplus Graphics object, pass my memory DC to it, and draw text using Graphics::DrawString. This works fine under normal circumstances. Over Remote Desktop, however, the text rendered is completely transparent, i.e. instead of drawing any colour pixels, you can see through where the text is. Does anyone know why this is so, and how to fix it??

Here's my drawString routine:

void SplashScreen::drawString (MyString &ivText, Gdiplus::RectF &r, 
  Gdiplus::ARGB c, Gdiplus::StringAlignment align, Gdiplus::Font &fnt,
  Gdiplus::Graphics &gfx)
  {
  Gdiplus::StringFormat fmt;
  fmt.SetAlignment (align);
  Gdiplus::SolidBrush brush (c);
  wchar_t *wstr = new wchar_t [ivText.length()+1];
  std::mbstowcs (wstr, ivText.cstr(), ivText.length()+1);
  gfx.DrawString (wstr, ivText.length(), &fnt, r, &fmt, &brush);
  delete wstr;
  }

And that's how I create the DIB:

BITMAPV5HEADER bhd;
memset (&bhd, 0, sizeof (bhd));
bhd.bV5Size = sizeof (BITMAPV5HEADER);
bhd.bV5Width = nWidth;
bhd.bV5Height = -nHeight;  // negative height indicates top-down DIB
bhd.bV5Planes = 1;
bhd.bV5BitCount = 32;
bhd.bV5Compression = BI_BITFIELDS;
bhd.bV5RedMask   = 0x00FF0000;
bhd.bV5GreenMask = 0x0000FF00;
bhd.bV5BlueMask  = 0x000000FF;
bhd.bV5AlphaMask = 0xFF000000; 
m_pBuf = NULL;
m_hBmp = ::CreateDIBSection (m_hDC, (BITMAPINFO *) &bhd, DIB_RGB_COLORS,
   (void **) &m_pBuf, NULL, 0);
if (m_hBmp == NULL || m_pBuf == NULL)
   {
   // error...
   }
HGDIOBJ oldObj = ::SelectObject (m_hDC, m_hBmp);
if (oldObj == NULL)
   {
   // error...
   }

After drawing text into the DIB, I do

gfx.Flush (Gdiplus::FlushIntentionSync);

EDIT: It may also be of interest to you that the window where the DIB is finally drawn into is a WS_EX_LAYERED window. It's a splash screen that shows when the application starts, and is slowly faded in and out using a timer and the following method:

void SplashScreen::setWindowTransparency (int nAlpha)
  // @param nAlpha: 255 is opaque, 0 is fully transparent.
  {
  HWND hwnd = getHwnd();
  BLENDFUNCTION blend;
  blend.BlendOp = AC_SRC_OVER;
  blend.BlendFlags = 0;
  blend.SourceConstantAlpha = nAlpha;
  blend.AlphaFormat = AC_SRC_ALPHA;
  BOOL bResult = ::UpdateLayeredWindow (hwnd, NULL, NULL, NULL, NULL,
     NULL, RGB (0, 0, 0), &blend, ULW_ALPHA);
  }
2
What happens when you change the colour depth setting of the RDP session?Lightness Races in Orbit
I've tested 15bit, 16bit, 24bit, 32bit (setting in Display tab before RDP session is started). The same problem with all these settings. (Actually, 32bit does not look 32bit to me. Maybe RDP is cheating?)digory doo
How about disabling Persistent Bitmap Caching?Lightness Races in Orbit
I tried disabling it, but the problem persists. I also tried setting my real display depth (not RDP) to 16bit and running the application natively - here everything works fine.digory doo
Okay thanks for trying those things.Lightness Races in Orbit

2 Answers

4
votes

I'm surprised this ever works. Drawing with gdi32 loses alpha information, and as I understand it any drawing on a 32-bit DIB with gdi32 leaves the alpha information in the DIB undefined. GDI+ has to go through gdi32 in this case because you gave it an HDC.

To draw to an RGBA DIB using GDI+, you need to create a GDI+ Bitmap object backed by your DIB's memory with the correct pixel format (using a constructor that takes a pixel data pointer, such as this one), then create a Graphics object from your Bitmap. This allows GDI+ to draw directly to the DIB's memory and handle the alpha channel correctly rather than go through gdi32.

Of course, if you don't need per-pixel alpha, you can simplify things by using an AlphaFormat of 0 in your blend function to ignore the alpha channel in your DIB.

0
votes

I have a possible solution for you. Not sure which version of Windows you are connecting to, but on the remote computer you may have to enable 32-bit color mode for terminal services. Otherwise your client may be limited to 16-bit mode.

On the server, using gpedit.msc, configure the "Limit maximum color depth" option to 32 bit. In Windows 2008/2012 this is in Administrative Templates - Windows Components - Remote Desktop Services - Remote Session Environment.

If you are connecting to Windows XP/Vista/7/8 computer, I am not sure if this gpedit setting is available.