2015-03-17 2 views
1

Я пишу (очень) небольшое приложение, которое просто запускает некоторые незначительные вещи при запуске и должно написать сообщение на экране, аналогичное экрану: большие буквы , без какого-либо окна, над всем, видимым на какое-то мгновение, а затем исчезающим.Windows API: запись на экран как на экране дисплея

Если возможно, я не хочу создавать для него окно.

Каков правильный способ сделать это?

(я надеюсь, что нет никаких специальных инструментальных средств, как DirectX, прямые графики доступа и т.д. требуется)

+3

Создание окна было бы нормальным способом для этого. Windows может быть прозрачной и не обязательно иметь видимый фрейм и т. Д., Если это то, что вас отталкивает от использования. –

+2

Прозрачное окно верхнего уровня лучше всего, но если вам абсолютно необходимо писать на экране напрямую, вы можете использовать 'GetDC (0)', чтобы получить дескриптор холста 'HDC' для экрана, а затем вы можете нарисовать его по мере необходимости. –

+0

Спасибо. Думаю, я пойду за окном – divB

ответ

6

Как было отмечено в комментариях, вы можете рисовать прямо на экране. GetDC предложения вернуть соответствующий контекст устройства:

HWND [в]

Дескриптор окна которого DC должен быть восстановлен. Если это значение равно NULL, GetDC получает DC для всего экрана.

Rendering непосредственно на экран создает по меньшей мере, две проблемы, которые необходимо решить:

  1. Экран DC является общим ресурсом. Всякий раз, когда кто-то другой отображается на экране (например, когда отображается окно), эта часть экрана перезаписывается.
  2. Рендеринг является разрушительным. При рендеринге в контексте устройства исходное содержимое перезаписывается. Чтобы реализовать эффект постепенного исчезновения, вам нужно будет сохранить исходное содержимое (и динамически обновлять его, когда отображаются другие окна).

Обе проблемы могут быть решены путем создания окна вместо этого. Окно не требуется для того, чтобы иметь границу, заголовок, системное меню или кнопки минимизации/максимизации/закрытия. Соответствующими Window Styles являются WS_POPUP | WS_VISIBLE.

Чтобы окно выглядело перед всем остальным, оно должно быть помечено как самое верхнее (с использованием WS_EX_TOPMOSTExtended Window Style). Обратите внимание, что это помещает окно выше всех других не самых верхних окон в Z-порядке. Вам все равно придется сражаться с другими самыми верхними окнами (гонка вооружений, которую вы не можете выиграть).

Для обеспечения прозрачности окно должно иметь расширенный стиль окна WS_EX_LAYERED, а также для создания Layered Window. Затем активируется альфа-прозрачность, вызывающая SetLayeredWindowAttributes. Чтобы фон окна полностью прозрачный, независимо от прозрачности окна, вам также необходимо включить цветную клавиатуру. Простой способ сделать это - установить hbrBackground член WNDCLASSEX structure на (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) { 

Сначала регистрируется главный класс окна приложения. Важным элементом является член 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); 

Это код установки, необходимый для создания экземпляра окна и настройки его атрибутов. Альфа-прозрачность позволяет подготовиться к эффекту затухания, а цветовая гамма маскирует те области окна, которые не отображаются.

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

Процедура окна выполняет простой рендеринг. Чтобы продемонстрировать прозрачность альфа-и ключевого цвета, код отображает белый эллипс с клиентской областью в качестве ограничивающего прямоугольника. Кроме того, обрабатывается WM_NCHITTEST message, чтобы обеспечить простой способ перетаскивать окно по экрану с помощью мыши или другого указывающего устройства. Обратите внимание, что вход мыши передается в окно внизу для всех областей, которые полностью прозрачны.

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; 
+0

Вообще это работает очень здорово. Однако, когда я показываю текст с помощью DrawText, фон всегда белый, несмотря на то, что само окно прозрачно. Когда я использую 'SetBkMode (hDC, TRANSPARENT)' перед 'DrawText', ничего не отображается. Есть ли исправление для этого? – divB

+1

@divB: Я предполагаю, что вы предоставили свой текст, используя цвет ключа (черный). Цвет ключа будет заменен тем, что находится под окном. Текст будет казаться полностью прозрачным. Я обновил ответ, чтобы вместо этого включить текст рендеринга кода. – IInspectable

+0

@Инспективный, возможно ли достичь того же эффекта, но без настроек «цветная настройка»? Что делать, если я хочу использовать все цвета (таким образом, я не могу использовать какой-либо цвет как «цвет прозрачности»)? Можно ли настроить его таким образом, когда я могу указать значение альфа-канала при рисовании чего-либо (чтобы я мог нарисовать нужную мне форму, а затем заполнить остальную часть окна «кистью», которая имеет альфа-последовательность или укажите, что окно заполнено прозрачным цветом по умолчанию, а затем нарисует форму поверх него?) – ScienceSE

Смежные вопросы