Komponen Windows Runtime yang ditengahi untuk aplikasi UWP yang dimuat di samping

Artikel ini membahas fitur yang ditargetkan perusahaan yang didukung oleh Windows 10, yang memungkinkan aplikasi .NET yang ramah sentuhan untuk menggunakan kode yang ada yang bertanggung jawab untuk operasi penting bisnis utama.

Pengantar

Nota Kode sampel yang menyertai makalah ini dapat diunduh untuk Visual Studio 2015 & 2017. Template Microsoft Visual Studio untuk membangun Komponen Runtime Windows yang Ditengahi dapat diunduh di sini: templat Visual Studio 2015 yang menargetkan Aplikasi Windows Universal untuk Windows 10

Windows mencakup fitur baru yang disebut Brokered Windows Runtime Components untuk aplikasi yang dimuat di samping. Kami menggunakan istilah IPC (inter-process communication) untuk menggambarkan kemampuan menjalankan aset perangkat lunak desktop yang ada dalam satu proses (komponen desktop) saat berinteraksi dengan kode ini di Aplikasi UWP. Ini adalah model yang akrab bagi pengembang perusahaan karena aplikasi dan aplikasi basis data yang memanfaatkan Layanan NT di Windows berbagi arsitektur multi-proses yang serupa.

Side-loading aplikasi adalah komponen penting dari fitur ini. Aplikasi khusus perusahaan tidak memiliki tempat di Microsoft Store konsumen umum dan perusahaan memiliki persyaratan yang sangat spesifik seputar keamanan, privasi, distribusi, pengaturan, dan servis. Dengan demikian, model pemuatan samping adalah persyaratan bagi mereka yang akan menggunakan fitur ini dan detail implementasi yang kritis.

Aplikasi data-sentris adalah target utama untuk arsitektur aplikasi ini. Hal ini dibayangkan bahwa aturan bisnis yang ada ensconced, misalnya, di SQL Server, akan menjadi bagian umum dari komponen desktop. Ini tentu bukan satu-satunya jenis fungsi yang dapat disodorkan oleh komponen desktop, tetapi sebagian besar permintaan untuk fitur ini terkait dengan data dan logika bisnis yang ada.

Terakhir, mengingat penetrasi runtime .NET yang luar biasa dan bahasa C # dalam pengembangan perusahaan, fitur ini dikembangkan dengan penekanan pada penggunaan .NET untuk aplikasi UWP dan sisi komponen desktop. Meskipun ada bahasa dan runtime lain yang mungkin untuk aplikasi UWP, sampel yang menyertainya hanya menggambarkan C #, dan dibatasi pada runtime .NET secara eksklusif.

Komponen aplikasi

Nota Fitur ini khusus untuk penggunaan .NET. Aplikasi klien dan komponen desktop harus ditulis menggunakan .NET.

Model aplikasi

Fitur ini dibangun di sekitar arsitektur aplikasi umum yang dikenal sebagai MVVM (Model View View-Model). Dengan demikian, diasumsikan bahwa "model" ditempatkan sepenuhnya di komponen desktop. Oleh karena itu, harus segera jelas bahwa komponen desktop akan "tanpa kepala" (yaitu tidak mengandung UI). Tampilan akan sepenuhnya terkandung dalam aplikasi perusahaan yang dimuat di samping. Meskipun tidak ada persyaratan bahwa aplikasi ini dibangun dengan konstruksi "view-model", kami mengantisipasi bahwa penggunaan pola ini akan umum.

Komponen desktop

Komponen desktop dalam fitur ini adalah jenis aplikasi baru yang diperkenalkan sebagai bagian dari fitur ini. Komponen desktop ini hanya dapat ditulis dalam C # dan harus menargetkan .NET 4.6 atau lebih besar untuk Windows 10. Jenis proyek adalah hibrida antara CLR yang menargetkan UWP karena format komunikasi antar proses terdiri dari jenis dan kelas UWP, sedangkan komponen desktop diizinkan untuk memanggil semua bagian pustaka kelas runtime .NET. Dampak pada proyek Visual Studio akan dijelaskan secara rinci nanti. Konfigurasi hibrida ini memungkinkan marshaling jenis UWP antara aplikasi yang dibangun pada komponen desktop sambil memungkinkan kode CLR desktop dipanggil di dalam implementasi komponen desktop.

Kontrak

Kontrak antara aplikasi yang dimuat di samping dan komponen desktop dijelaskan dalam hal sistem tipe UWP. Ini melibatkan mendeklarasikan satu atau lebih kelas C # yang dapat mewakili UWP. Lihat topik MSDN Membuat komponen runtime Windows di C# dan Visual Basic untuk persyaratan khusus membuat Kelas Runtime Windows menggunakan C#.

Nota Enums tidak didukung dalam kontrak komponen runtime Windows antara komponen desktop dan aplikasi yang dimuat di samping saat ini.

