Windows API:在屏幕显示上写入屏幕

div*_*ivB 1 windows winapi screen

我正在写一个(非常)小的应用程序,它只是在开始时执行一些小的操作,应该在屏幕上写一条消息,类似于屏幕显示:大字母,没有任何窗口,高于一切,可见一段时间和然后逐渐消失.

如果可能的话我不想为它创建一个窗口.

这样做的正确方法是什么?

(我希望没有像DirectX这样的特殊工具包,需要直接图形访问等)

IIn*_*ble 9

正如评论中指出的那样,您可以直接绘制到屏幕上.GetDC提供返回适当的设备上下文:

hWnd [in]

要检索其DC的窗口的句柄.如果此值为NULL,则GetDC将检索整个屏幕的DC.

直接渲染到屏幕会产生至少两个需要解决的问题:

  1. 屏幕DC是共享资源.每当其他人渲染到屏幕上时(例如,当显示窗口时),屏幕的该部分被覆盖.
  2. 渲染具有破坏性.渲染到设备上下文时,原始内容会被覆盖.要实现淡出效果,您必须保存原始内容(并在显示其他窗口时动态更新它们).

这两个问题都可以通过创建一个窗口来解决.窗口不需要具有边框,标题栏,系统菜单或最小化/最大化/关闭按钮.适当的窗口样式WS_POPUP | WS_VISIBLE.

要使窗口显示在其他所有内容之前,需要将其标记为最顶层(使用WS_EX_TOPMOST 扩展窗口样式).请注意,这会将窗口置于Z顺序中所有其他非最顶层窗口的上方.你仍然需要与其他最顶级的窗户战斗(你无法赢得的军备竞赛).

要实现透明度,窗口必须具有WS_EX_LAYERED扩展窗口样式以创建分层窗口.然后调用SetLayeredWindowAttributes启用Alpha透明度.为了使窗口背景完全透明,无论窗口的Alpha透明度如何,您还需要启用颜色键控.一种简单的方法是hbrBackgroundWNDCLASSEX结构的成员设置为(HBRUSH)GetStockObject(BLACK_BRUSH),并在调用中指定RGB(0, 0, 0)crKey参数SetLayeredWindowAttributes.


概念证明(错误检查简称为简洁):

#define STRICT 1
#define WIN32_LEAN_AND_MEAN
#include <SDKDDKVer.h>
#include <windows.h>

// Forward declarations
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );

// Entry point
int APIENTRY wWinMain( HINSTANCE hInstance,
                       HINSTANCE /*hPrevInstance*/,
                       LPTSTR    /*lpCmdLine*/,
                       int       nCmdShow ) {
Run Code Online (Sandbox Code Playgroud)

首先是注册主应用程序窗口类.重要的是hbrBackground会员.它控制背景渲染,最终将完全透明.

    const wchar_t k_WndClassName[] = L"OverlayWindowClass";

    // Register window class
    WNDCLASSEXW wcex = { 0 };
    wcex.cbSize = sizeof( wcex );
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.hInstance      = hInstance;
    wcex.hCursor        = ::LoadCursorW( NULL, IDC_ARROW );
    wcex.hbrBackground  = (HBRUSH)::GetStockObject( BLACK_BRUSH );
    wcex.lpszClassName  = k_WndClassName;
    ::RegisterClassExW( &wcex );
Run Code Online (Sandbox Code Playgroud)

这是实例化窗口所需的所有设置代码,并调整其属性.启用Alpha透明度以准备淡出效果,而颜色键控屏蔽窗口中未渲染的那些区域.

    HWND hWnd = ::CreateWindowExW( WS_EX_TOPMOST | WS_EX_LAYERED,
                                   k_WndClassName,
                                   L"Overlay Window",
                                   WS_POPUP | WS_VISIBLE,
                                   CW_USEDEFAULT, CW_USEDEFAULT,
                                   800, 600,
                                   NULL, NULL,
                                   hInstance,
                                   NULL );
    // Make window semi-transparent, and mask out background color
    ::SetLayeredWindowAttributes( hWnd, RGB( 0, 0, 0 ), 128, LWA_ALPHA | LWA_COLORKEY );
Run Code Online (Sandbox Code Playgroud)

其余部分wWinMain是样板窗口应用程序代码.

    ::ShowWindow( hWnd, nCmdShow );
    ::UpdateWindow( hWnd );

    // Main message loop:
    MSG msg = { 0 };
    while ( ::GetMessageW( &msg, NULL, 0, 0 ) > 0 )
    {
        ::TranslateMessage( &msg );
        ::DispatchMessageW( &msg );
    }

    return (int)msg.wParam;
}
Run Code Online (Sandbox Code Playgroud)

窗口过程执行简单渲染.为了演示alpha和键颜色透明度,代码呈现一个白色椭圆,客户区域为边界矩形.此外,还处理WM_NCHITTEST消息,以提供使用鼠标或其他指示设备在屏幕上拖动窗口的简单方法.请注意,鼠标输入将传递到下面的窗口,以用于完全透明的所有区域.

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch ( message )
    {
    case WM_PAINT:
        {
            PAINTSTRUCT ps = { 0 };
            HDC hDC = ::BeginPaint( hWnd, &ps );
            RECT rc = { 0 };
            ::GetClientRect( hWnd, &rc );
            HBRUSH hbrOld = (HBRUSH)::SelectObject( hDC,
                                                    ::GetStockObject( WHITE_BRUSH ) );
            ::Ellipse( hDC, rc.left, rc.top, rc.right, rc.bottom );
            ::SelectObject( hDC, hbrOld );
            ::EndPaint( hWnd, &ps );
        }
        return 0;

    case WM_NCHITTEST:
        return HTCAPTION;

    case WM_DESTROY:
        ::PostQuitMessage( 0 );
        return 0;

    default:
        break;
    }
    return ::DefWindowProc( hWnd, message, wParam, lParam );
}
Run Code Online (Sandbox Code Playgroud)


替代WM_PAINT处理程序,输出文本.使用与键颜色不同的文本颜色非常重要.如果要使用黑色文本,则必须使用不同的键颜色.

    case WM_PAINT:
        {
            PAINTSTRUCT ps = { 0 };
            HDC hDC = ::BeginPaint( hWnd, &ps );
            RECT rc = { 0 };
            ::GetClientRect( hWnd, &rc );
            ::SetTextColor( hDC, RGB( 255, 255, 255 ) );
            ::SetBkMode( hDC, TRANSPARENT );
            ::DrawTextExW( hDC, L"Hello, World!", -1, &rc,
                           DT_SINGLELINE | DT_CENTER | DT_VCENTER, NULL );
            ::EndPaint( hWnd, &ps );
        }
        return 0;
Run Code Online (Sandbox Code Playgroud)