Bagikan melalui


Hasilkan proyeksi C# dari komponen C++/WinRT, distribusikan sebagai NuGet untuk aplikasi .NET

Dalam topik ini, kita membahas penggunaan C#/WinRT untuk menghasilkan assembly proyeksi C# .NET (atau interop) dari komponen C++/WinRT Windows Runtime, dan mendistribusikannya sebagai paket NuGet untuk aplikasi .NET.

Di .NET 6 dan yang lebih baru, konsumsi file metadata Windows (WinMD) tidak lagi didukung (lihat Dukungan bawaan untuk WinRT dihapus dari .NET). Sebagai gantinya, alat C#/WinRT dapat digunakan untuk menghasilkan rakitan proyeksi untuk file WinMD apa pun, yang kemudian memungkinkan konsumsi komponen WinRT dari aplikasi .NET. Rakitan proyeksi juga dikenal sebagai rakitan interop. Panduan ini menunjukkan kepada Anda cara melakukan hal berikut:

  • Gunakan paket C#/WinRT untuk menghasilkan proyeksi C# dari komponen C++/WinRT.
  • Distribusikan komponen, bersama dengan rakitan proyeksi, sebagai paket NuGet.
  • Gunakan paket NuGet dari aplikasi konsol .NET.

Prasyarat

Panduan ini dan sampel yang sesuai memerlukan alat dan komponen berikut:

  • Visual Studio 2022 (atau Visual Studio 2019) dengan paket pengembangan Universal Windows Platform yang terinstal. Dalam Detail Penginstalan>pengembangan Universal Windows Platform, periksa opsi alat C++ (v14x) untuk Universal Windows Platform.
  • .NET 6.0 SDK atau yang lebih baru.

Visual Studio 2019 saja. Ekstensi C++/WinRT VSIX, yang memberi Anda templat proyek C++/WinRT di Visual Studio. Templat proyek dibangun di Visual Studio 2022.

Kami akan menggunakan Visual Studio 2022 dan .NET 6 dalam panduan ini.

Penting

Selain itu, Anda harus mengunduh atau mengkloning kode sampel untuk topik ini dari sampel proyeksi C#/WinRT di GitHub. Kunjungi CsWinRT, dan klik tombol Kode hijau untuk mendapatkan URL git clone. Pastikan untuk membaca file README.md sebagai contoh.

Membuat komponen C++/WinRT Windows Runtime sederhana

Untuk mengikuti panduan ini, Anda harus terlebih dahulu memiliki komponen C++/WinRT Windows Runtime (WRC) untuk menghasilkan rakitan proyeksi C#.

Panduan ini menggunakan SimpleMathComponent WRC dari sampel proyeksi C#/WinRT di GitHub, yang sudah Anda unduh atau kloning. SimpleMathComponent dibuat dari templat proyek Visual Studio Komponen Runtime Windows (C++/WinRT) (yang dilengkapi dengan Visual Studio 2022, atau dengan ekstensi C++/WinRT VSIX).

Untuk membuka proyek SimpleMathComponent di Visual Studio, buka \CsWinRT\src\Samples\NetProjectionSample\CppWinRTComponentProjectionSample.sln file, yang akan Anda temukan di unduhan atau klon repositori.

Kode dalam proyek ini menyediakan fungsionalitas untuk operasi matematika dasar yang ditunjukkan dalam file header di bawah ini.

// SimpleMath.h
...
namespace winrt::SimpleMathComponent::implementation
{
    struct SimpleMath: SimpleMathT<SimpleMath>
    {
        SimpleMath() = default;
        double add(double firstNumber, double secondNumber);
        double subtract(double firstNumber, double secondNumber);
        double multiply(double firstNumber, double secondNumber);
        double divide(double firstNumber, double secondNumber);
    };
}