Aplikasi yang dimuat di samping

Aplikasi yang dimuat di samping adalah aplikasi UWP normal dalam segala hal kecuali satu: itu dimuat di samping alih-alih diinstal melalui Microsoft Store. Sebagian besar mekanisme instalasi identik: manifes dan kemasan aplikasi serupa (satu tambahan manifes dijelaskan secara rinci nanti). Setelah pemuatan samping diaktifkan, skrip PowerShell sederhana dapat menginstal sertifikat yang diperlukan dan aplikasi itu sendiri. Ini adalah praktik terbaik yang normal bahwa aplikasi yang dimuat di samping lulus tes sertifikasi WACK yang termasuk dalam menu Project / Store di Visual Studio

Nota Pemuatan samping dapat diaktifkan di Pengaturan-> Perbarui & keamanan -> Untuk pengembang.

Satu hal penting yang perlu diperhatikan adalah bahwa mekanisme Broker Aplikasi yang dikirim sebagai bagian dari Windows 10 hanya 32-bit. Komponen desktop harus 32-bit. Aplikasi yang dimuat di samping bisa 64-bit (asalkan ada proxy 64-bit dan 32-bit yang terdaftar), tetapi ini akan atipikal. Membangun aplikasi yang dimuat di samping dalam C # menggunakan konfigurasi "netral" normal dan default "lebih suka 32-bit" secara alami menciptakan aplikasi yang dimuat sisi 32-bit.

Server instancing dan AppDomains

Setiap aplikasi yang dimuat dengan sisi menerima instancenya sendiri dari server App Broker (yang disebut "multi-instancing"). Kode server berjalan di dalam satu AppDomain. Hal ini memungkinkan untuk memiliki beberapa versi perpustakaan yang berjalan dalam instans terpisah. Misalnya, aplikasi A membutuhkan V1.1 dari komponen dan aplikasi B membutuhkan V2. Ini dipisahkan dengan bersih dengan memiliki komponen V1.1 dan V2 di direktori server terpisah dan mengarahkan aplikasi ke server mana pun yang mendukung versi yang benar yang diinginkan.

Implementasi kode server dapat dibagi di antara beberapa instans server App Broker dengan mengarahkan beberapa aplikasi ke direktori server yang sama. Masih akan ada beberapa contoh server App Broker tetapi mereka akan menjalankan kode yang sama. Semua komponen implementasi yang digunakan dalam satu aplikasi harus ada di jalur yang sama.

Mendefinisikan kontrak

Langkah pertama dalam membuat aplikasi menggunakan fitur ini adalah membuat kontrak antara aplikasi yang dimuat di samping dan komponen desktop. Ini harus dilakukan secara eksklusif menggunakan jenis Runtime Windows. Untungnya, ini mudah untuk menyatakan menggunakan kelas C #. Namun, ada pertimbangan kinerja yang penting saat mendefinisikan percakapan ini, yang tercakup dalam bagian selanjutnya.

Urutan untuk menentukan kontrak diperkenalkan sebagai berikut:

Langkah 1: Buat pustaka kelas baru di Visual Studio. Pastikan untuk membuat proyek menggunakan templat Pustaka Kelas, dan bukan templat Komponen Runtime Windows.

Implementasi jelas mengikuti, tetapi bagian ini hanya mencakup definisi kontrak antar-proses. Sampel yang menyertainya mencakup kelas berikut (EnterpriseServer.cs), bentuk awal yang terlihat seperti:

namespace Fabrikam
{
    public sealed class EnterpriseServer
    {

        public ILis<String> TestMethod(String input)
        {
            throw new NotImplementedException();
        }
        
        public IAsyncOperation<int> FindElementAsync(int input)
        {
            throw new NotImplementedException();
        }
        
        public string[] RetrieveData()
        {
            throw new NotImplementedException();
        }
        
        public event EventHandler<string> PeriodicEvent;
    }
}

Ini mendefinisikan kelas "EnterpriseServer" yang dapat instantiated dari aplikasi yang dimuat di samping. Kelas ini menyediakan fungsionalitas yang dijanjikan dalam RuntimeClass. RuntimeClass dapat digunakan untuk menghasilkan winmd referensi yang akan disertakan dalam aplikasi yang dimuat di samping.

Langkah 2: Edit file proyek secara manual untuk mengubah jenis output proyek menjadi Windows Komponen Runtime.

Untuk melakukan ini di Visual Studio, klik kanan pada proyek yang baru dibuat dan pilih "Bongkar Project", lalu klik kanan lagi dan pilih "Edit EnterpriseServer.csproj" untuk membuka file proyek, file XML, untuk diedit.

Dalam file yang dibuka, cari <tag OutputType> dan ubah nilainya menjadi "winmdobj".

Langkah 3: Buat aturan build yang membuat file metadata "referensi" Windows (file.winmd). Yaitu tidak memiliki implementasi.

