Bagikan melalui


Menggunakan Lapisan Visual dengan Formulir Windows

Anda dapat menggunakan API Komposisi Runtime Windows (juga disebut lapisan Visual) di aplikasi Formulir Windows Anda untuk menciptakan pengalaman modern yang menerangi pengguna Windows.

Kode lengkap untuk tutorial ini tersedia di GitHub: Formulir Windows sampel HelloComposition.

Prasyarat

API hosting UWP memiliki prasyarat ini.

Cara menggunakan API Komposisi di Formulir Windows

Dalam tutorial ini, Anda membuat antarmuka pengguna Formulir Windows sederhana dan menambahkan elemen Komposisi animasi ke dalamnya. Komponen Formulir Windows dan Komposisi tetap sederhana, tetapi kode interop yang ditampilkan sama terlepas dari kompleksitas komponen. Aplikasi yang sudah selesai terlihat seperti ini.

UI aplikasi yang sedang berjalan

Membuat proyek Formulir Windows

Langkah pertama adalah membuat proyek aplikasi Formulir Windows, yang mencakup definisi aplikasi dan formulir utama untuk UI.

Untuk membuat proyek aplikasi Formulir Windows baru di Visual C# bernama HelloComposition:

  1. Buka Visual Studio dan pilih File>Proyek Baru.>
    Dialog Proyek Baru terbuka.
  2. Di bawah kategori Terinstal, perluas simpul Visual C#, lalu pilih Windows Desktop.
  3. Pilih templat Formulir Windows App (.NET Framework).
  4. Masukkan nama HelloComposition, pilih Framework .NET Framework 4.7.2, lalu klik OK.

Visual Studio membuat proyek dan membuka perancang untuk jendela aplikasi default bernama Form1.cs.

Mengonfigurasi proyek untuk menggunakan WINDOWS Runtime API

Untuk menggunakan WINDOWS Runtime (WinRT) API di aplikasi Formulir Windows, Anda perlu mengonfigurasi proyek Visual Studio untuk mengakses Windows Runtime. Selain itu, vektor digunakan secara ekstensif oleh API Komposisi, jadi Anda perlu menambahkan referensi yang diperlukan untuk menggunakan vektor.

Paket NuGet tersedia untuk mengatasi kedua kebutuhan ini. Instal versi terbaru paket ini untuk menambahkan referensi yang diperlukan ke proyek Anda.

Catatan

Meskipun sebaiknya gunakan paket NuGet untuk mengonfigurasi proyek Anda, Anda dapat menambahkan referensi yang diperlukan secara manual. Untuk informasi selengkapnya, lihat Menyempurnakan aplikasi desktop Anda untuk Windows. Tabel berikut ini memperlihatkan file yang perlu Anda tambahkan referensinya.

File Lokasi
System.Runtime.WindowsRuntime C:\Windows\Microsoft.NET\Framework\v4.0.30319
Windows.Foundation.UniversalApiContract.winmd C:\Program Files (x86)\Windows Kits\10\References sdk version>\Windows.Foundation.UniversalApiContract<version<>
Windows.Foundation.FoundationContract.winmd C:\Program Files (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:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2

Membuat kontrol kustom untuk mengelola interop

Untuk menghosting konten yang Anda buat dengan lapisan visual, Anda membuat kontrol kustom yang berasal dari Kontrol. Kontrol ini memberi Anda akses ke Handel jendela, yang Anda butuhkan untuk membuat kontainer untuk konten lapisan visual Anda.

Di sinilah Anda melakukan sebagian besar konfigurasi untuk menghosting API Komposisi. Dalam kontrol ini, Anda menggunakan Platform Invocation Services (PInvoke) dan COM Interop untuk membawa API Komposisi ke aplikasi Formulir Windows Anda. Untuk informasi selengkapnya tentang PInvoke dan COM Interop, lihat Mengoperasikan dengan kode yang tidak dikelola.

Tip

Jika perlu, periksa kode lengkap di akhir tutorial untuk memastikan semua kode berada di tempat yang tepat saat Anda bekerja melalui tutorial.

  1. Tambahkan file kontrol kustom baru ke proyek Anda yang berasal dari Kontrol.

    • Di Penjelajah Solusi, klik kanan proyek HelloComposition.
    • Di menu konteks, pilih Tambahkan>Item Baru....
    • Dalam dialog Tambahkan Item Baru, pilih Kontrol Kustom.
    • Beri nama kontrol CompositionHost.cs, lalu klik Tambahkan. CompositionHost.cs terbuka dalam tampilan Desain.
  2. Beralih ke tampilan kode untuk CompositionHost.cs dan tambahkan kode berikut ke kelas .

    // 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. Tambahkan kode ke konstruktor.

    Di konstruktor, Anda memanggil metode InitializeCoreDispatcher dan InitComposition . Anda membuat metode ini di langkah berikutnya.

    public CompositionHost()
    {
        InitializeComponent();
    
        // Get the window handle.
        hwndHost = Handle;
    
        // Create dispatcher queue.
        dispatcherQueue = InitializeCoreDispatcher();
    
        // Build Composition tree of content.
        InitComposition(hwndHost);
    }
    
  4. Menginisialisasi utas dengan CoreDispatcher. Dispatcher inti bertanggung jawab untuk memproses pesan jendela dan mengirimkan peristiwa untuk API WinRT. Instans baru Compositor harus dibuat pada utas yang memiliki CoreDispatcher.

    • Buat metode bernama InitializeCoreDispatcher dan tambahkan kode untuk menyiapkan antrean 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;
    }
    
    • Antrean dispatcher memerlukan deklarasi PInvoke. Tempatkan deklarasi ini di akhir kode untuk kelas . (Kami menempatkan kode ini di dalam wilayah untuk menjaga agar kode kelas tetap rapi.)
    #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
    

    Anda sekarang memiliki antrean dispatcher yang siap dan dapat mulai menginisialisasi dan membuat konten Komposisi.

  5. Inisialisasi Compositor. Compositor adalah pabrik yang membuat berbagai jenis di namespace Windows.UI.Composition yang mencakup lapisan visual, sistem efek, dan sistem animasi. Kelas Compositor juga mengelola masa pakai objek yang dibuat dari pabrik.

    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 dan ICompositionTarget memerlukan impor COM. Tempatkan kode ini setelah kelas CompositionHost , tetapi di dalam deklarasi namespace layanan.
    #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
    

