Veelgestelde vragen over C++/WinRT

Antwoorden op vragen die u waarschijnlijk hebt over het ontwerpen en gebruiken van Windows Runtime API's met C++/WinRT.

Belangrijk

Zie Nieuws en wijzigingen in C++/WinRT in C++/WinRT 2.0 voor releaseopmerkingen.

Note

Als uw vraag betrekking heeft op een foutbericht dat u hebt gezien, raadpleegt u ook het onderwerp Probleemoplossing C++/WinRT .

Waar vind ik C++/WinRT-voorbeeld-apps?

Hoe kan ik mijn C++/WinRT-project opnieuw targeten naar een latere versie van de Windows SDK?

Waarom wordt mijn nieuwe project niet gecompileerd, nu ik ben verplaatst naar C++/WinRT 2.0?

Zie Nieuws en wijzigingen in C++/WinRT 2.0 voor de volledige set wijzigingen (inclusief belangrijke wijzigingen). Als u bijvoorbeeld een op bereik gebaseerde for gebruikt voor een Windows Runtime-verzameling, dan moet u nu #include <winrt/Windows.Foundation.Collections.h>.

Waarom wordt mijn nieuwe project niet gecompileerd? Ik gebruik Visual Studio 2017 (versie 15.8.0 of hoger) en SDK-versie 17134

Als u Visual Studio 2017 (versie 15.8.0 of hoger) gebruikt en gericht bent op de Windows SDK-versie 10.0.17134.0 (Windows 10, versie 1803) en vervolgens kan een nieuw C++/WinRT-project niet worden gecompileerd met de fout 'fout C3861: 'from_abi': id niet gevonden' en met andere fouten die afkomstig zijn uit base.h. De oplossing is om ofwel een latere (meer conforme) versie van de Windows SDK als doel te gebruiken, of de projecteigenschap C/C++>Taal>Conformiteitsmodus: Nee in te stellen (ook: als /permissive- voorkomt in de projecteigenschap C/C++>Opdrachtregel onder Extra opties, verwijder deze dan).

Hoe los ik de buildfout op: 'De C++/WinRT VSIX biedt geen ondersteuning meer voor projectbuilds. Voeg een projectreferentie toe aan het Microsoft.Windows.CppWinRT NuGet-pakket"?

Installeer de Microsoft.Windows. CppWinRT NuGet-pakket in uw project. Zie Eerdere versies van de VSIX-extensie voor meer informatie.

Hoe kan ik de build-ondersteuning aanpassen in het NuGet-pakket?

Ondersteuning voor C++/WinRT-builds (props/targets) is gedocumenteerd in de readme van het Microsoft.Windows.CppWinRT NuGet-pakket.

Wat zijn de vereisten voor de C++/WinRT-Visual Studio-extensie (VSIX)?

Zie Visual Studio ondersteuning voor C++/WinRT voor versie 1.0.190128.4 van de VSIX-extensie en hoger. Zie Eerdere versies van de VSIX-extensie voor andere versies.

Wat is een runtimeklasse?

Een runtimeklasse is een type dat kan worden geactiveerd en gebruikt via moderne COM-interfaces, meestal over uitvoerbare grenzen. Een runtimeklasse kan echter ook worden gebruikt in de compilatie-eenheid die deze implementeert. U declareert een runtimeklasse in Interface Definition Language (IDL) en u kunt deze implementeren in standaard C++ met behulp van C++/WinRT.

Wat betekenen het verwachte type en het implementatietype?

Als u alleen een Windows Runtime -klasse (runtimeklasse) gebruikt, hebt u uitsluitend te maken met projecttypen. C++/WinRT is een taalprojectie, dus geprojecteerde typen maken deel uit van het oppervlak van de Windows Runtime die in C++ worden geprojecteerd met C++/WinRT. Zie API's gebruiken met C++/WinRT voor meer informatie.

Het implementatietype bevat de implementatie van een runtimeklasse, dus deze is alleen beschikbaar in het project waarmee de runtimeklasse wordt geïmplementeerd. Wanneer u werkt in een project dat runtimeklassen implementeert (een Windows Runtime-onderdeelproject of een project dat gebruikmaakt van XAML UI), is het belangrijk dat u vertrouwd bent met het onderscheid tussen uw implementatietype voor een runtimeklasse en het verwachte type dat de runtimeklasse vertegenwoordigt die is geprojecteerd in C++/WinRT. Zie Author-API's met C++/WinRT voor meer informatie.

Moet ik een constructor declareren in de IDL van mijn runtimeklasse?

Alleen als de runtimeklasse is ontworpen voor gebruik van buiten de compilatie-eenheid (dit is een Windows Runtime onderdeel dat is bedoeld voor algemeen gebruik door Windows Runtime client-apps). Zie Constructors van runtime-klassen voor volledige informatie over het doel en de gevolgen van het declareren van constructors in IDL.