Langkah 4: Buat aturan build yang membuat file metadata "implementasi" Windows, yaitu memiliki informasi metadata yang sama, tetapi juga menyertakan implementasinya.

Ini akan dilakukan oleh skrip berikut. Tambahkan skrip ke baris perintah peristiwa Pasca-build, di Proyek PropertiesBuild> Events.

Perhatikan skrip berbeda berdasarkan versi Windows Anda targetkan (Windows 10) dan versi Visual Studio yang digunakan.

Visual Studio 2015

    call "$(DevEnvDir)..\..\vc\vcvarsall.bat" x86 10.0.14393.0

    md "$(TargetDir)"\impl    md "$(TargetDir)"\reference

    erase "$(TargetDir)\impl\*.winmd"
    erase "$(TargetDir)\impl\*.pdb"
    rem erase "$(TargetDir)\reference\*.winmd"

    xcopy /y "$(TargetPath)" "$(TargetDir)impl"
    xcopy /y "$(TargetDir)*.pdb" "$(TargetDir)impl"

    winmdidl /nosystemdeclares /metadata_dir:C:\Windows\System32\Winmetadata "$(TargetPath)"

    midl /metadata_dir "%WindowsSdkDir%UnionMetadata" /iid "$(SolutionDir)BrokeredProxyStub\$(TargetName)_i.c" /env win32 /x86 /h   "$(SolutionDir)BrokeredProxyStub\$(TargetName).h" /winmd "$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(SolutionDir)BrokeredProxyStub\dlldata.c" /proxy "$(SolutionDir)BrokeredProxyStub\$(TargetName)_p.c"  "$(TargetName).idl"
    mdmerge -n 1 -i "$(ProjectDir)bin\$(ConfigurationName)" -o "$(TargetDir)reference" -metadata_dir "%WindowsSdkDir%UnionMetadata" -partial

    rem erase "$(TargetPath)"

Visual Studio 2017

    call "$(DevEnvDir)..\..\vc\auxiliary\build\vcvarsall.bat" x86 10.0.16299.0

    md "$(TargetDir)"\impl
    md "$(TargetDir)"\reference

    erase "$(TargetDir)\impl\*.winmd"
    erase "$(TargetDir)\impl\*.pdb"
    rem erase "$(TargetDir)\reference\*.winmd"

    xcopy /y "$(TargetPath)" "$(TargetDir)impl"
    xcopy /y "$(TargetDir)*.pdb" "$(TargetDir)impl"

    winmdidl /nosystemdeclares /metadata_dir:C:\Windows\System32\Winmetadata "$(TargetPath)"

    midl /metadata_dir "%WindowsSdkDir%UnionMetadata" /iid "$(SolutionDir)BrokeredProxyStub\$(TargetName)_i.c" /env win32 /x86 /h "$(SolutionDir)BrokeredProxyStub\$(TargetName).h" /winmd "$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(SolutionDir)BrokeredProxyStub\dlldata.c" /proxy "$(SolutionDir)BrokeredProxyStub\$(TargetName)_p.c"  "$(TargetName).idl"
    mdmerge -n 1 -i "$(ProjectDir)bin\$(ConfigurationName)" -o "$(TargetDir)reference" -metadata_dir "%WindowsSdkDir%UnionMetadata" -partial

    rem erase "$(TargetPath)"

Setelah winmd referensi dibuat (dalam folder "referensi" di bawah folder Target proyek), itu dibawa dengan tangan (disalin) ke setiap proyek aplikasi yang dimuat di samping dan direferensikan. Ini akan dijelaskan lebih lanjut di bagian berikutnya. Struktur proyek yang terkandung dalam aturan build di atas memastikan bahwa implementasi dan winmd referensi berada di direktori yang jelas terpisah dalam hierarki build untuk menghindari kebingungan.

Aplikasi yang dimuat secara detail

Seperti yang dinyatakan sebelumnya, aplikasi yang dimuat di samping dibangun seperti aplikasi UWP lainnya, tetapi ada satu detail tambahan: menyatakan ketersediaan RuntimeClass (es) dalam manifes aplikasi yang dimuat di samping. Hal ini memungkinkan aplikasi untuk hanya menulis baru untuk mengakses fungsionalitas di komponen desktop. Entri manifes baru di <bagian Ekstensi> menjelaskan RuntimeClass yang diimplementasikan di komponen desktop dan informasi di mana lokasinya. Konten deklarasi ini dalam manifes aplikasi sama untuk aplikasi yang menargetkan Windows 10. Contohnya:

<Extension Category="windows.activatableClass.inProcessServer">
    <InProcessServer>
        <Path>clrhost.dll</Path>
        <ActivatableClass ActivatableClassId="Fabrikam.EnterpriseServer" ThreadingModel="both">
            <ActivatableClassAttribute Name="DesktopApplicationPath" Type="string" Value="c:\test" />
        </ActivatableClass>
    </InProcessServer>
