Componenti Windows Runtime con C++/WinRT

Questo argomento spiega come usare C++/WinRT per creare e usare un componente Windows Runtime, un componente che è possibile chiamare da un'app di Windows universale creata con qualsiasi linguaggio Windows Runtime.

Esistono diversi motivi per creare un componente Windows Runtime in C++/WinRT.

  • Sfruttare i vantaggi in termini di prestazioni di C++ in operazioni complesse o intensive dal punto di vista del calcolo.
  • Usare nuovamente il codice C++ standard già scritto e testato.
  • Esporre la funzionalità Win32 in un'app UWP (Universal Windows Platform) scritta in C#, ad esempio.

In generale, quando si crea il componente C++/WinRT, è possibile usare tipi della libreria C++ standard e tipi predefiniti, ad eccezione del limite ABI (Application Binary Interface) in cui si passano dati da e verso il codice in un altro pacchetto .winmd. Al limite ABI usare i tipi Windows Runtime. Inoltre, nel codice C++/WinRT, usare tipi come delegato ed evento per implementare eventi che è possibile generare dal componente e gestire in un altro linguaggio. Per altre informazioni su C++/WinRT, vedere C++/WinRT.

Il resto di questo argomento spiega come creare un componente Windows Runtime in C++/WinRT e come usarlo da un'applicazione.

Il componente Windows Runtime che si creerà in questo argomento contiene una classe di runtime che rappresenta un termometro. L'argomento illustra anche un'app core che usa la classe di runtime del termometro e chiama una funzione per regolare la temperatura.

Nota

Per informazioni sull'installazione e sull'uso dell'Estensione C++/WinRT per Visual Studio (VSIX) e del pacchetto NuGet, che insieme forniscono il modello di progetto e il supporto della compilazione, vedi Supporto di Visual Studio per C++/WinRT.

Importante

Per i concetti essenziali e i termini che possono aiutarti a comprendere come usare e creare classi di runtime con C++/WinRT, vedi Usare API con C++/WinRT e Creare API con C++/WinRT.

Procedura consigliata per denominare le DLL del componente Windows Runtime

Importante

Questa sezione descrive la convenzione di denominazione che è consigliabile usare per il file .dll (DLL) in cui si crea il componente Windows Runtime. Si tratta della sequenza di attivazione che C++/WinRT segue quando si usa una classe di runtime da un componente Windows Runtime.

Quando si attiva una class factory, C++/WinRT tenta innanzitutto una chiamata a RoGetActivationFactory. In caso di errore, C++/WinRT tenta di trovare una DLL da caricare direttamente. L'attivazione di Windows Runtime è sempre basata su un nome di classe completo. La logica consiste nel rimuovere il nome della classe (dal nome completo della classe), quindi nel cercare una DLL denominata per lo spazio dei nomi completo rimanente. Se non si trova, rimuovere il nome del segmento più specifico e ripetere.

Pertanto, se la classe da attivare ha un nome completo Contoso.Instruments.ThermometerWRC.Thermometer e RoGetActivationFactory restituisce un errore, si cercherà innanzitutto Contoso.Instruments.ThermometerWRC.dll. Se non si trova, si cercherà Contoso.Instruments.dll, quindi Contoso.dll.

Quando si trova una DLL (in quella sequenza), si userà il punto di ingresso DllGetActivationFactory di quella DLL per tentare di ottenere direttamente la factory (anziché indirettamente tramite la funzione RoGetActivationFactory tentata prima). Anche in questo caso, il risultato finale è indistinguibile al chiamante e alla DLL.

Questo processo è completamente automatico, non è necessaria alcuna registrazione o alcuno strumento. Se si crea un componente Windows Runtime, è necessario usare una convenzione di denominazione per le DLL che funziona con il processo appena descritto. E se si usa un componente Windows Runtime che non è denominato correttamente, si ha la possibilità di rinominarlo come descritto.

Creare un componente Windows Runtime (ThermometerWRC)

Per iniziare, crea un nuovo progetto in Microsoft Visual Studio. Creare un progetto Componente Windows Runtime (C++/WinRT) e assegnare a esso il nome ThermometerWRC (per il "componente Windows Runtime termometro"). Assicurarsi che l'opzione Inserisci soluzione e progetto nella stessa directory sia deselezionata. Specificare come destinazione la versione più recente disponibile a livello generale, ovvero non l'anteprima, di Windows SDK. Assegnando al progetto il nome ThermometerWRC sarà più semplice seguire il resto dei passaggi descritti in questo argomento.

Per il momento, non compilare il progetto.

Il nuovo progetto contiene un file denominato Class.idl. In Esplora soluzioni rinomina il file Thermometer.idl, rinominando il file .idl vengono rinominati automaticamente anche i file .h e .cpp dipendenti. Sostituisci il contenuto di Thermometer.idl con il listato riportato di seguito.

// Thermometer.idl
namespace ThermometerWRC
{
    runtimeclass Thermometer
    {
        Thermometer();
        void AdjustTemperature(Single deltaFahrenheit);
    };
}

Salvare il file. Il progetto non verrà compilato completamente, ma è consigliabile procedere ora per generare i file del codice sorgente in cui si implementerà la casse runtime Thermometer. Esegui la compilazione adesso; a questo punto potrai ottenere errori di compilazione riguardanti l'impossibilità di trovare Class.h e Class.g.h.