Waarom geeft de compiler de foutmelding "C3779: consume_Something: een functie die 'auto' retourneert, kan niet worden gebruikt voordat deze is gedefinieerd"?

U gebruikt een Windows Runtime object zonder dat u eerst het bijbehorende headerbestand voor de naamruimte hebt opgenomen. Neem de header op die is benoemd voor de naamruimte van de API en bouw opnieuw. Zie C++/WinRT-projectieheaders voor meer informatie.

Waarom geeft de linker me de foutmelding 'LNK2019: niet-opgelost extern symbool'?

Als het niet-opgeloste symbool een Windows Runtime gratis functie is, zoals RoInitialize, moet u expliciet de windowsApp.lib-paraplubibliotheek in uw project koppelen. De C++/WinRT-projectie is afhankelijk van sommige van deze gratis (niet-lid) functies en toegangspunten. Als u een van de projectsjablonen C++/WinRT Visual Studio Extension (VSIX) voor uw toepassing gebruikt, wordt deze WindowsApp.lib automatisch aan u gekoppeld. Zo niet, dan kunt u projectlinkinstellingen gebruiken om het toe te voegen, of het in de broncode opnemen.

#pragma comment(lib, "windowsapp")

Het is belangrijk dat u alle linkerfouten die u kunt oplossen, oplost door WindowsApp.lib te linken in plaats van een alternatieve bibliotheek voor statisch linken, omdat uw toepassing anders niet slaagt voor de Windows-app Certification Kit-tests die door Visual Studio en de Microsoft Store worden gebruikt om inzendingen te valideren (wat betekent dat uw toepassing daardoor niet succesvol in de Microsoft Store kan worden opgenomen).

Als het niet-opgeloste symbool een constructor is, bent u misschien vergeten het headerbestand voor de naamruimte op te nemen voor de klasse die wordt gemaakt. Neem de header op die is benoemd voor de naamruimte van de klasse en bouw opnieuw. Zie C++/WinRT-projectieheaders voor meer informatie.

Waarom krijg ik een uitzondering "klasse is niet geregistreerd"?

In dit geval is het symptoom dat u bij het maken van een runtimeklasse of het openen van een statisch lid een uitzondering ziet die tijdens runtime is gegenereerd met een HRESULT-waarde van REGDB_E_CLASSNOTREGISTERED.

Een van de oorzaken kan zijn dat uw Windows Runtime onderdeel niet kan worden geladen. Zorg ervoor dat het Windows Runtime metagegevensbestand van het onderdeel (.winmd) dezelfde naam heeft als het binaire onderdeel (de.dll), dat ook de naam van het project en de naam van de hoofdnaamruimte is. Zorg er ook voor dat de Windows Runtime metagegevens en het binaire bestand volledig zijn gekopieerd door het buildproces naar de map van Appx de verbruikende app. Controleer of de verbruikende app's AppxManifest.xml (ook in de Appx map) een <InProcessServer-element> bevatten dat de activeringsbare klasse en de binaire naam correct declareert.

Uniforme constructie Deze fout kan ook optreden als u een lokaal geïmplementeerde runtimeklasse probeert te instantiëren via een van de constructors van het projected type (met uitzondering van de std::nullptr_t constructor). Hiervoor hebt u de C++/WinRT 2.0-functie nodig die vaak uniforme constructie wordt genoemd. Als u zich wilt aanmelden voor deze functie, raadpleegt u Opt in to uniform construction en directe implementatietoegang voor meer informatie en codevoorbeelden.

Zie XAML-besturingselementen; bind aan een C++/WinRT-eigenschap voor een manier om uw lokaal geïmplementeerde runtimeklassen te instantiëren waarvoor geen uniforme constructie is vereist.

Moet ik Windows::Foundation::IClosable implementeren en, zo ja, hoe?

Als u een runtimeklasse hebt waarmee resources in de destructor worden vrijgemaakt en die runtimeklasse is ontworpen om te worden gebruikt van buiten de implementatiecompilatie-eenheid (dit is een Windows Runtime onderdeel dat is bedoeld voor algemeen gebruik door Windows Runtime client-apps), raden we u aan ook IClosable te implementeren om het verbruik van uw runtimeklasse te ondersteunen op talen die geen deterministische finalisatie hebben. Zorg ervoor dat uw systeembronnen worden vrijgemaakt, ongeacht of de destructor, IClosable::Close of beide worden aangeroepen. IClosable::Close kan een willekeurig aantal keren worden genoemd.

Moet ik IClosable::Close aanroepen voor runtime-klassen die ik gebruik?

