Komponen Windows Runtime broker untuk aplikasi UWP yang dimuat di samping

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

Pendahuluan

Catatan Kode sampel yang menyertai makalah ini dapat diunduh untuk Visual Studio 2015 & 2017. Templat Microsoft Visual Studio untuk membangun Komponen Windows Runtime Broker dapat diunduh di sini: Templat Visual Studio 2015 yang menargetkan Universal Windows Apps untuk Windows 10

Windows menyertakan fitur baru yang disebut Komponen Windows Runtime Broker untuk aplikasi yang dimuat di samping. Kami menggunakan istilah IPC (komunikasi antarproses) untuk menjelaskan kemampuan untuk 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 sebagai aplikasi dan aplikasi database yang menggunakan Layanan NT di Windows berbagi arsitektur multi-proses yang serupa.

Pemuatan samping 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, penyiapan, dan layanan. Dengan demikian, model pemuatan samping adalah persyaratan dari mereka yang akan menggunakan fitur ini dan detail implementasi penting.

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

Terakhir, mengingat penetrasi yang luar biasa dari runtime .NET 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 untuk runtime .NET secara eksklusif.

Komponen aplikasi

Catatan 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 menjadi "headless" (yaitu tidak berisi UI). Tampilan akan sepenuhnya terkandung dalam aplikasi perusahaan yang dimuat di samping. Meskipun tidak ada persyaratan bahwa aplikasi ini dibangun dengan konstruksi "model tampilan", 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 hibrid antara CLR yang menargetkan UWP karena format komunikasi antar-proses terdiri dari jenis dan kelas UWP, sementara komponen desktop diizinkan untuk memanggil semua bagian pustaka kelas runtime .NET. Dampak pada proyek Visual Studio akan dijelaskan secara rinci nanti. Konfigurasi hibrid 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 jenis UWP. Ini melibatkan mendeklarasikan satu atau beberapa kelas C# yang dapat mewakili UWP. Lihat topik MSDN Membuat komponen Windows Runtime di C# dan Visual Basic untuk persyaratan tertentu dalam membuat Windows Runtime Class menggunakan C#.

Catatan Enums tidak didukung dalam kontrak komponen Windows Runtime antara komponen desktop dan aplikasi yang dimuat samping saat ini.

Aplikasi yang dimuat samping

