4
votes

(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

1
The UpdateLayeredWindow call after TextOut will instantly erase the text. It really is rather important that you only draw in the WM_PAINT message handler. I can't see the reason you are bypassing this.Hans Passant
In addition to what Hans said, TextOut is a GDI function, not GDI+, and knows nothing about transparency. So it would create text blended with the DC background color, not whatever is supposed to show through.Ben Voigt
so I'm supposed to use DrawString? I've been avoiding it since I'm having major problems with it. I'm bypassing the WM_PAINT message because i'm using a gameloop to render stuff. I don't think i can put the draw loop inside WM_PAINT nowBNelsey
updated my code, now i'm now aiming lower and just trying to draw text on the bitmap before i get an HBITMAP from it, but for some reason the changes aren't applying to the bitmap so only the original image is applied to the layered window and is displayed :/BNelsey
I forgot to mention that WM_PAINT is completely disabled when using layered windows ^^BNelsey

1 Answers

3
votes

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.