Uso del livello visivo con Windows Forms

È possibile usare le API di composizione Windows Runtime (denominate anche layer Visual) nelle app Windows Forms per creare esperienze moderne che si illuminano per gli utenti di Windows.

Il codice completo per questa esercitazione è disponibile su GitHub: Windows Forms HelloComposition sample.

Prerequisiti

L'API di hosting UWP presenta questi prerequisiti.

Come usare le API di composizione in Windows Forms

In questa esercitazione si crea una semplice interfaccia utente Windows Forms e si aggiungono elementi Composition animati. Entrambi i componenti Windows Forms e Composition vengono mantenuti semplici, ma il codice di interoperabilità mostrato è lo stesso indipendentemente dalla complessità dei componenti. L'app completata ha un aspetto simile al seguente.

Interfaccia utente dell'app in esecuzione

Creare un progetto Windows Forms

Il primo passaggio consiste nel creare il progetto di app Windows Forms, che include una definizione dell'applicazione e il modulo principale per l'interfaccia utente.

Per creare un nuovo progetto applicazione di Windows Forms in Visual C# denominato HelloComposition:

  1. Apri Visual Studio e seleziona File>Nuovo>Progetto.
    Verrà visualizzata la finestra di dialogo Nuovo progetto.
  2. Nella categoria Installed espandere il nodo Visual C# e quindi selezionare Windows Desktop.
  3. Selezionare il modello Windows Forms App (.NET Framework).
  4. Immettere il nome HelloComposition, selezionare Framework .NET Framework 4.7.2, quindi fare clic su OK.

Visual Studio crea il progetto e apre la finestra di progettazione per la finestra dell'applicazione predefinita denominata Form1.cs.

Configurare il progetto per l'uso delle API di Windows Runtime

Per usare le API Windows Runtime (WinRT) nell'app Windows Forms, è necessario configurare il progetto di Visual Studio per accedere al Windows Runtime. Inoltre, i vettori vengono usati ampiamente dalle API di composizione, quindi è necessario aggiungere i riferimenti necessari per usare i vettori.

I pacchetti NuGet sono disponibili per soddisfare entrambe queste esigenze. Installare le versioni più recenti di questi pacchetti per aggiungere i riferimenti necessari al progetto.

Note

Anche se è consigliabile usare i pacchetti NuGet per configurare il progetto, è possibile aggiungere manualmente i riferimenti necessari. Per ulteriori informazioni, vedi Migliora l'applicazione desktop per Windows. La tabella seguente illustra i file a cui è necessario aggiungere riferimenti.

File Location
System.Runtime.WindowsRuntime C:\Windows\Microsoft.NET\Framework\v4.0.30319
Windows.Foundation.UniversalApiContract.winmd C:\Programmi (x86)\Windows Kits\10\References<sdk version>\Windows.Foundation.UniversalApiContract<version>
Windows.Foundation.FoundationContract.winmd C:\Programmi (x86)\Windows Kits\10\References<sdk version>\Windows.Foundation.FoundationContract<version>
System.Numerics.Vectors.dll C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Numerics.Vectors\v4.0_4.0.0.0__b03f5f7f11d50a3a
System.Numerics.dll C:\Programmi (x86)\Assembly di riferimento\Microsoft\Framework.NETFramework\v4.7.2

Creare un controllo personalizzato per gestire l'interoperabilità

Per ospitare il contenuto creato con il livello visivo, creare un controllo personalizzato derivato da Control. Questo controllo consente di accedere a un handle di finestra, necessario per creare il contenitore per il contenuto del livello visivo.

Questa è la posizione in cui si esegue la maggior parte della configurazione per l'hosting delle API di composizione. In questo controllo si usano Platform Invocation Services (PInvoke) e COM Interop per inserire le API composition nell'app Windows Forms. Per altre info su PInvoke e interoperabilità COM, vedi Interoperabilità con codice non gestito.

Suggerimento