</Extension>

Kategorinya ada diProcessServer karena ada beberapa entri dalam kategori outOfProcessServer yang tidak berlaku untuk konfigurasi aplikasi ini. Perhatikan bahwa <komponen Path> harus selalu berisi clrhost.dll (namun ini tidak diberlakukan dan menentukan nilai yang berbeda akan gagal dengan cara yang tidak terdefinisi).

Bagian <ActivatableClass> sama dengan RuntimeClass dalam proses yang benar yang disukai oleh komponen Runtime Windows dalam paket aplikasi. <ActivatableClassAttribute> adalah elemen baru, dan atribut Name="DesktopApplicationPath" dan Type="string" adalah wajib dan invarian. Atribut Nilai menunjuk ke lokasi di mana winmd implementasi komponen desktop berada (lebih detail tentang ini di bagian berikutnya). Setiap RuntimeClass yang disukai oleh komponen desktop harus memiliki pohon elemen ActivatableClass> sendiri<. ActivatableClassId harus sesuai dengan nama runtimeclass yang sepenuhnya memenuhi syarat.

Seperti disebutkan di bagian "Mendefinisikan kontrak", referensi proyek harus dibuat ke winmd referensi komponen desktop. Sistem proyek Visual Studio biasanya membuat struktur direktori dua tingkat dengan nama yang sama. Dalam sampel itu adalah EnterpriseIPCApplication\EnterpriseIPCApplication. Winmd referensi disalin secara manual ke direktori tingkat kedua ini dan kemudian dialog Referensi Project digunakan (klik tombol Browse.. ) untuk menemukan dan mereferensikan winmd ini. Setelah ini, namespace tingkat atas komponen desktop (misalnya, Fabrikam) akan muncul sebagai node tingkat atas di bagian Referensi proyek.

Nota Sangat penting untuk menggunakan winmd referensi dalam aplikasi yang dimuat di samping. Jika Anda secara tidak sengaja membawa winmd implementasi ke direktori aplikasi yang dimuat di samping dan mereferensikannya, Anda mungkin akan menerima kesalahan yang terkait dengan "tidak dapat menemukan IStringable". Ini adalah salah satu tanda pasti bahwa winmd yang salah telah dirujuk. Aturan pasca-build di aplikasi server IPC (dirinci di bagian berikutnya) dengan hati-hati memisahkan kedua winmd ini menjadi direktori terpisah.

Variabel lingkungan (terutama %ProgramFiles%) dapat digunakan di <ActivatableClassAttribute Value="path"> . Seperti disebutkan sebelumnya, Broker Aplikasi hanya mendukung 32-bit sehingga %ProgramFiles% akan menyelesaikan ke C:\Program Files (x86) jika aplikasi dijalankan pada OS 64-bit.

Detail server IPC Desktop

Dua bagian sebelumnya menggambarkan deklarasi kelas dan mekanisme pengangkutan winmd referensi ke proyek aplikasi yang dimuat di samping. Sebagian besar pekerjaan yang tersisa di komponen desktop melibatkan implementasi. Karena seluruh titik komponen desktop adalah untuk dapat memanggil kode desktop (biasanya untuk memanfaatkan kembali aset kode yang ada), proyek harus dikonfigurasi dengan cara khusus. Biasanya, proyek Visual Studio menggunakan .NET menggunakan salah satu dari dua "profil". Salah satunya adalah untuk desktop (". NetFramework") dan satu menargetkan bagian aplikasi UWP dari CLR (". NetCore"). Komponen desktop dalam fitur ini adalah hibrida di antara keduanya. Akibatnya, bagian referensi dibangun dengan sangat hati-hati untuk memadukan kedua profil ini.

Proyek aplikasi UWP normal tidak berisi referensi proyek eksplisit karena keseluruhan permukaan API Runtime Windows disertakan secara implisit. Biasanya hanya referensi antar proyek lainnya yang dibuat. Namun, proyek komponen desktop memiliki serangkaian referensi yang sangat khusus. Ini memulai kehidupan sebagai proyek "Perpustakaan Desktop Klasik" dan oleh karena itu adalah proyek desktop. Jadi referensi eksplisit ke Windows Runtime API (melalui referensi ke file winmd) harus dibuat. Tambahkan referensi yang tepat seperti yang ditunjukkan di bawah ini.

