Windows API:以屏幕显示方式写入屏幕

Windows API:以屏幕显示方式写入屏幕,windows,winapi,screen,Windows,Winapi,Screen,我正在编写一个(非常)小的应用程序,它一开始只执行一些小的操作,应该在屏幕上写一条类似于屏幕显示的消息:大的字母,没有任何窗口,最重要的是,在一段时间内可见,然后消失 如果可能的话,我不想为它创建一个窗口 正确的方法是什么 (我希望不需要DirectX、direct graphics access等特殊工具包)如评论中所述,您可以直接绘制到屏幕上。提供返回适当的设备上下文: hWnd[in] 要检索其DC的窗口的句柄如果此值为空,则GetDC检索整个屏幕的DC。 直接渲染到屏幕会产生至少两个需要

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

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

正确的方法是什么


(我希望不需要DirectX、direct graphics access等特殊工具包)

如评论中所述,您可以直接绘制到屏幕上。提供返回适当的设备上下文:

hWnd[in]

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

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

  • 屏幕DC是一个共享资源。当其他人呈现到屏幕时(例如,当显示窗口时),屏幕的该部分将被覆盖
  • 渲染是破坏性的。在呈现到设备上下文时,原始内容将被覆盖。要实现淡出效果,您必须保存原始内容(并在显示其他窗口时动态更新)
  • 这两个问题都可以通过创建窗口来解决。窗口不需要有边框、标题栏、系统菜单或最小化/最大化/关闭按钮。相应的是
    WS\u弹出窗口| WS\u可见

    要使窗口显示在所有其他窗口之前,需要将其标记为最顶部(使用
    WS\u EX\u topmest
    )。请注意,这会将窗口放置在Z顺序中所有其他非最上面的窗口之上。你仍然需要与其他最顶级的窗口进行斗争(这是一场你无法赢得的军备竞赛)

    要实现透明,窗口必须具有
    WS_EX_LAYERED
    扩展窗口样式,才能创建透明窗口。然后启用Alpha透明度。要保持窗口背景完全透明,而不考虑窗口的alpha透明度,还需要启用颜色关键帧。一种简单的方法是设置to的
    hbrBackground
    成员,并将
    RGB(0,0,0)
    指定为调用
    SetLayeredWindowAttributes
    中的
    crKey
    参数。
    概念证明(为简洁起见,省略了错误检查):

    这是实例化窗口并调整其属性所需的所有设置代码。启用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 );
    
    wWinMain的其余部分是样板windows应用程序代码

        ::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;
    }
    
    窗口过程执行简单的渲染。为了演示alpha和关键点颜色的透明度,代码渲染了一个白色椭圆,客户区域作为边界矩形。此外,还处理了,以提供使用鼠标或其他定点设备在屏幕上拖动窗口的简单方法。请注意,对于所有完全透明的区域,鼠标输入都会传递到下面的窗口

        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 );
    
    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 );
    }
    

    可选的
    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;
    

    创建一个窗口是正常的方法。窗口可以是透明的,不需要有一个可见的框架等,如果这是让你推迟使用的原因。一个透明的顶级窗口是最好的,但是如果你绝对需要直接在屏幕上写,你可以使用
    GetDC(0)
    来获取屏幕的
    HDC
    画布句柄,然后你可以根据需要画出来。谢谢。我想我会选择窗户的。一般来说,这真的很棒。但是,当我使用
    DrawText
    显示文本时,背景始终为白色,尽管窗口本身是透明的。在
    DrawText
    之前使用
    SetBkMode(hDC,透明)
    时,不会显示任何内容。有解决办法吗?@divB:我想你是用关键颜色(黑色)渲染文本的。关键颜色将替换为窗口下方的任何颜色。文本基本上是完全透明的。我更新了答案,改为包含代码呈现文本。@IInspectable,如果不设置“颜色键控”,是否可以达到相同的效果?如果我想使用所有颜色(因此我不能使用任何颜色作为“透明颜色”),该怎么办?当我在绘图时可以指定alpha通道值时,是否可以对其进行配置(这样我可以绘制所需的形状,然后用带有alpha chnanel的“画笔”填充窗口的其余部分?或者指定默认情况下窗口由透明颜色填充,然后在其顶部绘制形状?)
        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;