Anda dapat mengonfirmasi bahwa properti Kompatibel Desktop Windows diatur ke Ya untuk proyek komponen Windows Runtime C++/WinRT SimpleMathComponent. Untuk melakukannya, dalam properti proyek untuk SimpleMathComponent, di bawah Properti Konfigurasi>Umum>Default Proyek, atur properti Windows Desktop Compatible ke nilai Ya. Ini memastikan bahwa file biner runtime yang benar dimuat untuk menjalankan aplikasi desktop .NET.

halaman properti yang Kompatibel dengan Desktop

Untuk langkah-langkah lebih rinci tentang membuat komponen C++/WinRT dan membuat file WinMD, lihat komponen Windows Runtime dengan C++/WinRT.

Nota

Jika Anda menerapkan IInspectable::GetRuntimeClassName di komponen Anda, maka harus mengembalikan nama kelas WinRT yang valid. Karena C#/WinRT menggunakan string nama kelas untuk interop, nama kelas runtime yang salah akan memunculkan InvalidCastException.

Menambahkan proyeksi ke solusi komponen

Pertama, dengan solusi CppWinRTComponentProjectionSample yang masih terbuka di Visual Studio, hapus proyek SimpleMathProjection dari solusi tersebut. Kemudian hapus dari sistem file Anda folder SimpleMathProjection (atau ganti namanya jika Mau). Langkah-langkah tersebut diperlukan agar Anda dapat mengikuti panduan ini langkah demi langkah.

  1. Tambahkan proyek pustaka C# baru ke solusi Anda.

    1. Di Penjelajah Solusi, klik kanan pada node solusi Anda dan klik Tambah>Proyek Baru.
    2. Dalam kotak dialog Tambahkan proyek baru , ketik Pustaka Kelas di kotak pencarian. Pilih C# dari daftar bahasa, lalu pilih Windows dari daftar platform. Pilih templat proyek C# yang disebut hanya Pustaka Kelas (tanpa awalan maupun akhiran), dan klik Berikutnya.
    3. Beri nama proyek baru SimpleMathProjection. Lokasi harus sudah diatur ke folder \CsWinRT\src\Samples\NetProjectionSample yang sama dengan yang terdapat di folder SimpleMathComponent; tetapi pastikan bahwa demikian. Lalu, klik Berikutnya.
    4. Pada halaman Informasi tambahan , pilih .NET 6.0 (Dukungan jangka panjang), lalu pilih Buat.
  2. Hapus file Class1.cs stub dari proyek.

  3. Gunakan langkah-langkah di bawah ini untuk menginstal paket C#/WinRT NuGet.

    1. Di Penjelajah Solusi, klik kanan proyek SimpleMathProjection Anda dan pilih Kelola Paket NuGet.
    2. Di tab Telusuri , ketik atau tempelkan Microsoft.Windows.CsWinRT ke dalam kotak pencarian, di hasil pencarian pilih item dengan versi terbaru, lalu klik Instal untuk menginstal paket ke dalam proyek SimpleMathProjection .
  4. Tambahkan ke SimpleMathProjection referensi proyek ke proyek SimpleMathComponent . Di Penjelajah Solusi, klik kanan simpul Dependensi di bawah simpul proyek SimpleMathProjection, pilih Tambahkan Referensi Proyek, dan pilih proyek SimpleMathComponent>OK.

Jangan coba membangun proyek dulu. Kita akan melakukannya di langkah selanjutnya.

Sejauh ini, Solution Explorer Anda seharusnya terlihat mirip dengan ini (nomor versi Anda mungkin berbeda).

Solution Explorer memperlihatkan dependensi proyek proyeksi

Membangun proyek di luar sumber

Untuk solusi CppWinRTComponentProjectionSample dalam sampel proyeksi C#/WinRT (yang Anda unduh atau kloning dari GitHub, dan sekarang telah terbuka), lokasi output build dikonfigurasi dengan file Directory.Build.props untuk membangun dari sumber. Itu berarti bahwa file dari output build dihasilkan di luar folder sumber. Sebaiknya Anda membangun dari sumber saat menggunakan alat C#/WinRT. Itu mencegah pengkompilasi C# secara tidak sengaja mengambil semua file *.cs di bawah direktori akar proyek, yang dapat menyebabkan kesalahan jenis duplikat (misalnya saat mengkompilasi untuk beberapa konfigurasi dan/atau platform).