<ItemGroup>
    <!-- These reference are added by VS automatically when you create a Class Library project-->
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
    <!-- These reference should be added manually by editing .csproj file-->

    <Reference Include="System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
      <HintPath>$(MSBuildProgramFiles32)\Microsoft SDKs\NETCoreSDK\System.Runtime.WindowsRuntime\4.0.10\lib\netcore50\System.Runtime.WindowsRuntime.dll</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows">
      <HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Foundation.FoundationContract">
      <HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\References\Windows.Foundation.FoundationContract\1.0.0.0\Windows.Foundation.FoundationContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Foundation.UniversalApiContract">
      <HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\References\Windows.Foundation.UniversalApiContract\1.0.0.0\Windows.Foundation.UniversalApiContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Networking.Connectivity.WwanContract">
      <HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\References\Windows.Networking.Connectivity.WwanContract\1.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Activation.ActivatedEventsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Activation.ActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivatedEventsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Activation.ActivationCameraSettingsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Activation.ContactActivatedEventsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Activation.ContactActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract\1.0.0.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Calls.LockScreenCallContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Calls.LockScreenCallContract\1.0.0.0\Windows.ApplicationModel.Calls.LockScreenCallContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Resources.Management.ResourceIndexerContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract\1.0.0.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Search.Core.SearchCoreContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Search.Core.SearchCoreContract\1.0.0.0\Windows.ApplicationModel.Search.Core.SearchCoreContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Search.SearchContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Search.SearchContract\1.0.0.0\Windows.ApplicationModel.Search.SearchContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.ApplicationModel.Wallet.WalletContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.ApplicationModel.Wallet.WalletContract\1.0.0.0\Windows.ApplicationModel.Wallet.WalletContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Custom.CustomDeviceContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Portable.PortableDeviceContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Portable.PortableDeviceContract\1.0.0.0\Windows.Devices.Portable.PortableDeviceContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Printers.Extensions.ExtensionsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Printers.Extensions.ExtensionsContract\1.0.0.0\Windows.Devices.Printers.Extensions.ExtensionsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Printers.PrintersContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Scanners.ScannerDeviceContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Scanners.ScannerDeviceContract\1.0.0.0\Windows.Devices.Scanners.ScannerDeviceContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Devices.Sms.LegacySmsApiContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Devices.Sms.LegacySmsApiContract\1.0.0.0\Windows.Devices.Sms.LegacySmsApiContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Gaming.Preview.GamesEnumerationContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Gaming.Preview.GamesEnumerationContract\1.0.0.0\Windows.Gaming.Preview.GamesEnumerationContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract\1.0.0.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Graphics.Printing3D.Printing3DContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Graphics.Printing3D.Printing3DContract\1.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Management.Deployment.Preview.DeploymentPreviewContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Management.Deployment.Preview.DeploymentPreviewContract\1.0.0.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Management.Workplace.WorkplaceSettingsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Management.Workplace.WorkplaceSettingsContract\1.0.0.0\Windows.Management.Workplace.WorkplaceSettingsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.Capture.AppCaptureContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.Capture.AppCaptureContract\1.0.0.0\Windows.Media.Capture.AppCaptureContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.Capture.CameraCaptureUIContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.Capture.CameraCaptureUIContract\1.0.0.0\Windows.Media.Capture.CameraCaptureUIContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.Devices.CallControlContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.Devices.CallControlContract\1.0.0.0\Windows.Media.Devices.CallControlContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.MediaControlContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.MediaControlContract\1.0.0.0\Windows.Media.MediaControlContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.Playlists.PlaylistsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.Playlists.PlaylistsContract\1.0.0.0\Windows.Media.Playlists.PlaylistsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Media.Protection.ProtectionRenewalContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Media.Protection.ProtectionRenewalContract\1.0.0.0\Windows.Media.Protection.ProtectionRenewalContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract\1.0.0.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Networking.Sockets.ControlChannelTriggerContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Networking.Sockets.ControlChannelTriggerContract\1.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Security.EnterpriseData.EnterpriseDataContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Security.EnterpriseData.EnterpriseDataContract\1.0.0.0\Windows.Security.EnterpriseData.EnterpriseDataContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Security.ExchangeActiveSyncProvisioning.EasContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Security.ExchangeActiveSyncProvisioning.EasContract\1.0.0.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Services.Maps.GuidanceContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Services.Maps.GuidanceContract\1.0.0.0\Windows.Services.Maps.GuidanceContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Services.Maps.LocalSearchContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Services.Maps.LocalSearchContract\1.0.0.0\Windows.Services.Maps.LocalSearchContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.System.Profile.SystemManufacturers.SystemManufacturersContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\1.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.System.Profile.ProfileHardwareTokenContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.System.Profile.ProfileRetailInfoContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.System.UserProfile.UserProfileContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.System.UserProfile.UserProfileContract\1.0.0.0\Windows.System.UserProfile.UserProfileContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.System.UserProfile.UserProfileLockScreenContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.System.UserProfile.UserProfileLockScreenContract\1.0.0.0\Windows.System.UserProfile.UserProfileLockScreenContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.UI.ApplicationSettings.ApplicationsSettingsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.UI.ApplicationSettings.ApplicationsSettingsContract\1.0.0.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.UI.Core.AnimationMetrics.AnimationMetricsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract\1.0.0.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.UI.Core.CoreWindowDialogsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.UI.Core.CoreWindowDialogsContract\1.0.0.0\Windows.UI.Core.CoreWindowDialogsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.UI.Xaml.Hosting.HostingContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.UI.Xaml.Hosting.HostingContract\1.0.0.0\Windows.UI.Xaml.Hosting.HostingContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
    <Reference Include="Windows.Web.Http.Diagnostics.HttpDiagnosticsContract">
      <HintPath>$(MsBuildProgramFiles32)\Windows Kits\10\References\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract\1.0.0.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract.winmd</HintPath>
      <Private>False</Private>
    </Reference>