Se necessario, controlla il codice completo alla fine dell'esercitazione per assicurarti che tutto il codice sia nelle posizioni corrette man mano che procedi con l'esercitazione.

  1. Aggiungere un nuovo file di controllo personalizzato al progetto che deriva da Control.

    • In Esplora soluzioni fai clic con il pulsante destro del mouse sul progetto HelloComposition.
    • Nel menu di scelta rapida selezionare Aggiungi>nuovo elemento....
    • Nella finestra di dialogo Aggiungi nuovo elemento selezionare Controllo personalizzato.
    • Assegnare al controllo il nome CompositionHost.cs, quindi fare clic su Aggiungi. CompositionHost.cs si apre nella visualizzazione Struttura.
  2. Passare alla visualizzazione codice per CompositionHost.cs e aggiungere il codice seguente alla classe .

    // Add
    // using Windows.UI.Composition;
    
    IntPtr hwndHost;
    object dispatcherQueue;
    protected ContainerVisual containerVisual;
    protected Compositor compositor;
    
    private ICompositionTarget compositionTarget;
    
    public Visual Child
    {
        set
        {
            if (compositor == null)
            {
                InitComposition(hwndHost);
            }
            compositionTarget.Root = value;
        }
    }
    
  3. Aggiungere codice al costruttore.

    Nel costruttore si chiamano i metodi InitializeCoreDispatcher e InitComposition . Questi metodi vengono creati nei passaggi successivi.

    public CompositionHost()
    {
        InitializeComponent();
    
        // Get the window handle.
        hwndHost = Handle;
    
        // Create dispatcher queue.
        dispatcherQueue = InitializeCoreDispatcher();
    
        // Build Composition tree of content.
        InitComposition(hwndHost);
    }
    
  4. Inizializzare un thread con CoreDispatcher. Il dispatcher principale è responsabile dell'elaborazione dei messaggi della finestra e dell'invio di eventi per le API WinRT. È necessario creare nuove istanze di Compositor in un thread con CoreDispatcher.

    • Creare un metodo denominato InitializeCoreDispatcher e aggiungere il codice per configurare la coda del dispatcher.
    // Add
    // using System.Runtime.InteropServices;
    
    private object InitializeCoreDispatcher()
    {
        DispatcherQueueOptions options = new DispatcherQueueOptions();
        options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA;
        options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
        options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
    
        object queue = null;
        CreateDispatcherQueueController(options, out queue);
        return queue;
    }
    
    • La coda del dispatcher richiede una dichiarazione PInvoke. Inserire questa dichiarazione alla fine del codice per la classe . Questo codice viene inserito all'interno di un'area per mantenere ordinato il codice della classe.
    #region PInvoke declarations
    
    //typedef enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    //{
    //    DQTAT_COM_NONE,
    //    DQTAT_COM_ASTA,
    //    DQTAT_COM_STA
    //};
    internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    {
        DQTAT_COM_NONE = 0,
        DQTAT_COM_ASTA = 1,
        DQTAT_COM_STA = 2
    };
    
    //typedef enum DISPATCHERQUEUE_THREAD_TYPE
    //{
    //    DQTYPE_THREAD_DEDICATED,
    //    DQTYPE_THREAD_CURRENT
    //};
    internal enum DISPATCHERQUEUE_THREAD_TYPE
    {
        DQTYPE_THREAD_DEDICATED = 1,
        DQTYPE_THREAD_CURRENT = 2,
    };
    
    //struct DispatcherQueueOptions
    //{
    //    DWORD dwSize;
    //    DISPATCHERQUEUE_THREAD_TYPE threadType;
    //    DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    //};
    [StructLayout(LayoutKind.Sequential)]
    internal struct DispatcherQueueOptions
    {
        public int dwSize;
    
        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_TYPE threadType;
    
        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    };
    
    //HRESULT CreateDispatcherQueueController(
    //  DispatcherQueueOptions options,
    //  ABI::Windows::System::IDispatcherQueueController** dispatcherQueueController
    //);
    [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
    internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options,
                                            [MarshalAs(UnmanagedType.IUnknown)]
                                            out object dispatcherQueueController);
    
    #endregion PInvoke declarations
    

    A questo punto la coda dispatcher è pronta e puoi iniziare a inizializzare e creare il contenuto di composizione.

  5. Inizializzare il Compositor. Il Compositor è una factory che crea una varietà di tipi nel namespace Windows.UI.Composition, comprendente il livello visivo, il sistema di effetti e il sistema di animazione. La classe Compositor gestisce anche la durata degli oggetti creati dalla factory.

    private void InitComposition(IntPtr hwndHost)
    {
        ICompositorDesktopInterop interop;
    
        compositor = new Compositor();
        object iunknown = compositor as object;
        interop = (ICompositorDesktopInterop)iunknown;
        IntPtr raw;
        interop.CreateDesktopWindowTarget(hwndHost, true, out raw);
    
        object rawObject = Marshal.GetObjectForIUnknown(raw);
        compositionTarget = (ICompositionTarget)rawObject;
    
        if (raw == null) { throw new Exception("QI Failed"); }
    
        containerVisual = compositor.CreateContainerVisual();
        Child = containerVisual;
    }
    
    • ICompositorDesktopInterop e ICompositionTarget richiedono importazioni COM. Inserire questo codice dopo la classe CompositionHost , ma all'interno della dichiarazione dello spazio dei nomi.
    #region COM Interop
    
    /*
    #undef INTERFACE
    #define INTERFACE ICompositorDesktopInterop
        DECLARE_INTERFACE_IID_(ICompositorDesktopInterop, IUnknown, "29E691FA-4567-4DCA-B319-D0F207EB6807")
        {
            IFACEMETHOD(CreateDesktopWindowTarget)(
                _In_ HWND hwndTarget,
                _In_ BOOL isTopmost,
                _COM_Outptr_ IDesktopWindowTarget * *result
                ) PURE;
        };
    */
    [ComImport]
    [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ICompositorDesktopInterop
    {
        void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
    }
    
    //[contract(Windows.Foundation.UniversalApiContract, 2.0)]
    //[exclusiveto(Windows.UI.Composition.CompositionTarget)]
    //[uuid(A1BEA8BA - D726 - 4663 - 8129 - 6B5E7927FFA6)]
    //interface ICompositionTarget : IInspectable
    //{
    //    [propget] HRESULT Root([out] [retval] Windows.UI.Composition.Visual** value);
    //    [propput] HRESULT Root([in] Windows.UI.Composition.Visual* value);
    //}
    
    [ComImport]
    [Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
    public interface ICompositionTarget
    {
        Windows.UI.Composition.Visual Root
        {
            get;
            set;
        }
    }
    
    #endregion COM Interop
    

Creare un controllo personalizzato per ospitare elementi di composizione

È consigliabile inserire il codice che genera e gestisce gli elementi di composizione in un controllo separato che deriva da CompositionHost. In questo modo viene mantenuto riutilizzabile il codice di interoperabilità creato nella classe CompositionHost.

Qui si crea un controllo personalizzato derivato da CompositionHost. Questo controllo viene aggiunto alla casella degli strumenti Visual Studio in modo da poterlo aggiungere al modulo.

  1. Aggiungere un nuovo file di controllo personalizzato al progetto che deriva da CompositionHost.

    • In Esplora soluzioni fai clic con il pulsante destro del mouse sul progetto HelloComposition.
    • Nel menu di scelta rapida selezionare Aggiungi>nuovo elemento....
    • Nella finestra di dialogo Aggiungi nuovo elemento selezionare Controllo personalizzato.
    • Assegnare al controllo il nome CompositionHostControl.cs, quindi fare clic su Aggiungi. CompositionHostControl.cs si apre nella visualizzazione Struttura.
  2. Nel riquadro Proprietà per CompositionHostControl.cs, in visualizzazione struttura, impostare la proprietà BackColor su ControlLight.

    L'impostazione del colore di sfondo è facoltativa. Questa operazione viene eseguita in modo da poter visualizzare il controllo personalizzato sullo sfondo del modulo.

  3. Passare alla visualizzazione codice per CompositionHostControl.cs e aggiornare la dichiarazione di classe per derivare da CompositionHost.

    class CompositionHostControl : CompositionHost
    
  4. Aggiornare il costruttore al fine di chiamare il costruttore di base.

    public CompositionHostControl() : base()
    {
    
    }
    

Aggiungere elementi di composizione

Con l'infrastruttura sul posto, è ora possibile aggiungere contenuto di composizione all'interfaccia utente dell'app.

Per questo esempio, si aggiunge codice alla classe CompositionHostControl che crea e anima un semplice SpriteVisual.

  1. Aggiungi un elemento di composizione.

    In CompositionHostControl.cs aggiungere questi metodi alla classe CompositionHostControl.

    // Add
    // using Windows.UI.Composition;
    
    public void AddElement(float size, float offsetX, float offsetY)
    {
        var visual = compositor.CreateSpriteVisual();
        visual.Size = new Vector2(size, size); // Requires references
        visual.Brush = compositor.CreateColorBrush(GetRandomColor());
        visual.Offset = new Vector3(offsetX, offsetY, 0);
        containerVisual.Children.InsertAtTop(visual);
    
        AnimateSquare(visual, 3);
    }
    
    private void AnimateSquare(SpriteVisual visual, int delay)
    {
        float offsetX = (float)(visual.Offset.X);
        Vector3KeyFrameAnimation animation = compositor.CreateVector3KeyFrameAnimation();
        float bottom = Height - visual.Size.Y;
        animation.InsertKeyFrame(1f, new Vector3(offsetX, bottom, 0f));
        animation.Duration = TimeSpan.FromSeconds(2);
        animation.DelayTime = TimeSpan.FromSeconds(delay);
        visual.StartAnimation("Offset", animation);
    }
    
    private Windows.UI.Color GetRandomColor()
    {
        Random random = new Random();
        byte r = (byte)random.Next(0, 255);
        byte g = (byte)random.Next(0, 255);
        byte b = (byte)random.Next(0, 255);
        return Windows.UI.Color.FromArgb(255, r, g, b);
    }
    

Aggiungere il controllo al modulo

Ora che hai un controllo personalizzato per ospitare il contenuto di Composizione, puoi aggiungerlo all'interfaccia utente dell'app. In questo caso si aggiunge un'istanza di CompositionHostControl creata nel passaggio precedente. CompositionHostControl viene aggiunto automaticamente alla casella degli strumenti Visual Studio in nome progetto Components.

  1. Nella visualizzazione struttura di Form1.CS, aggiungi un pulsante all'interfaccia utente.

    • Trascinare un pulsante dalla casella degli strumenti in Form1. Posizionarlo nell'angolo superiore sinistro del form. Vedere l'immagine all'inizio dell'esercitazione per controllare il posizionamento dei controlli.
    • Nel riquadro Proprietà modificare la proprietà Text da button1 a Aggiungi elemento di composizione.
    • Ridimensionare il pulsante in modo che tutto il testo venga visualizzato.

    Per altre info, vedi Come: Aggiungere controlli a Windows Forms.

  2. Aggiungere compositionHostControl all'interfaccia utente.

    • Trascinare compositionHostControl dalla casella degli strumenti in Form1. Posizionarlo a destra del pulsante.
    • Ridimensionare CompositionHost in modo che riempia il resto del modulo.
  3. Gestire l'evento clic del pulsante.

    • Nel riquadro Proprietà fare clic sul fulmine per passare alla visualizzazione Eventi.
    • Nell'elenco degli eventi selezionare l'evento Click , digitare Button_Click e premere INVIO.
    • Questo codice viene aggiunto in Form1.cs:
    private void Button_Click(object sender, EventArgs e)
    {
    
    }
    
  4. Aggiungere il codice al gestore di clic del pulsante per creare nuovi elementi.

    • In Form1.cs aggiungere codice al gestore eventi Button_Click creato in precedenza. Questo codice chiama CompositionHostControl1.AddElement per creare un nuovo elemento con dimensioni e offset generati in modo casuale. L'istanza di CompositionHostControl è stata denominata automaticamente compositionHostControl1 quando è stata trascinata nel form.
    // Add
    // using System;
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Random random = new Random();
        float size = random.Next(50, 150);
        float offsetX = random.Next(0, (int)(compositionHostControl1.Width - size));
        float offsetY = random.Next(0, (int)(compositionHostControl1.Height/2 - size));
        compositionHostControl1.AddElement(size, offsetX, offsetY);
    }
    

È ora possibile compilare ed eseguire l'app Windows Forms. Quando si fa clic sul pulsante, vengono visualizzati quadrati animati aggiunti all'interfaccia utente.

Passaggi successivi

Per un esempio più completo basato sulla stessa infrastruttura, vedere l'esempio di integrazione del livello visivo Windows Forms su GitHub.

Risorse aggiuntive

Codice completo

Ecco il codice completo per questa esercitazione.

Form1.cs

using System;
using System.Windows.Forms;

namespace HelloComposition
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, EventArgs e)
        {
            Random random = new Random();
            float size = random.Next(50, 150);
            float offsetX = random.Next(0, (int)(compositionHostControl1.Width - size));
            float offsetY = random.Next(0, (int)(compositionHostControl1.Height/2 - size));
            compositionHostControl1.AddElement(size, offsetX, offsetY);
        }
    }
}