Meskipun ini sudah dikonfigurasi untuk solusi CppWinRTComponentProjectionSample, ikuti langkah-langkah di bawah ini untuk berlatih melakukan konfigurasi sendiri.

Untuk mengonfigurasi solusi Anda untuk membangun dari sumber:

  1. Dengan solusi CppWinRTComponentProjectionSample masih terbuka, klik kanan pada simpul solusi, dan pilih Tambahkan>Item Baru. Pilih item File XML , dan beri nama Directory.Build.props (tanpa .xml ekstensi). Klik Ya untuk menimpa file yang ada.

  2. Ganti konten Directory.Build.props dengan konfigurasi di bawah ini.

    <Project>
      <PropertyGroup>
        <BuildOutDir>$([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)'))</BuildOutDir>
        <OutDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin'))</OutDir>
        <IntDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj'))</IntDir>
      </PropertyGroup>
    </Project>
    
  3. Simpan dan tutup file Directory.Build.props .

Edit file proyek untuk menjalankan C#/WinRT

Sebelum dapat memanggil cswinrt.exe alat untuk menghasilkan rakitan proyeksi, Anda harus terlebih dahulu mengedit file proyek untuk menentukan beberapa properti proyek.

  1. Di Penjelajah Solusi, klik dua kali simpul SimpleMathProjection untuk membuka file proyek di editor.

  2. TargetFramework Perbarui elemen untuk menargetkan versi Windows SDK tertentu. Ini menambahkan dependensi perakitan perangkat lunak yang diperlukan untuk mendukung interoperabilitas dan proyeksi. Sampel ini menargetkan versi Windows SDK net6.0-windows10.0.19041.0 (juga dikenal sebagai Windows 10, versi 2004). Atur Platform elemen ke AnyCPU sehingga rakitan proyeksi yang dihasilkan dapat direferensikan dari arsitektur aplikasi apa pun. Untuk mengizinkan aplikasi referensi mendukung versi Windows SDK sebelumnya, Anda juga dapat mengatur TargetPlatformMinimumVersion properti .

    <PropertyGroup>
      <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
      <!-- Set Platform to AnyCPU to allow consumption of the projection assembly from any architecture. -->
      <Platform>AnyCPU</Platform>
    </PropertyGroup>
    

    Nota

    Untuk panduan ini dan kode sampel terkait, solusi dibuat untuk x64 dan Rilis. Perhatikan bahwa proyek SimpleMathProjection dikonfigurasi untuk membangun AnyCPU untuk semua konfigurasi arsitektur solusi.

  3. Tambahkan elemen kedua PropertyGroup (segera setelah yang pertama) yang mengatur beberapa properti C#/WinRT.

    <PropertyGroup>
      <CsWinRTIncludes>SimpleMathComponent</CsWinRTIncludes>
      <CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
    </PropertyGroup>
    

    Berikut adalah beberapa detail tentang pengaturan dalam contoh ini:

    • Properti CsWinRTIncludes menentukan namespace mana yang akan diproyeksikan.
    • Properti CsWinRTGeneratedFilesDir mengatur direktori output tempat file sumber proyeksi dihasilkan. Properti ini ditetapkan ke OutDir, yang didefinisikan dalam Directory.Build.props dari bagian di atas.
  4. Simpan dan tutup file SimpleMathProjection.csproj , dan klik muat ulang proyek jika perlu.

Membuat paket NuGet dengan proyeksi

Untuk mendistribusikan rakitan proyeksi untuk pengembang aplikasi .NET, Anda dapat secara otomatis membuat paket NuGet saat membangun solusi dengan menambahkan beberapa properti proyek tambahan. Untuk target .NET, paket NuGet perlu menyertakan rakitan proyeksi dan rakitan implementasi dari komponen.

  1. Gunakan langkah-langkah di bawah ini untuk menambahkan file spesifikasi NuGet (.nuspec) ke proyek SimpleMathProjection .

    1. Di Solution Explorer, klik kanan pada simpul SimpleMathProjection, pilih Tambah>Folder Baru, dan beri nama folder tersebut nuget.
    2. Klik kanan folder nuget , pilih TambahkanItem Baru, pilih file XML , dan beri nama SimpleMathProjection.nuspec.
  2. Di Penjelajah Solusi, klik dua kali simpul SimpleMathProjection untuk membuka file proyek di editor. Tambahkan grup properti berikut ke SimpleMathProjection.csproj yang sekarang terbuka (segera setelah dua elemen yang ada PropertyGroup ) untuk menghasilkan paket secara otomatis. Properti ini menentukan NuspecFile dan direktori untuk menghasilkan paket NuGet.

    <PropertyGroup>
      <GeneratedNugetDir>.\nuget\</GeneratedNugetDir>
      <NuspecFile>$(GeneratedNugetDir)SimpleMathProjection.nuspec</NuspecFile>
      <OutputPath>$(GeneratedNugetDir)</OutputPath>
      <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    </PropertyGroup>
    

    Nota

    Jika Anda lebih suka membuat paket secara terpisah, maka Anda juga dapat memilih untuk menjalankan nuget.exe alat dari baris perintah. Untuk informasi selengkapnya tentang membuat paket NuGet, lihat Membuat paket menggunakan CLI nuget.exe.

  3. Buka file SimpleMathProjection.nuspec untuk mengedit properti pembuatan paket, dan tempelkan kode berikut. Cuplikan di bawah ini adalah contoh spesifikasi NuGet untuk mendistribusikan SimpleMathComponent ke beberapa kerangka kerja target. Perhatikan bahwa rakitan proyeksi, SimpleMathProjection.dll, ditentukan alih-alih SimpleMathComponent.winmd untuk target lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll. Perilaku ini baru di .NET 6 dan yang lebih baru, dan diaktifkan oleh C#/WinRT. Rakitan implementasi, SimpleMathComponent.dll, juga harus didistribusikan, dan akan dimuat pada runtime.

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
      <metadata>
        <id>SimpleMathComponent</id>
        <version>0.1.0-prerelease</version>
        <authors>Contoso Math Inc.</authors>
        <description>A simple component with basic math operations</description>
        <dependencies>
          <group targetFramework="net6.0-windows10.0.19041.0" />
          <group targetFramework=".NETCoreApp3.0" />
          <group targetFramework="UAP10.0" />
          <group targetFramework=".NETFramework4.6" />
        </dependencies>
      </metadata>
      <files>
        <!--Support .NET 6, .NET Core 3, UAP, .NET Framework 4.6, C++ -->
        <!--Architecture-neutral assemblies-->
        <file src="..\..\_build\AnyCPU\Release\SimpleMathProjection\bin\SimpleMathProjection.dll" target="lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\netcoreapp3.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\uap10.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\net46\SimpleMathComponent.winmd" />
        <!--Architecture-specific implementation DLLs should be copied into RID-relative folders-->
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x64\native\SimpleMathComponent.dll" />
        <!--To support x86 and Arm64, build SimpleMathComponent for those other architectures and uncomment the entries below.-->
        <!--<file src="..\..\_build\Win32\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x86\native\SimpleMathComponent.dll" />-->
        <!--<file src="..\..\_build\arm64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-arm64\native\SimpleMathComponent.dll" />-->
      </files>
    </package>
    

    Nota

    SimpleMathComponent.dll, rakitan implementasi untuk komponen, khusus arsitektur. Jika Anda mendukung platform lain (misalnya, x86 atau Arm64), maka Anda harus terlebih dahulu membangun SimpleMathComponent untuk platform yang diinginkan, dan menambahkan file rakitan ini ke folder RELATIF RID yang sesuai. Rakitan proyeksi SimpleMathProjection.dll dan komponen SimpleMathComponent.winmd keduanya netral arsitektur.

  4. Simpan dan tutup file yang baru saja Anda edit.

Bangun solusi untuk menghasilkan proyeksi dan paket NuGet

Sebelum membangun solusi, pastikan memeriksa pengaturan Configuration Manager di Visual Studio, pada bagian BuildConfiguration Manager. Untuk panduan ini, atur Konfigurasi ke Rilis dan Platform ke x64 untuk solusi tersebut.

Pada titik ini Anda sekarang dapat membangun solusi. Klik kanan pada simpul solusi Anda dan pilih Bangun Solusi. Ini pertama-tama akan membangun proyek SimpleMathComponent , lalu proyek SimpleMathProjection . Komponen WinMD dan rakitan implementasi (SimpleMathComponent.winmd dan SimpleMathComponent.dll), file sumber proyeksi, dan rakitan proyeksi (SimpleMathProjection.dll), semuanya akan dihasilkan di bawah direktori output _build . Anda juga akan dapat melihat paket NuGet yang dihasilkan, SimpleMathComponent0.1.0-prerelease.nupkg, di bawah folder \SimpleMathProjection\nuget .

Penting

Jika salah satu file yang disebutkan di atas tidak dihasilkan, buat solusi untuk kedua kalinya. Anda mungkin juga perlu menutup dan membuka kembali solusi tersebut sebelum menyusun ulang.

Anda mungkin perlu menutup dan membuka kembali solusi agar .nupkg muncul di Visual Studio seperti yang diilustrasikan (atau cukup pilih lalu batal pilih Tampilkan Semua File).

Solution Explorer memperlihatkan pembuatan proyeksi

Mereferensikan paket NuGet dalam aplikasi konsol C# .NET 6

Untuk menggunakan SimpleMathComponent dari proyek .NET, Anda dapat dengan mudah menambahkan referensi pada proyek .NET baru ke paket NuGet SimpleMathComponent0.1.0-prerelease.nupkg yang kami buat di bagian sebelumnya. Langkah-langkah berikut menunjukkan cara melakukannya dengan membuat aplikasi Konsol sederhana dalam solusi terpisah.

  1. Gunakan langkah-langkah di bawah ini untuk membuat solusi baru yang berisi proyek Aplikasi Konsol C# (membuat proyek ini dalam solusi baru memungkinkan Anda memulihkan paket SimpleMathComponent NuGet secara independen).

    Penting

    Kami akan membuat proyek aplikasi konsol baru ini di folder , yang dapat Anda temukan pada sampel proyeksi C#/WinRT .

    1. Dalam instans baru Visual Studio, pilih File >Baru>Proyek.
    2. Dalam kotak dialog Buat proyek baru , cari templat proyek Aplikasi Konsol . Pilih templat proyek C# yang disebut hanya Aplikasi Konsol (tanpa awalan atau akhiran), dan klik Berikutnya. Jika Anda menggunakan Visual Studio 2019, maka templat proyeknya adalah Aplikasi Konsol.
    3. Beri nama proyek baru SampleConsoleApp, atur lokasinya ke folder \CsWinRT\src\Samples\NetProjectionSample yang sama dengan folder SimpleMathComponent dan folder SimpleMathProjection, dan klik Next.
    4. Pada halaman Informasi tambahan , pilih .NET 6.0 (Dukungan jangka panjang), lalu pilih Buat.
  2. Di Penjelajah Solusi, klik dua kali simpul SampleConsoleApp untuk membuka file proyek SampleConsoleApp.csproj , dan edit TargetFramework properti dan Platform sehingga terlihat seperti yang ditunjukkan dalam daftar berikut. Tambahkan elemen Platform jika tidak ada.

    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
      <Platform>x64</Platform>
    </PropertyGroup>
    
  3. Dengan file proyek SampleConsoleApp.csproj masih terbuka, berikutnya kita akan menambahkan referensi ke proyek SampleConsoleApp paket SimpleMathComponent NuGet. Untuk memulihkan SimpleMathComponent NuGet saat membangun proyek, Anda dapat menggunakan properti dengan jalur ke folder nuget dalam solusi komponen Anda. Salin konfigurasi berikut, dan tempelkan ke SampleConsoleApp.csproj (di Project dalam elemen ).

    <PropertyGroup>
      <RestoreSources>
        https://api.nuget.org/v3/index.json;
        ../SimpleMathProjection/nuget
      </RestoreSources>
    </PropertyGroup>
    
    <ItemGroup>
      <PackageReference Include="SimpleMathComponent" Version="0.1.0-prerelease" />
    </ItemGroup>
    

    Penting

    Jalur RestoreSources untuk paket SimpleMathComponent yang ditunjukkan di atas ditetapkan ke ../SimpleMathProjection/nuget. Jalur tersebut benar asalkan Anda mengikuti langkah-langkah dalam panduan ini, sehingga proyek SimpleMathComponent dan SampleConsoleApp keduanya berada di folder yang sama ( NetProjectionSample folder, dalam hal ini). Jika Anda telah melakukan sesuatu yang berbeda, maka Anda harus menyesuaikan jalur tersebut dengan sesuai. Atau, Anda dapat menambahkan umpan paket NuGet lokal ke solusi Anda.

  4. Edit file Program.cs untuk menggunakan fungsionalitas yang disediakan oleh SimpleMathComponent.

    var x = new SimpleMathComponent.SimpleMath();
    Console.WriteLine("Adding 5.5 + 6.5 ...");
    Console.WriteLine(x.add(5.5, 6.5).ToString());
    
  5. Simpan dan tutup file yang baru saja Anda edit, dan buat dan jalankan aplikasi konsol. Anda akan melihat output di bawah ini.

    Output konsol NET5

Masalah yang diketahui

  • Saat membangun proyeksi, Anda mungkin melihat kesalahan seperti: Kesalahan MSB3271 Ada ketidakcocokan antara arsitektur prosesor proyek yang dibangun "MSIL" dan arsitektur prosesor, "x86", dari file implementasi "..\SimpleMathComponent.dll" untuk ".. \SimpleMathComponent.winmd". Ketidakcocokan ini dapat menyebabkan kegagalan runtime. Pertimbangkan untuk mengubah arsitektur prosesor yang ditargetkan dari proyek Anda melalui Configuration Manager sehingga dapat menyelaraskan arsitektur prosesor antara file proyek dan implementasi Anda, atau pilih file winmd dengan file implementasi yang memiliki arsitektur prosesor yang cocok dengan arsitektur prosesor yang ditargetkan dari proyek Anda. Untuk mengatasi kesalahan ini, tambahkan properti berikut ke file proyek pustaka C# Anda:
    <PropertyGroup>
        <!-- Workaround for MSB3271 error on processor architecture mismatch -->
        <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    </PropertyGroup>
    

Pertimbangan lebih lanjut

Rakitan proyeksi C# (atau interop) yang kami tunjukkan cara membuat dalam topik ini cukup sederhana—tidak memiliki dependensi pada komponen lain. Tetapi untuk menghasilkan proyeksi C# untuk komponen C++/WinRT yang memiliki referensi ke jenis Windows App SDK, dalam proyeksi, Anda perlu menambahkan referensi ke paket Windows App SDK NuGet. Jika ada referensi seperti itu yang hilang, maka Anda akan melihat kesalahan seperti "Jenis <T> tidak dapat ditemukan".

Hal lain yang kita lakukan dalam topik ini adalah mendistribusikan proyeksi sebagai paket NuGet. itu saat ini diperlukan.

Sumber Daya