</ItemGroup>

Referensi di atas adalah campuran hati-hati dari eferences yang sangat penting untuk operasi yang tepat dari server hybrid ini. Protokolnya adalah membuka file .csproj (seperti yang dijelaskan dalam cara mengedit outputtype proyek) dan menambahkan referensi ini seperlunya.

Setelah referensi dikonfigurasi dengan benar, tugas selanjutnya adalah menerapkan fungsionalitas server. Lihat topik Praktik terbaik untuk interoperabilitas dengan komponen Runtime Windows (aplikasi UWP menggunakan C#/VB/C++ dan XAML). Tugasnya adalah membuat komponen runtime Windows dll yang mampu memanggil kode desktop sebagai bagian dari implementasinya. Sampel yang menyertainya mencakup pola utama yang digunakan dalam runtime Windows:

  • Panggilan metode

  • Windows Sumber Peristiwa Runtime menurut komponen desktop

  • Windows Operasi Runtime Async

  • Mengembalikan array tipe dasar

Instal

Untuk menginstal aplikasi, salin winmd implementasi ke direktori yang benar yang ditentukan dalam manifes aplikasi bermuatan samping terkait: <Value="path" ActivatableClassAttribute>. Juga salin file dukungan terkait dan dll proxy / rintisan (detail terakhir ini tercakup di bawah). Gagal menyalin winmd implementasi ke lokasi direktori server akan menyebabkan semua panggilan aplikasi yang dimuat ke yang baru di RuntimeClass akan melemparkan kesalahan "kelas tidak terdaftar". Kegagalan untuk menginstal proxy / rintisan (atau kegagalan untuk mendaftar) akan menyebabkan semua panggilan gagal tanpa nilai kembali. Kesalahan terakhir ini sering tidak terkait dengan pengecualian yang terlihat. Jika pengecualian diamati karena kesalahan konfigurasi ini, mereka dapat merujuk ke "pemeran tidak valid".

Pertimbangan implementasi server

Server runtime Windows desktop dapat dianggap sebagai berbasis "pekerja" atau "tugas". Setiap panggilan ke server beroperasi pada utas non-UI dan semua kode harus sadar multi-thread dan aman. Bagian mana dari aplikasi yang dimuat di samping yang memanggil fungsionalitas server juga penting. Sangat penting untuk selalu menghindari memanggil kode yang sudah berjalan lama dari utas UI apa pun di aplikasi yang dimuat di samping. Ada dua cara utama untuk mencapai hal ini:

  1. Jika memanggil fungsionalitas server dari utas UI, selalu gunakan pola async di area permukaan publik dan implementasi server.

  2. Panggil fungsionalitas server dari utas latar belakang di aplikasi yang dimuat di samping.

Windows Runtime asinkron di server

Mengingat sifat lintas proses dari model aplikasi, panggilan ke server memiliki lebih banyak overhead daripada kode yang berjalan secara eksklusif dalam proses. Biasanya aman untuk memanggil properti sederhana yang mengembalikan nilai dalam memori karena akan mengeksekusi cukup cepat sehingga memblokir utas UI tidak menjadi perhatian. Namun, setiap panggilan yang melibatkan I /O dalam bentuk apa pun (ini mencakup semua penanganan file dan pengambilan database) berpotensi memblokir utas UI panggilan dan menyebabkan aplikasi dihentikan karena tidak responsif. Selain itu, panggilan properti pada objek tidak disarankan dalam arsitektur aplikasi ini karena alasan kinerja. Ini dibahas secara lebih mendalam di bagian berikut.

Server yang diimplementasikan dengan benar biasanya akan menerapkan panggilan yang dibuat langsung dari utas UI melalui pola async Runtime Windows. Ini dapat diimplementasikan dengan mengikuti pola ini. Pertama, deklarasi (sekali lagi, dari sampel yang menyertainya):

public IAsyncOperation<int> FindElementAsync(int input)

Ini mendeklarasikan operasi async runtime Windows yang mengembalikan bilangan bulat. Implementasi operasi async biasanya mengambil formulir:

return Task<int>.Run( () =>
{
    int retval = ...
    // execute some potentially long-running code here 
}).AsAsyncOperation<int>();

Nota Adalah umum untuk menunggu beberapa operasi lain yang berpotensi lama berjalan sambil menulis implementasi. Jika demikian, kode Task.Run perlu dideklarasikan:

return Task<int>.Run(async () =>
{
    int retval = ...
    // execute some potentially long-running code here 
    await ... // some other WinRT async operation or Task
}).AsAsyncOperation<int>();

Klien dari metode async ini dapat menunggu operasi ini seperti operasi aysnc Runtime Windows lainnya.

Fungsi server panggilan dari utas latar belakang aplikasi

Karena biasanya bahwa klien dan server akan ditulis oleh organisasi yang sama, praktik pemrograman dapat diadopsi bahwa semua panggilan ke server akan dilakukan oleh utas latar belakang di aplikasi yang dimuat di samping. Panggilan langsung yang mengumpulkan satu atau lebih kumpulan data dari server dapat dilakukan dari utas latar belakang. Ketika hasilnya benar-benar diambil, kumpulan data yang ada dalam memori dalam proses aplikasi biasanya dapat langsung diambil dari utas UI. Objek C # secara alami gesit antara utas latar belakang dan utas UI sehingga sangat berguna untuk pola panggilan semacam ini.

Membuat dan menyebarkan proxy runtime Windows

Karena pendekatan IPC melibatkan marshaling Windows antarmuka Runtime antara dua proses, proxy dan rintisan runtime Windows yang terdaftar secara global harus digunakan.

Membuat proxy di Visual Studio

Proses untuk membuat dan mendaftarkan proxy dan rintisan untuk digunakan di dalam paket aplikasi UWP biasa dijelaskan dalam topik Raising Events in Windows Runtime Components. Langkah-langkah yang dijelaskan dalam artikel ini lebih rumit daripada proses yang dijelaskan di bawah ini karena melibatkan pendaftaran proxy / rintisan dalam paket aplikasi (sebagai lawan mendaftarkannya secara global).

Langkah 1: Menggunakan solusi untuk proyek komponen desktop, buat proyek Proxy/Stub di Visual Studio:

Solusi > Tambahkan > Project > Opsi Opsi Pilih DLL Pilih Konsol C++ > Win32 Visual.

Untuk langkah-langkah di bawah ini, kami menganggap komponen server disebut MyWinRTComponent.

Langkah 3: Hapus semua file CPP /H dari proyek.

Langkah 4: Bagian sebelumnya "Mendefinisikan Kontrak" berisi perintah Post-Build yang menjalankan winmdidl.exe, midl.exe, mdmerge.exe, dan sebagainya. Salah satu output dari langkah tengah perintah pasca-build ini menghasilkan empat output penting:

a) Dlldata.c

