Search code examples
windowswinapiwidgetwindows-runtimec++-winrt

Which Windows API can be used to make transparent text on top of the screen?


I'd like to display text at the bottom right corner of a Windows computer (the Task Bar is hidden). I'd like the text to be visible but no background.

What is the correct Windows API to do this with?

The approach I've thought of is to make a regular Window and make its background transparent, and make it always on top of other windows. I'd ideally not want the window to block clicks, but rather have the click and mouse events go to the window underneath.

Is there a better API to do this with?


Solution

  • How to display the transparent window on desktop and not block clicks?(you can set position to display at the bottom right corner )

    Use CreateWindowEx with WS_EX_TRANSPARENT and WS_EX_LAYERED. And use UpdateLayeredWindow to set the transparency of the window. WS_EX_TRANSPARENT will allow you to mouse penetration.

    But there's a problem. When using Textout or Drawtext to output text, the transparency of the text is the same as that of the window. This means that when the window is fully transparent, neither the text nor the window is visible. So we need to use gdiplus to set the transparency of the window and the text separately.

    The Graphics::Clear method clears a Graphics object (background) to a specified color. SourceConstantAlpha (text)of struct BLENDFUNCTION can specifies an alpha transparency value to be used on the entire source bitmap.

    This is full code, it is based on this thread:

    #include <Windows.h>
    #include <stdio.h>
    #include <iostream>
    #include <ObjIdl.h>
    #include <gdiplus.h>
    #include <gdiplusheaders.h>
    using namespace Gdiplus;
    #pragma comment (lib,"Gdiplus.lib")
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
    {
        const wchar_t CLASS_NAME[] = L"Sample Window Class";
        WNDCLASS wc = { };
    
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.lpszClassName = CLASS_NAME;
        RegisterClass(&wc);
    
        GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR gdiplusToken;
        HDC hdc{};
        //Initialize GDI+
        GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
        HWND hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, CLASS_NAME, NULL, WS_POPUP,
            0, 0, 1000, 600, NULL, NULL, hInstance, NULL);
    
        FontFamily  fontFamily(L"Times New Roman");
        Font        font(&fontFamily, 32, FontStyleRegular, UnitPixel);
        PointF      pointF(30.0f, 10.0f);
        SolidBrush  solidBrush(Color(255, 0, 0, 0));
    
        Bitmap softwareBitmap(800, 600, PixelFormat32bppARGB);
        Graphics g(&softwareBitmap);
    
        g.Clear(Gdiplus::Color(30, 0, 0, 0));  // 30: alpha value 
        g.DrawString(L"Hello Hello Hello Hello Hello Hello Hello Hello", -1, &font, pointF, &solidBrush);
    
        HBITMAP bmp;
        softwareBitmap.GetHBITMAP(Color(0, 0, 0, 0), &bmp);
        HDC memdc = CreateCompatibleDC(hdc);
        HGDIOBJ original = SelectObject(memdc, bmp);
    
        BLENDFUNCTION blend = { 0 };
        blend.BlendOp = AC_SRC_OVER;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat = AC_SRC_ALPHA;
        POINT ptLocation = { 550, 300 };
        SIZE szWnd = { 800, 600 };
        POINT ptSrc = { 0, 0 };
        UpdateLayeredWindow(hWnd, hdc, &ptLocation, &szWnd, memdc, &ptSrc, 0, &blend, ULW_ALPHA);
        SelectObject(hdc, original);
    
        DeleteObject(bmp);
        DeleteObject(memdc);
        if (hWnd == NULL)
        {
            return 0;
        }
        ShowWindow(hWnd, nCmdShow);
        MSG msg = { };
        while (GetMessage(&msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return 0;
    }
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    

    Let's see the effect: enter image description here

    enter image description here

    enter image description here