C++ GDI+ drawing text on a transparent layered window

BNelsey picture BNelsey · Jan 24, 2011 · Viewed 10.5k times · Source

(unmanaged C++) I already succeeded drawing PNG files to a transparent layered window that I can drag around the desktop, but now my problem is drawing text on a transparent layered window

Here's my code and my attempt at drawing text in the middle, it's important to note that i'm using the screenDC instead of using the one in WM_PAINT messages

[edit] updated code after the comments, now i'm just trying to write text on the bitmap before getting the HBITMAP version which i need to use this time I'm using DrawString because textout() isn't GDI+, I hope DrawString really is GDI+ lol still doesn't work though, wonder what i'm doing wrong

void Draw() // draws a frame on the layered window AND moves it based on x and y
{
    HDC screenDC( NULL ); // grab screen
    HDC sourceDC( CreateCompatibleDC(screenDC) );

    POINT pos = {x,y}; // drawing location
    POINT sourcePos = {0,0}; // top left of image
    SIZE size = {100,100}; // 100x100 image

    BLENDFUNCTION blendFunction = {0};
    HBITMAP bufferBitmap = {0};
    Bitmap* TheBitmap = crnimage; // crnimage was already loaded earlier

    // ------------important part goes here, my attempt at drawing text ------------//

 Gdiplus::Graphics     Gx(TheBitmap);

// Font* myFont =    new Font(sourceDC);
 Font myFont(L"Arial", 16);


 RectF therect;
 therect.Height = 20;
 therect.Width = 180;
 therect.X = 0;
 therect.Y = 0;

 StringFormat format;
 format.SetAlignment(StringAlignmentCenter);
 format.GenericDefault();
 Gdiplus::SolidBrush   GxTextBrush(Gdiplus::Color(255, 255, 0,255));


 WCHAR thetext[] = L"Sample Text";

 int stats = Gx.DrawString(thetext, -1, &myFont, therect, &format, &GxTextBrush);
 if(stats) // DrawString returns nonzero if there is an error
     msgbox(stats); 
 stats = Gx.DrawRectangle(&Pen(Color::Red, 3), therect);
 // the rectangle and text both draw fine now

 // ------------important part goes here, my attempt at drawing text ------------//

    TheBitmap->GetHBITMAP(0, &bufferBitmap);
    HBITMAP oldBmpSelInDC;
    oldBmpSelInDC = (HBITMAP)SelectObject(sourceDC, bufferBitmap);

    // some alpha blending
    blendFunction.BlendOp = AC_SRC_OVER;
    blendFunction.SourceConstantAlpha = wndalpha;
    blendFunction.AlphaFormat = AC_SRC_ALPHA;
    COLORREF colorKey( RGB(255,0,255) );
    DWORD flags( ULW_ALPHA);

    UpdateLayeredWindow(hWnd, screenDC, &pos, & size, sourceDC, &sourcePos,
    colorKey, &blendFunction, flags);

    // release buffered image from memory
    SelectObject(sourceDC, oldBmpSelInDC);
    DeleteDC(sourceDC);
    DeleteObject(bufferBitmap); 

    // finally release the screen
    ReleaseDC(0, screenDC);
}

I've been trying to write text on my layered window for two days now, but from those attempts I know there are several ways I can go about doing this (unfortunately I have no idea how exactly)

The usual option I see is drawing text on a bitmap, then rendering the bitmap itself

  1. Use Gdi+ to load a bitmap
  2. Create a Graphics object from the bitmap
  3. Use DrawString to write text to the bitmap
  4. Dispose of the Graphics object
  5. Use the bitmap Save method to save the result to a file

Apparently one can also make a graphics object from a DC, then draw text on the DC, but again i have no clue as to how to do this

Answer

Adrian McCarthy picture Adrian McCarthy · Jan 25, 2011

The overall approach looks right, but I think you've got some problems with the DrawString call. Check out the documentation (especially the sample) on MSDN.

Gx.DrawString(thetext, 4, NULL, therect, NULL,  NULL)

The third, fifth, and sixth parameters (font, format, and brush) probably need to be specified. The documentation doesn't say that they are optional. Passing NULL for these is probably causing GDI+ to treat the call as a no-op.

The second parameter should not include the terminating L'\0' in the string. It's probably safest to use -1 if your string is always terminated.