CompositionHostControl.cs

using System;
using System.Numerics;
using Windows.UI.Composition;

namespace HelloComposition
{
    class CompositionHostControl : CompositionHost
    {
        public CompositionHostControl() : base()
        {

        }

        public void AddElement(float size, float offsetX, float offsetY)
        {
            var visual = compositor.CreateSpriteVisual();
            visual.Size = new Vector2(size, size); // Requires references
            visual.Brush = compositor.CreateColorBrush(GetRandomColor());
            visual.Offset = new Vector3(offsetX, offsetY, 0);
            containerVisual.Children.InsertAtTop(visual);

            AnimateSquare(visual, 3);
        }

        private void AnimateSquare(SpriteVisual visual, int delay)
        {
            float offsetX = (float)(visual.Offset.X);
            Vector3KeyFrameAnimation animation = compositor.CreateVector3KeyFrameAnimation();
            float bottom = Height - visual.Size.Y;
            animation.InsertKeyFrame(1f, new Vector3(offsetX, bottom, 0f));
            animation.Duration = TimeSpan.FromSeconds(2);
            animation.DelayTime = TimeSpan.FromSeconds(delay);
            visual.StartAnimation("Offset", animation);
        }

        private Windows.UI.Color GetRandomColor()
        {
            Random random = new Random();
            byte r = (byte)random.Next(0, 255);
            byte g = (byte)random.Next(0, 255);
            byte b = (byte)random.Next(0, 255);
            return Windows.UI.Color.FromArgb(255, r, g, b);
        }
    }
}

