Применение Mica в классических приложениях Win32 для Windows 11

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

В этой статье описывается, как применить Mica в качестве базового слоя приложения Win32, чтобы определить приоритеты приложения и видимости в области заголовка. Дополнительные сведения о настройке слоев приложений с помощью Mica см. в разделе Материал Mica.

Необходимые компоненты

Чтобы применить Mica к приложению Win32 для Windows 11, необходимо использовать Windows App SDK. Потребуется следующее:

Использование Mica в приложениях Win32

Чтобы использовать Mica в приложении, используйте класс MicaController. Этот класс управляет отрисовкой материала фона системы, а также обработкой системной политики для материала Mica.

MicaController реагирует на системные светлые и темные темы по умолчанию. Чтобы переопределить это поведение, можно передать в MicaController следующие свойства:

Совет

Код в этом разделе взят из примера Windows App SDK Win32 Mica в GitHub. См. полный код в репозитории GitHub. В этих примерах используется C++/WinRT.

Чтобы включить Mica, вам потребуется ссылка на Windows App SDK, Compositor и DispatcherQueue.

В этом примере показано, как настроить неупакованное приложение:

Из WinMain.cpp

int __stdcall WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE,  _In_ PSTR, _In_ int)
{
    // Initialize WinRt Instance
    winrt::init_apartment();

    // Enable referencing the WindowsAppSDK from an unpackaged app.
    Utilities::WindowsAppSDKBootstrapperContext sdkContext;

    // Register Window class before making the window.
    MicaWindow::RegisterWindowClass();

    // Mica requires a compositor, which also requires a dispatcher queue.
    auto controller = Utilities::CreateDispatcherQueueControllerForCurrentThread();
    auto compositor = winrt::Compositor();

    // Create your window...
    ...
}

Из MicaWindow.cpp

void MicaWindow::RegisterWindowClass()
{
    auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
    WNDCLASSEX wcex = { sizeof(wcex) };
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = instance;
    wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
    wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszClassName = ClassName.c_str();
    wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
    winrt::check_bool(RegisterClassExW(&wcex)); // check if the window class was registered successfully
}

Метод winrt::init_apartment по умолчанию используется с несколькими потоками. Если приложению требуется один поток, например, пример WebView2, можно легко задать тип.

winrt::init_apartment(winrt::apartment_type::single_threaded);

Теперь можно использовать функцию CreateWindowEx() для создания окна. Затем необходимо создать целевой объект окна и задать его в качестве корневого элемента, чтобы указать, к какому слою следует применить Mica. Наконец, убедитесь, что Mica поддерживается окном и целевым объектом.

В примере Win32 Mica создаются классы DesktopWindow и MicaWindow для выполнения этой задачи. Эти классы определяют следующее: ClassName, windowTitle, m_target, m_micaController, и m_isMicaSupported.

Из WinMain.cpp

// Mica window is inherited from the MicaWindow class, which is an extension of the DesktopWindow Class.
// Here, we initialize the main window and set the title.
   auto window = MicaWindow(compositor, L"Hello, Mica!");

Из MicaWindow.cpp

// Create the main window and enable Mica.
MicaWindow::MicaWindow(const winrt::Compositor& compositor, const std::wstring& windowTitle)
{
    auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
    WINRT_ASSERT(!m_window); // check that window is not initialized
    WINRT_VERIFY(
        // Window Properties
        CreateWindowExW(
            WS_EX_COMPOSITED,
            ClassName.c_str(), // declared in MicaWindow.h and defined above
            windowTitle.c_str(),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT, 
            800, 600, 
            nullptr, 
            nullptr, 
            instance, 
            this
        ));

    // Check that the window was created successfully.
    WINRT_ASSERT(m_window);

    ShowWindow(m_window, SW_SHOWDEFAULT);
    UpdateWindow(m_window);

    // The Mica controller needs to set a target with a root to recognize the visual base layer.
    m_target = CreateWindowTarget(compositor);

    // Need to set a root before we can enable Mica.
    m_target.Root(compositor.CreateContainerVisual());

    m_micaController = winrt::MicaController();
    m_isMicaSupported = m_micaController.SetTarget(winrt::Microsoft::UI::WindowId{ reinterpret_cast<uint64_t>(m_window) }, m_target);
}

Использование Mica в приложениях Win32 WebView2

В большинстве приложений Win32 используются согласованные принципы применения Mica. В процессе webView2 выполняются основные шаги из приведенных выше инструкций Win32. Однако в этом случае необходимо указать однопоточный процесс из функции WinRT init_apartment.

Совет

Код в этом разделе взят из примера Windows App SDK WebView2 Mica в GitHub. См. полный код в репозитории GitHub.

Чтобы приступить к работе, настройте необходимое подразделение, контроллер, компоновщик, целевой объект и корневой каталог. По умолчанию функция WinRT init_apartment является многопоточной, однако функция WebView2 изначально является однопоточной. Чтобы задать init_apartment как однопоточную функцию, передайте параметр winrt::apartment_type::single_threaded. В примере Mica WebView2 мы упростим синтаксис, создав отдельный класс для функций веб-представления, на который ссылается следующий код.

Из Main.cpp

int __stdcall WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PSTR, _In_ int)
{
    winrt::init_apartment(winrt::apartment_type::single_threaded);
    // Enable referencing the WindowsAppSDK from an unpackaged app.
    // Remember to have a matching Microsoft.WindowsAppRuntime.Redist installed.
    // https://learn.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps
    Utilities::WindowsAppSDKBootstrapperContext sdkContext;
    CompositionWindow::RegisterWindowClass();
    // A dispatcher queue is required to be able to create a compositor.
    auto controller = Utilities::CreateDispatcherQueueControllerForCurrentThread();
    auto compositor = winrt::Compositor();
    auto window = WebView2Window(compositor, L"Hello, WebView2!");

    ...
}

Полную демонстрацию класса WebView2Window и его интеграцию с Mica см. в примере Windows App SDK WebView2 Mica на GitHub. Обратите внимание, как классы CompositionWindow и WebView2Window обрабатывают сообщения, инициализируют среду веб-представления и удаляют контроллер окна после закрытия окна.

Материалы, уровень и повышение прав, примеры Mica пакета SDK для приложений Windows