b) File header (misalnya, MyWinRTComponent.h)

c) File *_i.c (misalnya, MyWinRTComponent_i.c)

d) File *_p.c (misalnya, MyWinRTComponent_p.c)

Langkah 5: Tambahkan empat file yang dihasilkan ini ke proyek "MyWinRTProxy".

Langkah 6: Tambahkan file def ke proyek "MyWinRTProxy" (Project > Tambahkan Kode > Item > Baru Module-Definition File) dan perbarui kontennya menjadi:

perpustakaan MyWinRTComponent.Proxies.dll

EKSPOR

DllCanUnloadNow PRIVATE

DllGetClassObject PRIVATE

DllRegisterServer PRIVATE

DllUnregisterServer PRIVATE

Langkah 7: Properti terbuka untuk proyek "MyWinRTProxy":

Nama Target Umum > Properti > Comfiguration :

MyWinRTComponent.Proxys

Definisi Praprosesor > C/C++ > Tambahkan

"WIN32;_WINDOWS; REGISTER_PROXY_DLL"

Header C/C++ > yang telah dikompilasi: Pilih "Tidak Menggunakan Header yang Telah Dikompilasi"

Linker > General > Abaikan Pustaka Impor : Pilih "Ya"

Linker > Input > Dependensi Tambahan : Tambahkan rpcrt4.lib;runtimeobject.lib

Linker > Windows Metadata > Menghasilkan Metadata Windows : Pilih "Tidak"

Langkah 8: Membangun proyek "MyWinRTProxy".

Menyebarkan proxy

Proxy harus terdaftar secara global. Cara termudah untuk melakukan ini adalah dengan meminta proses instalasi Anda memanggil DllRegisterServer pada dll proxy. Perhatikan bahwa karena fitur ini hanya mendukung server yang dibangun untuk x86 (yaitu tidak ada dukungan 64-bit), konfigurasi paling sederhana adalah menggunakan server 32-bit, proxy 32-bit, dan aplikasi side-loaded 32-bit. Proxy biasanya duduk di samping winmd implementasi untuk komponen desktop.