CompositionHost.cs

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Windows.UI.Composition;

namespace HelloComposition
{
    public partial class CompositionHost : Control
    {
        IntPtr hwndHost;
        object dispatcherQueue;
        protected ContainerVisual containerVisual;
        protected Compositor compositor;
        private ICompositionTarget compositionTarget;

        public Visual Child
        {
            set
            {
                if (compositor == null)
                {
                    InitComposition(hwndHost);
                }
                compositionTarget.Root = value;
            }
        }

        public CompositionHost()
        {
            // Get the window handle.
            hwndHost = Handle;

            // Create dispatcher queue.
            dispatcherQueue = InitializeCoreDispatcher();

            // Build Composition tree of content.
            InitComposition(hwndHost);
        }

        private object InitializeCoreDispatcher()
        {
            DispatcherQueueOptions options = new DispatcherQueueOptions();
            options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA;
            options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
            options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));

            object queue = null;
            CreateDispatcherQueueController(options, out queue);
            return queue;
        }

        private void InitComposition(IntPtr hwndHost)
        {
            ICompositorDesktopInterop interop;

            compositor = new Compositor();
            object iunknown = compositor as object;
            interop = (ICompositorDesktopInterop)iunknown;
            IntPtr raw;
            interop.CreateDesktopWindowTarget(hwndHost, true, out raw);

            object rawObject = Marshal.GetObjectForIUnknown(raw);
            compositionTarget = (ICompositionTarget)rawObject;

            if (raw == null) { throw new Exception("QI Failed"); }

            containerVisual = compositor.CreateContainerVisual();
            Child = containerVisual;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
        }

        #region PInvoke declarations

        //typedef enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
        //{
        //    DQTAT_COM_NONE,
        //    DQTAT_COM_ASTA,
        //    DQTAT_COM_STA
        //};
        internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
        {
            DQTAT_COM_NONE = 0,
            DQTAT_COM_ASTA = 1,
            DQTAT_COM_STA = 2
        };

        //typedef enum DISPATCHERQUEUE_THREAD_TYPE
        //{
        //    DQTYPE_THREAD_DEDICATED,
        //    DQTYPE_THREAD_CURRENT
        //};
        internal enum DISPATCHERQUEUE_THREAD_TYPE
        {
            DQTYPE_THREAD_DEDICATED = 1,
            DQTYPE_THREAD_CURRENT = 2,
        };

        //struct DispatcherQueueOptions
        //{
        //    DWORD dwSize;
        //    DISPATCHERQUEUE_THREAD_TYPE threadType;
        //    DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
        //};
        [StructLayout(LayoutKind.Sequential)]
        internal struct DispatcherQueueOptions
        {
            public int dwSize;

            [MarshalAs(UnmanagedType.I4)]
            public DISPATCHERQUEUE_THREAD_TYPE threadType;

            [MarshalAs(UnmanagedType.I4)]
            public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
        };

        //HRESULT CreateDispatcherQueueController(
        //  DispatcherQueueOptions options,
        //  ABI::Windows::System::IDispatcherQueueController** dispatcherQueueController
        //);
        [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
        internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options,
                                                 [MarshalAs(UnmanagedType.IUnknown)]
                                        out object dispatcherQueueController);

        #endregion PInvoke declarations
    }

    #region COM Interop

    /*
    #undef INTERFACE
    #define INTERFACE ICompositorDesktopInterop
        DECLARE_INTERFACE_IID_(ICompositorDesktopInterop, IUnknown, "29E691FA-4567-4DCA-B319-D0F207EB6807")
        {
            IFACEMETHOD(CreateDesktopWindowTarget)(
                _In_ HWND hwndTarget,
                _In_ BOOL isTopmost,
                _COM_Outptr_ IDesktopWindowTarget * *result
                ) PURE;
        };
    */
    [ComImport]
    [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ICompositorDesktopInterop
    {
        void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
    }

    //[contract(Windows.Foundation.UniversalApiContract, 2.0)]
    //[exclusiveto(Windows.UI.Composition.CompositionTarget)]
    //[uuid(A1BEA8BA - D726 - 4663 - 8129 - 6B5E7927FFA6)]
    //interface ICompositionTarget : IInspectable
    //{
    //    [propget] HRESULT Root([out] [retval] Windows.UI.Composition.Visual** value);
    //    [propput] HRESULT Root([in] Windows.UI.Composition.Visual* value);
    //}

    [ComImport]
    [Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
    public interface ICompositionTarget
    {
        Windows.UI.Composition.Visual Root
        {
            get;
            set;
        }
    }
    #endregion COM Interop
}