Использование Mica в настольных приложениях Win32 для Windows 11

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

Совет

Мика Alt является вариантом Mica с более сильным тонированием цвета фона рабочего стола, полезным для приложений с вкладкой заголовка. Чтобы использовать Mica Alt, задайте для MicaController.Kind значение MicaKind.BaseAlt (тот же элемент управления, который используется во всей этой статье). Дополнительные сведения см. в статье Применение материалов Mica и Acrylic в настольных приложениях. Рекомендации по проектированию см. в материале 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.

Чтобы начать, настройте необходимые apartment, controller, compositor, target и root. По умолчанию функция 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 в Windows App SDK