Satu langkah konfigurasi tambahan harus dilakukan. Agar proses yang dimuat di samping memuat dan menjalankan proxy, direktori harus ditandai "baca / jalankan" untuk ALL_APPLICATION_PACKAGES. Ini dilakukan melalui alat baris perintah icacls.exe . Perintah ini harus dijalankan di direktori tempat implementasi winmd dan proxy/rintisan dll berada:

icacls . /T /grant *S-1-15-2-1:RX

Pola dan kinerja

Sangat penting bahwa kinerja transportasi lintas proses dipantau dengan cermat. Panggilan lintas proses setidaknya dua kali lebih mahal daripada panggilan dalam proses. Membuat percakapan "cerewet" lintas proses atau melakukan transfer berulang dari objek besar seperti gambar bitmap, dapat menyebabkan kinerja aplikasi yang tidak terduga dan tidak diinginkan.

Berikut adalah daftar hal-hal yang tidak lengkap untuk dipertimbangkan:

  • Panggilan metode sinkron dari utas UI aplikasi ke server harus selalu dihindari. Panggil metode dari utas latar belakang dalam aplikasi dan kemudian gunakan CoreWindowDispatcher untuk mendapatkan hasilnya ke utas UI jika perlu.

  • Memanggil operasi async dari utas UI aplikasi aman, tetapi pertimbangkan masalah kinerja yang dibahas di bawah ini.

  • Transfer massal hasil mengurangi cerewet lintas proses. Ini biasanya dilakukan dengan menggunakan Windows runtime array build.

  • Mengembalikan ListT<> di mana T adalah objek dari operasi async atau pengambilan properti, akan menyebabkan banyak obrolan lintas proses. Misalnya, asumsikan Anda mengembalikan objek aListPeople<>. Setiap iterasi lulus akan menjadi panggilan lintas proses. Setiap objek Orang yang dikembalikan diwakili oleh proxy dan setiap panggilan ke metode atau properti pada objek individual tersebut akan menghasilkan panggilan lintas proses. Jadi objek ListPeople<> "tidak bersalah" di mana Count besar akan menyebabkan sejumlah besar panggilan lambat. Hasil kinerja yang lebih baik dari transfer massal struktur konten dalam array. Contohnya:

struct PersonStruct
{
    String LastName;
    String FirstName;
    int Age;
   // etc.
}

Kemudian kembali personstruct[] bukan ListPersonObject<>. Ini mendapatkan semua data dalam satu "hop" lintas proses

Seperti halnya semua pertimbangan kinerja, pengukuran dan pengujian sangat penting. Idealnya telemetri harus dimasukkan ke dalam berbagai operasi untuk menentukan berapa lama waktu yang dibutuhkan. Penting untuk mengukur di seluruh rentang: misalnya, berapa lama waktu yang dibutuhkan untuk mengkonsumsi semua objek Orang untuk kueri tertentu di aplikasi yang dimuat di samping?

Teknik lain adalah pengujian beban variabel. Hal ini dapat dilakukan dengan menempatkan kait uji kinerja ke dalam aplikasi yang memperkenalkan beban penundaan variabel ke dalam pemrosesan server. Ini dapat mensimulasikan berbagai jenis beban dan reaksi aplikasi terhadap berbagai kinerja server. Sampel menggambarkan bagaimana menempatkan penundaan waktu ke dalam kode menggunakan teknik async yang tepat. Jumlah penundaan yang tepat untuk disuntikkan dan kisaran pengacakan untuk dimasukkan ke dalam beban buatan itu akan bervariasi menurut desain aplikasi dan lingkungan yang diantisipasi di mana aplikasi akan berjalan.

Proses pengembangan

Ketika Anda membuat perubahan pada server, perlu untuk memastikan setiap instans yang berjalan sebelumnya tidak lagi berjalan. COM pada akhirnya akan mengais-ngais prosesnya, tetapi timer rundown membutuhkan waktu lebih lama daripada yang efisien untuk pengembangan berulang. Dengan demikian, membunuh instance yang berjalan sebelumnya adalah langkah normal selama pengembangan. Ini mengharuskan pengembang melacak instance dllhost mana yang menghosting server.

Proses server dapat ditemukan dan dibunuh menggunakan Task Manager atau aplikasi pihak ketiga lainnya. Alat baris perintah TaskList.exe juga disertakan dan memiliki sintaks yang fleksibel, misalnya:

Perintah Tindakan
daftar tugas Daftar semua proses yang berjalan dalam perkiraan urutan waktu pembuatan, dengan proses yang paling baru dibuat di dekat bagian bawah.
daftar tugas /FI "IMAGENAME eq dllhost.exe" /M Mencantumkan info tentang semua instans dllhost.exe. Sakelar /M mencantumkan modul yang telah mereka muat.
daftar tugas /FI "PID eq 12564" /M Anda dapat menggunakan opsi ini untuk meminta dllhost.exe jika Anda tahu PID-nya.

Daftar modul untuk server broker harus mencantumkan clrhost.dll dalam daftar modul yang dimuat.

Sumber