Aplikasi yang dimuat samping adalah aplikasi UWP normal dalam setiap hal kecuali satu: aplikasi ini dimuat samping alih-alih diinstal melalui Microsoft Store. Sebagian besar mekanisme penginstalan identik: manifes dan kemasan aplikasi serupa (satu tambahan untuk 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 normal bahwa aplikasi yang dimuat di samping lulus uji sertifikasi WACK yang disertakan dalam menu Proyek / Toko di Visual Studio

Catatan Side-loading dapat diaktifkan di Pengaturan-> Pembaruan & keamanan -> Untuk pengembang.

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

Instancing server dan AppDomains

Setiap aplikasi yang dimuat di sisi menerima instans sendiri dari server App Broker (yang disebut "multi-instancing"). Kode server berjalan di dalam satu AppDomain. Ini memungkinkan untuk memiliki beberapa versi pustaka 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 dibagikan di antara beberapa instans server App Broker dengan mengarahkan beberapa aplikasi ke direktori server yang sama. Masih akan ada beberapa instans server App Broker tetapi mereka akan menjalankan kode yang identik. Semua komponen implementasi yang digunakan dalam satu aplikasi harus ada di jalur yang sama.

Menentukan kontrak

Langkah pertama dalam membuat aplikasi menggunakan fitur ini adalah membuat kontrak antara aplikasi yang dimuat samping dan komponen desktop. Ini harus dilakukan secara eksklusif menggunakan jenis Windows Runtime. Untungnya, ini mudah dinyatakan menggunakan kelas C#. Namun, ada pertimbangan performa penting saat menentukan percakapan ini, yang dibahas di 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 antarproses. 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 diinstansiasi 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 ke Komponen Runtime Windows.

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

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

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

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

Ini akan dilakukan oleh skrip berikut. Tambahkan skrip ke baris perintah peristiwa Pasca-build, dalam proyek Properti>Bangun Peristiwa.

Perhatikan bahwa skrip berbeda berdasarkan versi Windows yang 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 diangkut tangan (disalin) ke setiap proyek aplikasi yang dimuat samping dan direferensikan. Ini akan dijelaskan lebih lanjut di bagian berikutnya. Struktur proyek yang diwujudkan dalam aturan build di atas memastikan bahwa implementasi dan winmd referensi berada dalam direktori yang dipisahkan dengan jelas dalam hierarki build untuk menghindari kebingungan.

Aplikasi yang dimuat secara terperinci

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

<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 adalah inProcessServer karena ada beberapa entri dalam kategori outOfProcessServer yang tidak berlaku untuk konfigurasi aplikasi ini. Perhatikan bahwa <komponen Jalur> harus selalu berisi clrhost.dll (namun ini tidak diberlakukan dan menentukan nilai yang berbeda akan gagal dengan cara yang tidak ditentukan).

Bagian <ActivatableClass> sama dengan RuntimeClass benar dalam proses yang lebih disukai oleh komponen Windows Runtime dalam paket aplikasi. <ActivatableClassAttribute> adalah elemen baru, dan atribut Name="DesktopApplicationPath" dan Type="string" wajib dan invariant. Atribut Nilai menunjuk ke lokasi tempat winmd implementasi komponen desktop berada (detail selengkapnya 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 namespace layanan.

Seperti disebutkan di bagian "Menentukan 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 lalu dialog Referensi Proyek digunakan (klik tombol Telusuri.. ) 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.

Perhatikan Sangat penting untuk menggunakan referensi winmd di aplikasi yang dimuat samping. Jika Anda secara tidak sengaja membawa winmd implementasi ke direktori aplikasi yang dimuat di samping dan mereferensikannya, Anda kemungkinan 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 dalam <ActivatableClassAttribute Value="path"> . Seperti disebutkan sebelumnya, App Broker hanya mendukung 32-bit sehingga %ProgramFiles% akan diselesaikan ke C:\Program Files (x86) jika aplikasi dijalankan pada OS 64-bit.

Detail server IPC desktop

Dua bagian sebelumnya menjelaskan deklarasi kelas dan mekanisme pengangkutan referensi winmd 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 menggunakan 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 hibrid antara keduanya. Akibatnya, bagian referensi dibangun dengan sangat hati-hati untuk menyatukan dua profil ini.

Proyek aplikasi UWP normal tidak berisi referensi proyek eksplisit karena keseluruhan permukaan WINDOWS Runtime API 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 "Desktop\Class Library", 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 eferensi yang cermat yang penting untuk operasi server hibrid ini yang tepat. Protokolnya adalah membuka file .csproj (seperti yang dijelaskan dalam cara mengedit outputtype proyek) dan menambahkan referensi ini seperlunya.

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

  • Panggilan metode

  • Sumber Peristiwa Runtime Windows menurut komponen desktop

  • Operasi Asinkron Runtime Windows

  • Mengembalikan array dari jenis dasar

Pemasangan

Untuk menginstal aplikasi, salin winmd implementasi ke direktori yang benar yang ditentukan dalam manifes aplikasi yang dimuat samping terkait: <ActivatableClassAttribute's> Value="path". Salin juga file dukungan terkait dan dll proksi/stub (detail terakhir ini tercakup di bawah). Gagal menyalin winmd implementasi ke lokasi direktori server akan menyebabkan semua panggilan aplikasi yang dimuat samping ke yang baru pada RuntimeClass akan melemparkan kesalahan "kelas tidak terdaftar". Kegagalan untuk menginstal proksi/stub (atau gagal mendaftar) akan menyebabkan semua panggilan gagal tanpa nilai yang dikembalikan. Kesalahan terakhir ini sering tidak terkait dengan pengecualian yang terlihat. Jika pengecualian diamati karena kesalahan konfigurasi ini, pengecualian mungkin merujuk ke "cast tidak valid".

Pertimbangan implementasi server

Server Windows Runtime desktop dapat dianggap sebagai berbasis "pekerja" atau "tugas". Setiap panggilan ke server beroperasi pada utas non-UI dan semua kode harus sadar dan aman. Bagian mana dari aplikasi yang dimuat di samping yang memanggil fungsionalitas server juga penting. Sangat penting untuk selalu menghindari panggilan kode jangka panjang 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 asinkron di area permukaan publik server dan implementasi.

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

Asinkron Windows Runtime 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 dijalankan dengan cukup cepat sehingga memblokir utas UI tidak menjadi perhatian. Namun, setiap panggilan yang melibatkan I/O dalam bentuk apa pun (ini termasuk 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 dianjurkan dalam arsitektur aplikasi ini karena alasan performa. Ini tercakup lebih mendalam di bagian berikut.

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

public IAsyncOperation<int> FindElementAsync(int input)

Ini mendeklarasikan operasi asinkron Windows Runtime yang mengembalikan bilangan bulat. Implementasi operasi asinkron biasanya mengambil formulir:

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

Catatan Adalah umum untuk menunggu beberapa operasi lain yang berpotensi berjalan lama saat 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 metode asinkron ini dapat menunggu operasi ini seperti operasi sinkron Windows Runtime lainnya.

Memanggil fungsionalitas server dari utas latar belakang aplikasi

Karena khas 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 beberapa batch data dari server dapat dilakukan dari utas latar belakang. Ketika hasilnya benar-benar diambil, batch 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 proksi Windows Runtime

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

Membuat proksi di Visual Studio

Proses untuk membuat dan mendaftarkan proksi dan stub untuk digunakan di dalam paket aplikasi UWP reguler dijelaskan dalam topik Meningkatkan Peristiwa di Komponen Runtime Windows. Langkah-langkah yang dijelaskan dalam artikel ini lebih rumit daripada proses yang dijelaskan di bawah ini karena melibatkan pendaftaran proksi/stub di dalam paket aplikasi (dibandingkan dengan mendaftarkannya secara global).

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

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

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 "Menentukan Kontrak" berisi perintah Post-Build yang menjalankan winmdidl.exe, midl.exe, mdmerge.exe, dan sebagainya. Salah satu output dari langkah midl dari 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 keempat file yang dihasilkan ini ke proyek "MyWinRTProxy".

Langkah 6: Tambahkan file def ke proyek "MyWinRTProxy" (Project > Add New Item > Code > Module-Definition File) dan perbarui konten menjadi:

LIBRARY MyWinRTComponent.Proxies.dll

EXPORTS

DllCanUnloadNow PRIVATE

DllGetClassObject PRIVATE

DllRegisterServer PRIVATE

DllUnregisterServer PRIVATE

Langkah 7: Buka properti untuk proyek "MyWinRTProxy":

Nama Target Umum > Properti > Kompfigurasi :

MyWinRTComponent.Proxies

Tambahkan Definisi Praproscesor > C/C++ >

"WIN32;_WINDOWS; REGISTER_PROXY_DLL"

Header C/C++ > Yang Telah Dikompilasi Sebelumnya: Pilih "Tidak Menggunakan Header yang Telah Dikompilasi"

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

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

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

Langkah 8: Bangun proyek "MyWinRTProxy".

Menyebarkan proksi

Proksi harus terdaftar secara global. Cara paling sederhana untuk melakukan ini adalah dengan meminta proses penginstalan Anda memanggil DllRegisterServer di dll proksi. Perhatikan bahwa karena fitur ini hanya mendukung server yang dibuat untuk x86 (yaitu tidak ada dukungan 64-bit), konfigurasi paling sederhana adalah menggunakan server 32-bit, proksi 32-bit, dan aplikasi yang dimuat samping 32-bit. Proksi biasanya berada di samping winmd implementasi untuk komponen desktop.

Satu langkah konfigurasi tambahan harus dilakukan. Agar proses yang dimuat samping memuat dan menjalankan proksi, 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/stub dll berada:

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

Pola dan performa

Sangat penting bahwa performa transportasi lintas proses dipantau dengan hati-hati. Panggilan lintas proses setidaknya dua kali lebih mahal daripada panggilan dalam proses. Membuat percakapan "cerewet" lintas proses atau melakukan transfer berulang objek besar seperti gambar bitmap, dapat menyebabkan performa 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 lalu gunakan CoreWindowDispatcher untuk mendapatkan hasilnya ke utas UI jika perlu.

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

  • Transfer massal hasil mengurangi obrolan lintas proses. Ini biasanya dilakukan dengan menggunakan konstruksi Array Runtime Windows.

  • Mengembalikan Daftar<T> di mana T adalah objek dari operasi asinkron atau pengambilan properti, akan menyebabkan banyak obrolan lintas proses. Misalnya, asumsikan Anda mengembalikanobjek Daftar< Orang>. Setiap perulangan lulus akan menjadi panggilan lintas proses. Setiap objek Orang yang dikembalikan diwakili oleh proksi dan setiap panggilan ke metode atau properti pada objek individual tersebut akan menghasilkan panggilan lintas proses. Jadi Daftar< "tidak bersalah Orang> objek di mana Hitungan besar akan menyebabkan sejumlah besar panggilan lambat. Hasil performa yang lebih baik dari transfer massal struktur konten dalam array. Misalnya:

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

Kemudian kembalikan PersonStruct[] alih-alih List<PersonObject>. Ini mendapatkan semua data dalam satu proses silang "hop"

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

Teknik lain adalah pengujian beban variabel. Ini dapat dilakukan dengan menempatkan kait pengujian performa ke dalam aplikasi yang memperkenalkan beban penundaan variabel ke dalam pemrosesan server. Ini dapat mensimulasikan berbagai jenis beban dan reaksi aplikasi terhadap berbagai performa server. Sampel ini menggambarkan cara memasukkan penundaan waktu ke dalam kode menggunakan teknik asinkron yang tepat. Jumlah penundaan yang tepat untuk disuntikkan dan rentang pengacakan untuk dimasukkan ke dalam beban buatan tersebut akan bervariasi menurut desain aplikasi dan lingkungan yang diantisipasi tempat 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 proses, tetapi timer rundown membutuhkan waktu lebih lama daripada yang efisien untuk pengembangan berulang. Dengan demikian, membunuh instans yang dijalankan sebelumnya adalah langkah normal selama pengembangan. Ini mengharuskan pengembang melacak instans dllhost mana yang menghosting server.

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

Perintah Perbuatan
daftar tugas Mencantumkan semua proses yang sedang berjalan dalam perkiraan urutan waktu pembuatan, dengan proses yang terakhir dibuat di dekat bagian bawah.
tasklist /FI "IMAGENAME eq dllhost.exe" /M Mencantumkan info pada semua instans dllhost.exe. Sakelar /M mencantumkan modul yang telah dimuat.
daftar tugas /FI "PID eq 12564" /M Anda dapat menggunakan opsi ini untuk mengkueri dllhost.exe jika Anda mengetahui PID-nya.

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

Sumber daya