Exibir objetos da interface do usuário do WinRT que dependem do CoreWindow

Determinados seletores, pop-ups, caixas de diálogo e outros objetos do WinRT (Windows Runtime) dependem de um CoreWindow, normalmente, para exibir uma interface do usuário. Embora não haja suporte para CoreWindow em aplicativos da área de trabalho (veja Classes Core sem suporte), ainda é possível usar muitas dessas classes do WinRT nesses aplicativos adicionando algum código de interoperação.

Seu aplicativo de área de trabalho pode ser WinUI 3, Windows Presentation Foundation (WPF) ou Windows Forms (WinForms). Exemplos de código são apresentados em C# e C++/WinRT.

Definir o identificador de janela do proprietário (HWND) para um objeto de interface do usuário do WinRT

Para classes que implementam a interface IInitializeWithWindow (ou a IDataTransferManagerInterop equivalente), você pode usar essa interface para definir uma janela de proprietário no objeto antes de exibi-lo. É um processo de duas etapas.

  1. Decida qual janela será o proprietário do objeto de interface do usuário que você deseja exibir e recupere o HWND dessa janela. Para obter mais detalhes e exemplos de código para esta etapa, consulte Recuperar um identificador de janela (HWND).
  2. Em seguida, chame a API de interoperabilidade apropriada (para C# ou C++/WinRT) para definir um identificador de janela do proprietário (HWND) para o objeto da interface do usuário do WinRT.

Para classes que implementam IInitializeWithWindow

Essas classes implementam IInitializeWithWindow:

Observação

A lista acima está necessariamente incompleta — consulte a documentação de um tipo para ver se ele implementa IInitializeWithWindow (ou uma interface de interoperabilidade equivalente).

As próximas seções contêm exemplos de código para exibir um FolderPicker. Mas é a mesma técnica para exibir qualquer uma das APIs listadas acima.

WinUI 3 com C# (também WPF/WinForms com .NET 6 ou posterior)

Observação

Os exemplos de código nesta seção usam a classe de interoperabilidade C# WinRT.Interop.WindowNative. Se direcionar o .NET 6 ou posterior, você poderá usar essa classe em um projeto WPF ou WinForms. Para obter informações sobre como configurar seu projeto para fazer isso, consulte Chamar APIs de interoperabilidade de um aplicativo .NET.

O código C# abaixo espera que você já tenha usado o padrão documentado em Recuperar um identificador de janela (HWND). Em seguida, para definir a janela do proprietário para o objeto de interface do usuário que você deseja exibir, o código chama o método Initialize na classe de interoperabilidade C# WinRT.Interop.InitializeWithWindow. Para obter mais informações sobre as classes de interoperabilidade C#, consulte Chame APIs de interoperabilidade de um aplicativo .NET.

// MainWindow.xaml.cs
private async void ShowFolderPickerAsync(IntPtr hWnd)
{
    // Create a folder picker.
    var folderPicker = new Windows.Storage.Pickers.FolderPicker();

    // Initialize the folder picker with the window handle (HWND).
    WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hWnd);

    // Use the folder picker as usual.
    folderPicker.FileTypeFilter.Add("*");
    var folder = await folderPicker.PickSingleFolderAsync();
}

WinUI 3 com C++

O código C++/WinRT abaixo supõe que você já tenha usado o padrão documentado em Recuperar um identificador de janela (HWND). Em seguida, para definir a janela do proprietário para o objeto de interface do usuário que você deseja exibir, o código chama o método de interoperabilidade IInitializeWithWindow::Initialize.

// pch.h
...
#include <microsoft.ui.xaml.window.h>
#include <Shobjidl.h>
#include <winrt/Windows.Storage.Pickers.h>

// MainWindow.xaml.cpp
winrt::fire_and_forget ShowFolderPickerAsync(HWND hWnd)
{
    // Create a folder picker.
    Windows::Storage::Pickers::FolderPicker folderPicker;

    // Initialize the folder picker with the window handle (HWND).
    auto initializeWithWindow{ folderPicker.as<::IInitializeWithWindow>() };
    initializeWithWindow->Initialize(hWnd);

    // Use the folder picker as usual.
    folderPicker.FileTypeFilter().Append(L"*");
    auto folder{ co_await folderPicker.PickSingleFolderAsync() };
}

Para classes que implementam IDataTransferManagerInterop