Membuat kontrol kustom untuk menghosting elemen komposisi

Sebaiknya letakkan kode yang menghasilkan dan mengelola elemen komposisi Anda dalam kontrol terpisah yang berasal dari CompositionHost. Ini menjaga kode interop yang Anda buat di kelas CompositionHost dapat digunakan kembali.

Di sini, Anda membuat kontrol kustom yang berasal dari CompositionHost. Kontrol ini ditambahkan ke kotak alat Visual Studio sehingga Anda dapat menambahkannya ke formulir Anda.

  1. Tambahkan file kontrol kustom baru ke proyek Anda yang berasal dari CompositionHost.

    • Di Penjelajah Solusi, klik kanan proyek HelloComposition.
    • Di menu konteks, pilih Tambahkan>Item Baru....
    • Dalam dialog Tambahkan Item Baru, pilih Kontrol Kustom.
    • Beri nama kontrol CompositionHostControl.cs, lalu klik Tambahkan. CompositionHostControl.cs terbuka dalam tampilan Desain.
  2. Di panel Properti untuk tampilan desain CompositionHostControl.cs, atur properti BackColor ke ControlLight.

    Mengatur warna latar belakang bersifat opsional. Kami melakukannya di sini sehingga Anda dapat melihat kontrol kustom Anda terhadap latar belakang formulir.

  3. Beralih ke tampilan kode untuk CompositionHostControl.cs dan perbarui deklarasi kelas untuk berasal dari CompositionHost.

    class CompositionHostControl : CompositionHost
    
  4. Perbarui konstruktor untuk memanggil konstruktor dasar.

    public CompositionHostControl() : base()
    {
    
    }
    

Menambahkan elemen komposisi

Dengan infrastruktur di tempat, Anda sekarang dapat menambahkan konten Komposisi ke UI aplikasi.

Untuk contoh ini, Anda menambahkan kode ke kelas CompositionHostControl yang membuat dan menganimasikan SpriteVisual sederhana.

  1. Tambahkan elemen komposisi.

    Dalam CompositionHostControl.cs, tambahkan metode ini ke kelas 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);
    }
    

Menambahkan kontrol ke formulir Anda

Sekarang setelah Anda memiliki kontrol kustom untuk menghosting konten Komposisi, Anda dapat menambahkannya ke antarmuka pengguna aplikasi. Di sini, Anda menambahkan instans CompositionHostControl yang Anda buat di langkah sebelumnya. CompositionHostControl secara otomatis ditambahkan ke kotak alat Visual Studio di bawah nama proyek Komponen.

  1. Dalam tampilan desain Form1.CS, tambahkan Tombol ke UI.

    • Seret Tombol dari kotak alat ke Formulir1. Letakkan di sudut kiri atas formulir. (Lihat gambar di awal tutorial untuk memeriksa penempatan kontrol.)
    • Di panel Properti, ubah properti Teks dari tombol1 ke Tambahkan elemen komposisi.
    • Mengubah ukuran Tombol sehingga semua teks ditampilkan.

    (Untuk informasi selengkapnya, lihat Cara: Menambahkan Kontrol ke Formulir Windows.)

  2. Tambahkan CompositionHostControl ke UI.

    • Seret CompositionHostControl dari kotak alat ke Form1. Letakkan di sebelah kanan Tombol.
    • Mengubah ukuran CompositionHost sehingga mengisi sisa formulir.
  3. Menangani peristiwa klik tombol.

    • Di panel Properti, klik petir untuk beralih ke tampilan Peristiwa.
    • Di daftar peristiwa, pilih Peristiwa klik , ketik Button_Click, dan tekan Enter.
    • Kode ini ditambahkan dalam Form1.cs:
    private void Button_Click(object sender, EventArgs e)
    {
    
    }
    
  4. Tambahkan kode ke tombol klik handler untuk membuat elemen baru.

    • Di Form1.cs, tambahkan kode ke penanganan aktivitas Button_Click yang Anda buat sebelumnya. Kode ini memanggil CompositionHostControl1.AddElement untuk membuat elemen baru dengan ukuran dan offset yang dihasilkan secara acak. (Instans CompositionHostControl secara otomatis bernama compositionHostControl1 ketika Anda menyeretnya ke formulir.)
    // 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);
    }
    

Sekarang Anda dapat membuat dan menjalankan aplikasi Formulir Windows Anda. Saat Anda mengklik tombol , Anda akan melihat kotak animasi ditambahkan ke UI.

Langkah berikutnya

Untuk contoh yang lebih lengkap yang dibangun pada infrastruktur yang sama, lihat sampel integrasi lapisan Visual Formulir Windows di GitHub.

Sumber Daya Tambahan:

Kode lengkap

Berikut adalah kode lengkap untuk tutorial ini.

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
}