Durante il processo di compilazione, viene eseguito lo strumento midl.exe per creare il file di metadati del componente Windows Runtime, ovvero \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd. Viene quindi eseguito lo strumento cppwinrt.exe, con l'opzione -component, per generare i file di codice sorgente utili per la creazione del componente. Questi file includono gli stub necessari per iniziare l'implementazione della classe di runtime Thermometer dichiarata nel file IDL. Gli stub sono \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.h e Thermometer.cpp.

Fai clic con il pulsante destro del mouse sul nodo del progetto e fai clic su Apri cartella in Esplora file. Verrà aperta la cartella del progetto in Esplora file. Qui copia i file stub Thermometer.h e Thermometer.cpp dalla cartella \ThermometerWRC\ThermometerWRC\Generated Files\sources\ alla cartella che contiene i file di progetto, ovvero \ThermometerWRC\ThermometerWRC\, e sostituisci i file nella destinazione. A questo punto apriamo Thermometer.h e Thermometer.cpp e implementiamo la classe di runtime. In Thermometer.h aggiungere un nuovo membro privato all'implementazione (non l'implementazione factory) di Thermometer.

// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
    struct Thermometer : ThermometerT<Thermometer>
    {
        ...

    private:
        float m_temperatureFahrenheit { 0.f };
    };
}
...

In Thermometer.cpp implementare il metodo AdjustTemperature come illustrato nell'elenco seguente.

// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
    void Thermometer::AdjustTemperature(float deltaFahrenheit)
    {
        m_temperatureFahrenheit += deltaFahrenheit;
    }
}

Verrà visualizzato static_assert nella parte superiore di Thermometer.h e Thermometer.cpp, che sarà necessario rimuovere prima che il progetto venga compilato. A questo punto, il progetto verrà compilato.

Se eventuali avvisi impediscono la compilazione, risolvili o imposta la proprietà del progetto C/C++>Generale>Considera gli avvisi come errori su No (/WX-) e compila nuovamente il progetto.

Creare un'app Core (ThermometerCoreApp) per testare il componente Windows Runtime

Creare ora una nuovo progetto (nella soluzione ThermometerWRC o in una nuova). Creare un progetto App Core (C++/WinRT) e assegnare a esso il nome ThermometerCoreApp. Se i due progetti si trovano nella stessa soluzione, impostare ThermometerCoreApp come progetto di avvio.

Nota

Come indicato in precedenza, il file di metadati Windows Runtime per il componente Windows Runtime (il cui progetto è stato nominato ThermometerWRC) viene creato nella cartella \ThermometerWRC\Debug\ThermometerWRC\. Il primo segmento di tale percorso è il nome della cartella che contiene il file di soluzione. Il segmento successivo è la sottodirectory di quella denominata Debug. L'ultimo segmento è la sottodirectory di quella denominata per il componente Windows Runtime. Se il progetto non è stato denominato ThermometerWRC, il file di metadati sarà presente nella cartella \<YourProjectName>\Debug\<YourProjectName>\.

A questo punto, nel progetto App Core (ThermometerCoreApp) aggiungere un riferimento e passare a \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (o aggiungere un riferimento da progetto a progetto, se i due progetti sono nella stessa soluzione). Fai clic su Aggiungi, quindi su OK. Creare ora ThermometerCoreApp. Nel caso improbabile in cui venga visualizzato un errore che indica che il file di payload readme.txt non esiste, escludere quel file dal progetto del componente Windows Runtime, ricompilarlo e quindi ricompilare ThermometerCoreApp.

Durante il processo di compilazione, viene eseguito lo strumento cppwinrt.exe per elaborare il file .winmd a cui viene fatto riferimento nei file di codice sorgente con i tipi proiettati per aiutarti durante l'uso del componente. L'intestazione per i tipi proiettati per le classi runtime del componente, ThermometerWRC.h, viene generata nella cartella \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\.

Includi questa intestazione in App.cpp.

// App.cpp
...
#include <winrt/ThermometerWRC.h>
...

In App.cpp aggiungere il codice seguente per creare un'istanza di un oggetto Thermometer (usando il costruttore predefinito del tipo proiettato) e chiamare un metodo sull'oggetto termometro.

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer m_thermometer;
    ...
    
    void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
    {
        m_thermometer.AdjustTemperature(1.f);
        ...
    }
    ...
};

Ogni volta che si fa clic sulla finestra, si incrementa la temperatura dell'oggetto termometro. È possibile impostare punti di interruzione se si vuole eseguire il codice per confermare che l'applicazione stia effettivamente chiamando il componente Windows Runtime.

Passaggi successivi

Per aggiungere altra funzionalità, o nuovi tipi di Windows Runtime, al componente Windows Runtime C++/WinRT, è possibile seguire gli stessi modelli mostrati in precedenza. Usare innanzitutto IDL per definire le funzionalità da esporre. Compilare il progetto in Visual Studio per generare un'implementazione stub. Completare l'implementazione in base alle esigenze. I metodi, le proprietà e gli eventi definiti in IDL sono visibili all'applicazione che usa il componente Windows Runtime. Per altre informazioni su IDL, vedere Introduzione a Microsoft Interface Definition Language 3.0.

Per un esempio di come aggiungere un evento al componente Windows Runtime, vedere Creare eventi in C++/WinRT.

Risoluzione dei problemi

Sintomo Rimedio
In un'app C++/WinRT, quando viene usato un componente Windows Runtime C# che usa XAML, il compilatore genera un errore "'MyNamespace_XamlTypeInfo': non è un membro di 'winrt::MyNamespace'"dove MyNamespace è il nome dello spazio dei nomi del componente Windows Runtime. Nel file pch.h dell'app C++/WinRT consumer aggiungi #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>sostituendo MyNamespace in base alle esigenze.