A classe Windows.ApplicationModel.DataTransfer.DataTransferManager implementa a interface IDataTransferManagerInterop (que, assim como IInitializeWithWindow, permite que você defina uma janela de proprietário).

Em um aplicativo de área de trabalho, em vez de chamar o método DataTransferManager.ShowShareUI, você chama IDataTransferManagerInterop::ShowShareUIForWindow, conforme mostrado nos exemplos de código abaixo.

WinUI 3 com C# (também WPF/WinForms com .NET 6 ou posterior)

// MainWindow.xaml.cs
...
public sealed partial class MainWindow : Window
{
    ...

    [System.Runtime.InteropServices.ComImport]
    [System.Runtime.InteropServices.Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")]
    [System.Runtime.InteropServices.InterfaceType(
        System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
    interface IDataTransferManagerInterop
    {
        IntPtr GetForWindow([System.Runtime.InteropServices.In] IntPtr appWindow,
            [System.Runtime.InteropServices.In] ref Guid riid);
        void ShowShareUIForWindow(IntPtr appWindow);
    }

    static readonly Guid _dtm_iid = 
        new Guid(0xa5caee9b, 0x8708, 0x49d1, 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c);

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
        // Retrieve the window handle (HWND) of the current WinUI 3 window.
        var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

        IDataTransferManagerInterop interop =
        Windows.ApplicationModel.DataTransfer.DataTransferManager.As
            <IDataTransferManagerInterop>();

        IntPtr result = interop.GetForWindow(hWnd, _dtm_iid);
        var dataTransferManager = WinRT.MarshalInterface
            <Windows.ApplicationModel.DataTransfer.DataTransferManager>.FromAbi(result);

        dataTransferManager.DataRequested += (sender, args) =>
        {
            args.Request.Data.Properties.Title = "In a desktop app...";
            args.Request.Data.SetText("...display WinRT UI objects that depend on CoreWindow.");
            args.Request.Data.RequestedOperation = 
                Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
        };

        // Show the Share UI
        interop.ShowShareUIForWindow(hWnd);
    }
}
...

WinUI 3 com C++

// pch.h in a Windows App SDK app
...
#include <shobjidl_core.h>
#include <microsoft.ui.xaml.window.h>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
...

// MainWindow.xaml.cpp
...
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
    // Retrieve the window handle (HWND) of the current WinUI 3 window.
    auto windowNative{ this->m_inner.as<::IWindowNative>() };
    HWND hWnd{ 0 };
    windowNative->get_WindowHandle(&hWnd);

    winrt::com_ptr<IDataTransferManagerInterop> interop = 
        winrt::get_activation_factory<Windows::ApplicationModel::DataTransfer::DataTransferManager,
        IDataTransferManagerInterop>();

    winrt::guid _dtm_iid{ 0xa5caee9b, 0x8708, 0x49d1, { 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c } };
    Windows::ApplicationModel::DataTransfer::DataTransferManager dataTransferManager{ nullptr };
    interop->GetForWindow(hWnd, _dtm_iid, winrt::put_abi(dataTransferManager));

    dataTransferManager.DataRequested([](Windows::ApplicationModel::DataTransfer::DataTransferManager const& /* sender */,
        Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs const& args)
    {
        args.Request().Data().Properties().Title(L"In a desktop app...");
        args.Request().Data().SetText(L"...display WinRT UI objects that depend on CoreWindow.");
        args.Request().Data().RequestedOperation(Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy);
    });

    interop->ShowShareUIForWindow(hWnd);
}
...

Para classes que implementam IUserConsentVerifierInterop

A classe Windows.Security.Credentials.UI.UserConsentVerifier implementa a interface IUserConsentVerifierInterop (que, assim como IInitializeWithWindow, permite definir uma janela de proprietário).

Em um aplicativo de desktop, em vez de chamar o método UserConsentVerifier.RequestVerificationAsync:

Para obter mais informações e exemplos de código, consulte UserConsentVerifier.

Para classes que implementam outras interfaces de interoperabilidade

Essas interfaces têm métodos XxxForWindow, que permitem definir um identificador de janela do proprietário (HWND). Você pode usar essas interfaces diretamente do C++/WinRT. As versões das interfaces também existem na forma de classes C# — para obter mais detalhes, consulte Chamar APIs de interoperabilidade de um aplicativo .NET .