Aplicación de Mica en aplicaciones de escritorio en Win32 para Windows 11

Mica es un material opaco que incorpora el tema del usuario y el fondo de pantalla de escritorio para crear una apariencia altamente personalizada. A medida que el usuario mueve la ventana a través de la pantalla, el material de Mica se adapta dinámicamente para crear una visualización enriquecida mediante el fondo de pantalla debajo de la aplicación. Además, el material ayuda a los usuarios a centrarse en la tarea actual volviendo a un color neutro cuando la aplicación está inactiva.

En este artículo se describe cómo aplicar Mica como la capa base de la aplicación Win32, priorizando la aplicación y la visibilidad en el área de la barra de título. Para obtener más información sobre la capa de aplicaciones con Mica, consulte material de Mica.

Prerrequisitos

Para aplicar Mica a una aplicación Win32 para Windows 11 debe usar el SDK para aplicaciones de Windows. Necesitará lo siguiente:

Uso de Mica en aplicaciones Win32

Para usar Mica en la aplicación, use la clase MicaController. Esta clase administra tanto la representación del material de fondo del sistema como el manejo de la directiva del sistema para el material Mica.

MicaController reacciona a los temas Claro y Oscuro del sistema de forma predeterminada. Para invalidar este comportamiento, puede pasar las siguientes propiedades a MicaController:

Sugerencia

El código de esta sección se toma del ejemplo de Mica de SDK para aplicaciones de Windows Win32 en GitHub. Consulte el repositorio GitHub para obtener el código completo. En estos ejemplos se usa C++/WinRT.

Para habilitar Mica, necesita una referencia a la SDK para aplicaciones de Windows, un Compositor y un DispatcherQueue.

En este ejemplo se muestra cómo hacer lo siguiente para configurar una aplicación sin empaquetar:

Desde 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...
    ...
}

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

El método winrt::init_apartment es multiproceso de forma predeterminada. Si la aplicación requiere un único subproceso, como el ejemplo webView2, puede establecer el tipo fácilmente.

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

Ahora puede usar la función CreateWindowEx() para crear una ventana. A continuación, debe crear un destino de ventana y establecerlo como raíz para especificar a qué capa se va a aplicar Mica. Por último, confirme que Mica es soportado por la ventana y el destino.

El ejemplo Mica Win32 crea las clases DesktopWindow y MicaWindow para realizar este trabajo. Estas clases definen: ClassName, windowTitle, m_target, m_micaController y m_isMicaSupported.

Desde 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!");

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

Uso de Mica en aplicaciones WebView2 de Win32

Los principios fundamentales de la aplicación de Mica son coherentes en la mayoría de las aplicaciones Win32. El proceso de WebView2 sigue los pasos básicos de las instrucciones de Win32 mostradas anteriormente. Sin embargo, en este caso tendrás que especificar un único subproceso de la característica init_apartment de WinRT.

Sugerencia

El código de esta sección se toma del ejemplo de Mica WebView2 de SDK para aplicaciones de Windows en GitHub. Consulte el repositorio GitHub para obtener el código completo.

Para empezar, configure el apartamento, el controlador, el compositor, el destino y la raíz necesarios. De forma predeterminada, la función init_apartment de WinRT es multiproceso, pero WebView2 es intrínsecamente de un solo subproceso. Para establecer init_apartment como un único subproceso, pase el parámetro winrt::apartment_type::single_threaded. En el ejemplo de Mica WebView2, simplificamos la sintaxis mediante la creación de una clase independiente para las funciones de vista web, a las que se hace referencia en el código siguiente.

Desde 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!");

    ...
}

Para obtener una demostración completa de la clase WebView2Window y su integración con Mica, consulte el ejemplo de Mica WebView2 de SDK para aplicaciones de Windows en GitHub. Observe cómo las clases CompositionWindow y WebView2Window manejan los mensajes, inicializan el entorno de vista web y eliminan el controlador de ventana una vez se cierra la ventana.

Materiales, Capas y Elevación, Ejemplos de Mica de SDK para aplicaciones de Windows