我正在写一个(非常)小的应用程序,它在开始时只执行一些小的事情,并且应该在屏幕上写一个类似于屏幕显示的消息:大的字母,没有任何窗口,高于一切,然后消失。
如果可能的话,我不想为它创build一个窗口。
什么是正确的方法来做到这一点?
(我希望没有像DirectX这样的特殊工具包,需要直接graphics访问等)
正如在评论中指出的那样,你可以直接画到屏幕上。 GetDC提供返回适当的设备上下文:
hWnd [in]
要检索DC的窗口的句柄。 如果此值为NULL,则GetDC将检索整个屏幕的DC。
直接渲染到屏幕上至少需要解决两个问题:
这两个问题都可以通过创建一个窗口来解决。 窗口不需要有边框,标题栏,系统菜单或最小化/最大化/关闭按钮。 适当的窗口样式是WS_POPUP | WS_VISIBLE
WS_POPUP | WS_VISIBLE
。
为了使窗口显示在其他所有窗口之前,需要将其标记为最上方(使用WS_EX_TOPMOST
扩展窗口样式 )。 请注意,这将窗口放置在Z顺序的所有其他非最顶层窗口之上。 你仍然必须与其他最高层的窗口进行斗争(你不能赢得军备竞赛)。
要实现透明度,窗口必须具有WS_EX_LAYERED
扩展窗口样式以创建分层窗口 。 Alpha透明度然后启用调用SetLayeredWindowAttributes 。 为了保持窗口背景完全透明,无论窗口的透明度如何,您还需要启用颜色键控。 一个简单的方法是将WNDCLASSEX结构的hbrBackground
成员设置为(HBRUSH)GetStockObject(BLACK_BRUSH)
,并在调用SetLayeredWindowAttributes
指定RGB(0, 0, 0)
作为crKey
参数。
概念证明(错误检查简化):
#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 ) {
首先是注册主应用程序窗口类。 重要的作品是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 );
这是实例化窗口所需的所有设置代码,并调整其属性。 启用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
的其余部分是样板窗口应用程序代码。
::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和关键颜色透明度,代码呈现一个白色椭圆,客户区域作为边界矩形。 另外,还处理了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 ); }
替代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;