IClosable bestaat ter ondersteuning van talen die geen deterministische finalisatie hebben. Dus in het algemeen hoeft u IClosable::Close from C++/WinRT niet aan te roepen. Maar houd rekening met deze uitzonderingen op die algemene regel.

  • Er zijn zeer zeldzame gevallen met afsluitraces of semi-dodelijke omhelzingen, waar u IClosable::Close moet aanroepen. Als u bijvoorbeeld typen van Windows.UI.Composition gebruikt, kunt u situaties tegenkomen waarin u objecten in een bepaalde volgorde wilt opruimen, in plaats van het werk over te laten aan de vernietiging van de C++/WinRT-wrapper.
  • Als u niet kunt garanderen dat u de laatste verwijzing naar een object hebt (omdat u deze hebt doorgegeven aan andere API's, die een verwijzing kunnen behouden), is het aanroepen van IClosable::Close een goed idee.
  • Bij twijfel kunt u IClosable::Close veilig handmatig aanroepen, in plaats van te wachten tot de wrapper dit bij destructie aanroept.

Dus als u weet dat u de laatste verwijzing hebt, kunt u de wrapper destructor het werk laten doen. Als u moet sluiten voordat de laatste verwijzing verdwijnt, moet u Sluiten aanroepen. Om uitzonderingsveilig te zijn, moet u Close onderbrengen in een resource-acquisition-is-initialization-type (RAII), zodat Close wordt uitgevoerd tijdens het afwikkelen van de stack. C++/WinRT heeft geen unique_close wrapper, maar u kunt er zelf een maken.

Kan ik LLVM/Clang gebruiken om te compileren met C++/WinRT?

We bieden geen ondersteuning voor de LLVM- en Clang-hulpprogrammaketen voor C++/WinRT, maar we maken er intern gebruik van om de standaarden van C++/WinRT te valideren. Als u bijvoorbeeld intern wilt emuleren wat we doen, kunt u een experiment proberen, zoals het experiment dat hieronder wordt beschreven.

Ga naar de LLVM-downloadpagina, zoek Download LLVM 6.0.0>voorgecompileerde binaire bestanden en download Clang voor Windows (64-bitsversie). Kies er tijdens de installatie voor om LLVM toe te voegen aan de PATH-systeemvariabele, zodat u deze kunt aanroepen vanaf een opdrachtprompt. Voor de doeleinden van dit experiment kunt u eventuele foutmeldingen "Failed to find MSBuild toolsets directory" en/of "MSVC integration install failed" negeren, als u die tegenkomt. Er zijn verschillende manieren om LLVM/Clang aan te roepen; in het onderstaande voorbeeld ziet u slechts één manier.

C:\ExperimentWithLLVMClang>type main.cpp
// main.cpp
#pragma comment(lib, "windowsapp")
#pragma comment(lib, "ole32")

#include <winrt/Windows.Foundation.h>
#include <stdio.h>
#include <iostream>

using namespace winrt;

int main()
{
    winrt::init_apartment();
    Windows::Foundation::Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
    std::wcout << rssFeedUri.Domain().c_str() << std::endl;
}

C:\ExperimentWithLLVMClang>clang-cl main.cpp /EHsc /I ..\.. -Xclang -std=c++17 -Xclang -Wno-delete-non-virtual-dtor -o app.exe

C:\ExperimentWithLLVMClang>app
windows.com

Omdat C++/WinRT gebruikmaakt van functies van de C++17-standaard, moet u alle compilervlagmen gebruiken om die ondersteuning te krijgen; dergelijke vlaggen verschillen van de ene compiler naar de andere.

Visual Studio is het ontwikkelhulpprogramma dat we ondersteunen en aanbevelen voor C++/WinRT. Zie Visual Studio ondersteuning voor C++/WinRT.

Waarom heeft de gegenereerde implementatiefunctie voor een alleen-lezen-eigenschap niet de kwalificatie 'const'?

Wanneer u in MIDL 3.0 een alleen-leeseigenschap definieert, verwacht u mogelijk dat het hulpprogramma cppwinrt.exe een implementatiefunctie voor u genereert die met const is gekwalificeerd (een const-functie behandelt de this-pointer als const).

We raden zeker aan om waar mogelijk const te gebruiken, maar de cppwinrt.exe tool zelf probeert niet te bepalen welke implementatiefuncties mogelijk const kunnen zijn en welke niet. U kunt ervoor kiezen om een van uw implementatiefuncties const te maken, zoals in dit voorbeeld.

struct MyStringable : winrt::implements<MyStringable, winrt::Windows::Foundation::IStringable>
{
    winrt::hstring ToString() const
    {
        return L"MyStringable";
    }
};

U kunt deze const kwalificatie voor ToString verwijderen als u besluit dat u een bepaalde objectstatus in de implementatie moet wijzigen. Maar zorg dat elke lidfunctie óf const óf niet-const is, niet allebei. Met andere woorden, een implementatiefunctie niet overbelasten op const.

Afgezien van uw implementatiefuncties, bevindt zich nog een andere plaats waar const in het beeld komt in Windows Runtime functieprojecties. Houd rekening met deze code.

int main()
{
    winrt::Windows::Foundation::IStringable s{ winrt::make<MyStringable>() };
    auto result{ s.ToString() };
}

Voor de aanroep naar ToString hierboven ziet de opdracht Go To Declaration in Visual Studio dat de projectie van de Windows Runtime IStringable::ToString in C++/WinRT er als volgt uitziet.

winrt::hstring ToString() const;

Functies van de projectie zijn const, ongeacht hoe u ervoor kiest uw implementatie daarvan te kwalificeren. Achter de schermen roept de projectie de binaire interface (ABI) van de toepassing aan, wat neerkomt op een aanroep via een COM-interfacepointer. De enige toestand waarmee de geprojecteerde ToString interageert, is die COM-interfacepointer; en die hoeft beslist niet te worden gewijzigd, dus de functie is const. Dit geeft u de garantie dat er niets verandert aan de IStringable-verwijzing waarop u een aanroep uitvoert, en zorgt ervoor dat u ToString ook kunt aanroepen met een const-verwijzing naar een IStringable.

Begrijp dat deze voorbeelden const implementatiedetails zijn van C++/WinRT-projecties en -implementaties; ze vormen code hygiëne voor uw voordeel. Zoiets als const bestaat niet in de COM- of Windows Runtime-ABI (voor memberfuncties).

Hebt u aanbevelingen voor het verlagen van de codegrootte voor binaire C++/WinRT-bestanden?

Wanneer u met Windows Runtime objecten werkt, moet u het onderstaande coderingspatroon vermijden, omdat dit een negatieve invloed kan hebben op uw toepassing door meer binaire code te veroorzaken dan nodig is om te worden gegenereerd.

anobject.b().c().d();
anobject.b().c().e();
anobject.b().c().f();

In de Windows Runtime wereld kan de compiler de waarde van c() of de interfaces niet opslaan voor elke methode die wordt aangeroepen via een indirectie ('.'). Tenzij u tussenbeide komt, leidt dat tot meer virtuele aanroepen en overhead door referentietelling. Het bovenstaande patroon kan eenvoudig twee keer zoveel code genereren als strikt nodig is. Geef in plaats daarvan de voorkeur aan het onderstaande patroon, waar u ook kunt. Het genereert veel minder code en het kan ook de runtimeprestaties aanzienlijk verbeteren.

auto a{ anobject.b().c() };
a.d();
a.e();
a.f();

Het aanbevolen patroon dat hierboven wordt weergegeven, is niet alleen van toepassing op C++/WinRT, maar op alle Windows Runtime taalprojecties.

Hoe zet ik een tekenreeks om in een type (bijvoorbeeld voor navigatie)?

Aan het einde van het codevoorbeeld van de navigatieweergave (meestal in C#) ziet u een C++/WinRT-codefragment waarin wordt getoond hoe u dit doet.

Hoe los ik dubbelzinnigheden op met GetCurrentTime en/of TRY?

Het headerbestand winrt/Windows.UI.Xaml.Media.Animation.h declareert een methode met de naam GetCurrentTime, terwijl windows.h (via winbase.h) een macro met de naam GetCurrentTime wordt gedefinieerd. Wanneer de twee botsen, produceert de C++-compiler 'fout C4002: Te veel argumenten voor functieachtige macro-aanroep GetCurrentTime'.

Declareert op dezelfde manier winrt/Windows.Globalization.h een methode met de naam TRY, terwijl afx.h een macro met de naam TRY wordt gedefinieerd. Wanneer deze botsen, produceert de C++-compiler "fout C2334: onverwachte token(s) voorafgaand aan {"; duidelijke functietekst overslaan".

U kunt dit doen om een of beide problemen op te lossen.

#pragma push_macro("GetCurrentTime")
#pragma push_macro("TRY")
#undef GetCurrentTime
#undef TRY
#include <winrt/include_your_cppwinrt_headers_here.h>
#include <winrt/include_your_cppwinrt_headers_here.h>
#pragma pop_macro("TRY")
#pragma pop_macro("GetCurrentTime")

Hoe kan ik het laden van symbolen versnellen?

Schakel in Visual Studio Extra>Opties>Foutopsporing>Symbolen>Alleen opgegeven modules laden in. U kunt vervolgens met de rechtermuisknop op DLL's in de stacklijst klikken en afzonderlijke modules laden.

Note

Als dit onderwerp uw vraag niet heeft beantwoord, kunt u hulp vinden door naar de Visual Studio C++-ontwikkelaarscommunity te gaan of door de c++-winrt tag op Stack Overflow te gebruiken.