CLR Profilers en Windows Store-apps
In dit onderwerp wordt besproken wat u moet bedenken bij het schrijven van diagnostische hulpprogramma's waarmee beheerde code wordt geanalyseerd die wordt uitgevoerd in een Windows Store-app. Het biedt ook richtlijnen voor het wijzigen van uw bestaande ontwikkelhulpprogramma's, zodat ze blijven werken wanneer u ze uitvoert op Windows Store-apps. Om deze informatie te begrijpen, is het raadzaam als u bekend bent met de Common Language Runtime Profile-API, u deze API al hebt gebruikt in een diagnostisch hulpprogramma dat correct wordt uitgevoerd voor Windows-bureaubladtoepassingen en u bent nu geïnteresseerd in het wijzigen van het hulpprogramma om correct te worden uitgevoerd voor Windows Store-apps.
Inleiding
Als u de inleidende alinea hebt geplakt, bent u bekend met de CLR-profilerings-API. U hebt al een diagnostisch hulpprogramma geschreven dat goed werkt voor beheerde bureaubladtoepassingen. U bent nu benieuwd wat u moet doen, zodat uw hulpprogramma werkt met een beheerde Windows Store-app. Misschien hebt u al geprobeerd dit werk te maken en ontdekt dat het geen eenvoudige taak is. Er zijn inderdaad een aantal overwegingen die mogelijk niet duidelijk zijn voor alle hulpprogramma'sontwikkelaars. Voorbeeld:
Windows Store-apps worden uitgevoerd in een context met sterk verminderde machtigingen.
Windows-metagegevensbestanden hebben unieke kenmerken in vergelijking met traditionele beheerde modules.
Windows Store-apps hebben een gewoonte om zichzelf te onderbreken wanneer interactiviteit uitvalt.
Uw communicatiemechanismen tussen processen werken mogelijk om verschillende redenen niet meer.
In dit onderwerp worden de dingen vermeld waarvan u op de hoogte moet zijn en hoe u hiermee omgaat.
Als u geen ervaring hebt met de CLR-profilerings-API, gaat u verder met de resources aan het einde van dit onderwerp om betere inleidende informatie te vinden.
Het verstrekken van details over specifieke Windows-API's en hoe ze moeten worden gebruikt, valt ook buiten het bereik van dit onderwerp. Bekijk dit onderwerp als uitgangspunt en raadpleeg MSDN voor meer informatie over eventuele Windows-API's waarnaar hier wordt verwezen.
Architectuur en terminologie
Normaal gesproken heeft een diagnostisch hulpprogramma een architectuur zoals die in de volgende afbeelding wordt weergegeven. Het gebruikt de term profiler, maar veel dergelijke hulpprogramma's gaan veel verder dan typische prestaties of geheugenprofilering in gebieden zoals codedekking, mock-objectframeworks, foutopsporing op tijdreizen, toepassingsbewaking, enzovoort. Ter vereenvoudiging blijft dit onderwerp verwijzen naar al deze hulpprogramma's als profilers.
In dit onderwerp wordt de volgende terminologie gebruikt:
Toepassing
Dit is de toepassing die door de profiler wordt geanalyseerd. Normaal gesproken gebruikt de ontwikkelaar van deze toepassing nu de profiler om problemen met de toepassing vast te stellen. Deze toepassing zou traditioneel een Windows-bureaubladtoepassing zijn, maar in dit onderwerp kijken we naar Windows Store-apps.
Profiler DLL
Dit is het onderdeel dat wordt geladen in de procesruimte van de toepassing die wordt geanalyseerd. Dit onderdeel, ook wel bekend als de profiler 'agent', implementeert de ICorProfilerCallbackICorProfilerCallback Interface(2,3, enzovoort) interfaces en gebruikt de ICorProfilerInfo(2,3, enzovoort) interfaces om gegevens te verzamelen over de geanalyseerde toepassing en mogelijk aspecten van het gedrag van de toepassing te wijzigen.
Profiler-gebruikersinterface
Dit is een bureaubladtoepassing waarmee de profilergebruiker communiceert. Het is verantwoordelijk voor het weergeven van de toepassingsstatus aan de gebruiker en het geven van de gebruiker de middelen om het gedrag van de geanalyseerde toepassing te beheren. Dit onderdeel wordt altijd uitgevoerd in een eigen procesruimte, gescheiden van de procesruimte van de toepassing die wordt geprofileerd. De Profiler-gebruikersinterface kan ook fungeren als de 'trigger koppelen'. Dit is het proces dat de methode ICLRProfiling aanroept::AttachProfiler , om ervoor te zorgen dat de geanalyseerde toepassing de Profiler-DLL laadt in die gevallen waarin het DLL-bestand van de profiler niet is geladen bij het opstarten.
Belangrijk
Uw Profiler-gebruikersinterface moet een Windows-bureaubladtoepassing blijven, zelfs wanneer deze wordt gebruikt voor het beheren en rapporteren van een Windows Store-app. Verwacht niet dat u uw diagnostische hulpprogramma in de Windows Store kunt verpakken en verzenden. Uw hulpprogramma moet dingen doen die Windows Store-apps niet kunnen doen en veel van deze dingen bevinden zich in uw Profiler-gebruikersinterface.
In dit document wordt in de voorbeeldcode ervan uitgegaan dat:
Uw Profiler-DLL is geschreven in C++, omdat het een systeemeigen DLL moet zijn, volgens de vereisten van de CLR-profilerings-API.
Uw Profiler-gebruikersinterface is geschreven in C#. Dit is niet nodig, maar omdat er geen vereisten zijn voor de taal voor het proces van uw Profiler-gebruikersinterface, kiest u een taal die beknopt en eenvoudig is?
Windows RT-apparaten
Windows RT-apparaten zijn behoorlijk vergrendeld. Profilers van derden kunnen gewoon niet worden geladen op dergelijke apparaten. Dit document is gericht op Windows 8-pc's.
Windows Runtime-API's gebruiken
In een aantal scenario's die in de volgende secties worden besproken, moet uw Profiler UI-bureaubladtoepassing enkele nieuwe Windows Runtime-API's gebruiken. Raadpleeg de documentatie om te begrijpen welke Windows Runtime-API's kunnen worden gebruikt vanuit desktoptoepassingen en of hun gedrag verschilt wanneer ze worden aangeroepen vanuit bureaubladtoepassingen en Windows Store-apps.
Als uw Profiler-gebruikersinterface is geschreven in beheerde code, zijn er enkele stappen die u moet uitvoeren om het gebruik van deze Windows Runtime-API's eenvoudig te maken. Zie het artikel Beheerde bureaublad-apps en Windows Runtime voor meer informatie.
Het DLL-bestand van Profiler laden
In deze sectie wordt beschreven hoe uw Profiler-gebruikersinterface ervoor zorgt dat de Windows Store-app uw Profiler-DLL laadt. De code die in deze sectie wordt besproken, behoort tot uw Profiler UI-bureaublad-app en omvat daarom het gebruik van Windows-API's die veilig zijn voor desktop-apps, maar niet noodzakelijkerwijs veilig voor Windows Store-apps.
Uw Profiler-gebruikersinterface kan ertoe leiden dat uw Profiler-DLL op twee manieren in de procesruimte van de toepassing wordt geladen:
Bij het opstarten van de toepassing, zoals beheerd door omgevingsvariabelen.
Door de toepassing te koppelen nadat het opstarten is voltooid, roept u de methode ICLRProfiling::AttachProfiler aan.
Een van uw eerste obstakels krijgt opstart-laden en laden van uw Profiler-DLL om correct te werken met Windows Store-apps. Beide vormen van het laden van delen delen enkele speciale overwegingen gemeen, dus laten we beginnen met ze.
Veelvoorkomende overwegingen voor het opstarten en koppelen van belastingen
Uw Profiler-DLL ondertekenen
Wanneer Windows probeert uw Profiler-DLL te laden, wordt gecontroleerd of uw Profiler-DLL juist is ondertekend. Als dat niet het probleem is, mislukt de belasting standaard. Er zijn twee manieren om dit te doen:
Zorg ervoor dat uw Profiler-DLL is ondertekend.
Vertel uw gebruikers dat ze een ontwikkelaarslicentie op hun Windows 8-computer moeten installeren voordat ze uw hulpprogramma gebruiken. Dit kan automatisch vanuit Visual Studio of handmatig vanaf een opdrachtprompt worden gedaan. Zie Een licentie voor ontwikkelaars ophalen voor meer informatie.
Machtigingen voor bestandssysteem
De Windows Store-app moet gemachtigd zijn om uw Profiler-DLL te laden en uit te voeren vanaf de locatie op het bestandssysteem waarin deze zich standaard bevindtBy, de Windows Store-app heeft geen dergelijke machtiging voor de meeste mappen en elke mislukte poging om uw Profiler-DLL te laden, produceert een vermelding in het gebeurtenislogboek van de Windows-toepassing die er ongeveer als volgt uitziet:
NET Runtime version 4.0.30319.17929 - Loading profiler failed during CoCreateInstance. Profiler CLSID: '{xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'. HRESULT: 0x80070005. Process ID (decimal): 4688. Message ID: [0x2504].
Over het algemeen hebben Windows Store-apps alleen toegang tot een beperkt aantal locaties op de schijf. Elke Windows Store-app heeft toegang tot zijn eigen mappen met toepassingsgegevens, evenals een paar andere gebieden in het bestandssysteem waarvoor alle Windows Store-apps toegang krijgen. Het is raadzaam om uw Profiler-DLL en de bijbehorende afhankelijkheden ergens onder Program Files of Program Files (x86) te installeren, omdat alle Windows Store-apps standaard lees- en uitvoermachtigingen hebben.
Opstartbelasting
Normaal gesproken vraagt uw Profiler-gebruikersinterface in een desktop-app om een opstartbelasting van uw Profiler-DLL door een omgevingsblok te initialiseren dat de vereiste omgevingsvariabelen voor CLR-profilerings-API bevat (d.w.w.v COR_PROFILER
. , COR_ENABLE_PROFILING
en COR_PROFILER_PATH
) en vervolgens een nieuw proces met dat omgevingsblok te maken. Hetzelfde geldt voor Windows Store-apps, maar de mechanismen verschillen.
Niet uitvoeren met verhoogde bevoegdheden
Als proces A probeert windows Store-app-proces B uit te voeren, moet proces A worden uitgevoerd op gemiddeld integriteitsniveau, niet op hoog integriteitsniveau (dat wil gezegd, niet verhoogd). Dit betekent dat uw Profiler-gebruikersinterface moet worden uitgevoerd op gemiddeld integriteitsniveau of dat er een ander bureaubladproces moet worden uitgevoerd op gemiddeld integriteitsniveau om ervoor te zorgen dat de Windows Store-app wordt gestart.
Een Windows Store-app kiezen om te profileren
Eerst wilt u uw profilergebruiker vragen welke Windows Store-app moet worden gestart. Voor bureaublad-apps zou u misschien een dialoogvenster Bladeren van een bestand weergeven en de gebruiker een .exe-bestand zoeken en selecteren. Windows Store-apps zijn echter anders en het gebruik van een dialoogvenster Bladeren is niet logisch. In plaats daarvan is het beter om de gebruiker een lijst weer te geven met Windows Store-apps die voor die gebruiker zijn geïnstalleerd.
U kunt de PackageManager klasse gebruiken om deze lijst te genereren. PackageManager
is een Windows Runtime-klasse die beschikbaar is voor bureaublad-apps en in feite alleen beschikbaar is voor desktop-apps.
In het volgende codevoorbeeld van een hypothetische Profiler-gebruikersinterface die is geschreven als een bureaublad-app in C# wordt gebruikgemaakt van de functie voor het PackageManager
genereren van een lijst met Windows-apps:
string currentUserSID = WindowsIdentity.GetCurrent().User.ToString();
IAppxFactory appxFactory = (IAppxFactory) new AppxFactory();
PackageManager packageManager = new PackageManager();
IEnumerable<Package> packages = packageManager.FindPackagesForUser(currentUserSID);
Het aangepaste omgevingsblok opgeven
Met een nieuwe COM-interface, IPackageDebug Instellingen kunt u het uitvoeringsgedrag van een Windows Store-app aanpassen om bepaalde vormen van diagnostische gegevens gemakkelijker te maken. Met een van de methoden EnableDebugging kunt u een omgevingsblok doorgeven aan de Windows Store-app wanneer deze wordt gestart, samen met andere nuttige effecten, zoals het uitschakelen van automatische procesvering. Het omgevingsblok is belangrijk omdat u hier de omgevingsvariabelen (COR_PROFILER
, COR_ENABLE_PROFILING
en COR_PROFILER_PATH)
) moet opgeven die door de CLR worden gebruikt om uw Profiler-DLL te laden.
Bekijk het volgende codefragment:
IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, debuggerCommandLine,
(IntPtr)fixedEnvironmentPzz);
Er zijn een aantal items die u nodig hebt om goed te zijn:
packageFullName
kan worden bepaald tijdens het herhalen van de pakketten en het ophalenpackage.Id.FullName
.debuggerCommandLine
is iets interessanter. Als u het aangepaste omgevingsblok wilt doorgeven aan de Windows Store-app, moet u uw eigen, simplistische dummy-foutopsporingsprogramma schrijven. Windows spawnst de Windows Store-app onderbroken en koppelt vervolgens het foutopsporingsprogramma door het foutopsporingsprogramma te starten met een opdrachtregel zoals in dit voorbeeld:MyDummyDebugger.exe -p 1336 -tid 1424
waarbij
-p 1336
betekent dat de Windows Store-app proces-id 1336 heeft en-tid 1424
thread-id 1424 de thread is die is onderbroken. Het dummy-foutopsporingsprogramma parseert de ThreadID vanaf de opdrachtregel, hervat die thread en sluit vervolgens af.Hier volgt een voorbeeld van C++-code om dit te doen (zorg ervoor dat u foutcontrole toevoegt!):
int wmain(int argc, wchar_t* argv[]) { // … // Parse command line here // … HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE /* bInheritHandle */, nThreadID); ResumeThread(hThread); CloseHandle(hThread); return 0; }
U moet dit dummy-foutopsporingsprogramma implementeren als onderdeel van de installatie van uw diagnostische hulpprogramma en vervolgens het pad naar dit foutopsporingsprogramma in de
debuggerCommandLine
parameter opgeven.
De Windows Store-app starten
Het moment waarop de Windows Store-app wordt gestart, is eindelijk aangekomen. Als u dit zelf al hebt geprobeerd, hebt u mogelijk gemerkt dat CreateProcess niet de wijze is waarop u een Windows Store-app-proces maakt. In plaats daarvan moet u de methode IApplicationActivationManager::ActivateApplication gebruiken. Hiervoor moet u de app-gebruikersmodel-id ophalen van de Windows Store-app die u start. En dat betekent dat je een beetje door het manifest moet graven.
Tijdens het herhalen van uw pakketten (zie 'Een Windows Store-app kiezen voor profiel' in de sectie Opstartbelasting eerder), wilt u de set toepassingen in het manifest van het huidige pakket ophalen:
string manifestPath = package.InstalledLocation.Path + "\\AppxManifest.xml";
AppxPackaging.IStream manifestStream;
SHCreateStreamOnFileEx(
manifestPath,
0x00000040, // STGM_READ | STGM_SHARE_DENY_NONE
0, // file creation attributes
false, // fCreate
null, // reserved
out manifestStream);
IAppxManifestReader manifestReader = appxFactory.CreateManifestReader(manifestStream);
IAppxManifestApplicationsEnumerator appsEnum = manifestReader.GetApplications();
Ja, één pakket kan meerdere toepassingen hebben en elke toepassing heeft een eigen gebruikersmodel-id voor toepassingen. U wilt uw gebruiker dus vragen welke toepassing moet worden geprofileer en de model-id van de toepassingsgebruiker van die specifieke toepassing ophalen:
while (appsEnum.GetHasCurrent() != 0)
{
IAppxManifestApplication app = appsEnum.GetCurrent();
string appUserModelId = app.GetAppUserModelId();
//...
}
Ten slotte hebt u nu wat u nodig hebt om de Windows Store-app te starten:
IApplicationActivationManager appActivationMgr = new ApplicationActivationManager();
appActivationMgr.ActivateApplication(appUserModelId, appArgs, ACTIVATEOPTIONS.AO_NONE, out pid);
Vergeet niet om DisableDebugging aan te roepen
Wanneer u IPackageDebug hebt genoemd Instellingen::EnableDebugging hebt u een belofte gedaan dat u na uzelf zou opschonen door de methode IPackageDebug aan te roepen Instellingen::D isableDebugging, dus zorg ervoor dat u dat doet wanneer de profileringssessie voorbij is.
Laden bijvoegen
Wanneer uw Profiler-gebruikersinterface de profiler-DLL wil koppelen aan een toepassing die al is gestart, wordt ICLRProfiling::AttachProfiler gebruikt. Hetzelfde geldt voor Windows Store-apps. Maar zorg er niet alleen voor dat de windows Store-doel-app wordt onderbroken, maar niet naast de veelvoorkomende overwegingen die eerder zijn vermeld.
EnableDebugging
Net als bij het laden van het opstarten roept u de methode IPackageDebug aan Instellingen::EnableDebugging. U hebt het niet nodig om een omgevingsblok door te geven, maar u hebt een van de andere functies nodig: automatische procesvering uitschakelen. Anders kan de Windows Store-doel-app worden onderbroken wanneer uw Profiler UI AttachProfiler aanroept. Dit is zelfs waarschijnlijk als de gebruiker nu communiceert met de gebruikersinterface van Profiler en de Windows Store-app niet actief is op een van de schermen van de gebruiker. En als de Windows Store-app is onderbroken, kan deze niet reageren op een signaal dat de CLR naar de APP verzendt om uw Profiler-DLL te koppelen.
U wilt dus iets als volgt doen:
IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, null /* debuggerCommandLine */,
IntPtr.Zero /* environment */);
Dit is dezelfde aanroep die u zou maken voor de opstarttaakcase, behalve dat u geen opdrachtregel voor foutopsporingsprogramma of een omgevingsblok opgeeft.
DisableDebugging
Vergeet niet om IPackageDebug aan te roepen Instellingen::D isableDebugging wanneer uw profileringssessie is voltooid.
Wordt uitgevoerd in de Windows Store-app
De Windows Store-app heeft uw Profiler-DLL dus eindelijk geladen. Nu moet uw Profiler-DLL worden geleerd hoe u kunt afspelen op basis van de verschillende regels die zijn vereist voor Windows Store-apps, waaronder welke API's zijn toegestaan en hoe u kunt worden uitgevoerd met beperkte machtigingen.
Houd vast aan de Api's van de Windows Store-app
Terwijl u door de Windows-API bladert, ziet u dat elke API wordt gedocumenteerd als van toepassing op desktop-apps, Windows Store-apps of beide. De sectie Vereisten van de documentatie voor de functie InitializeCriticalSectionAndSpinCount geeft bijvoorbeeld aan dat de functie alleen van toepassing is op bureaublad-apps. De functie InitializeCriticalSectionEx is daarentegen beschikbaar voor zowel desktop-apps als Windows Store-apps.
Wanneer u uw Profiler-DLL ontwikkelt, behandelt u deze alsof het een Windows Store-app is en gebruikt u alleen API's die worden gedocumenteerd als beschikbaar voor Windows Store-apps. Analyseer uw afhankelijkheden (u kunt bijvoorbeeld uitvoeren link /dump /imports
op uw Profiler-DLL om te controleren) en doorzoek de documenten om te zien welke van uw afhankelijkheden in orde zijn en welke niet. In de meeste gevallen kunnen uw schendingen worden opgelost door ze te vervangen door een nieuwere vorm van de API die wordt gedocumenteerd als veilig (bijvoorbeeld initializeCriticalSectionAndSpinCount vervangen door InitializeCriticalSectionEx).
Mogelijk ziet u dat uw Profiler-DLL enkele API's aanroept die alleen van toepassing zijn op desktop-apps, en toch lijken ze te werken, zelfs wanneer uw Profiler-DLL in een Windows Store-app wordt geladen. Houd er rekening mee dat het riskant is om een API te gebruiken die niet is gedocumenteerd voor gebruik met Windows Store-apps in uw Profiler-DLL wanneer deze in een Windows Store-app-proces wordt geladen:
Dergelijke API's werken niet gegarandeerd wanneer ze worden aangeroepen in de unieke context waarin Windows Store-apps worden uitgevoerd.
Dergelijke API's werken mogelijk niet consistent wanneer ze vanuit verschillende Windows Store-app-processen worden aangeroepen.
Dergelijke API's werken mogelijk prima vanuit Windows Store-apps in de huidige versie van Windows, maar kunnen in toekomstige versies van Windows worden verbroken of uitgeschakeld.
Het beste advies is om al uw schendingen op te lossen en het risico te voorkomen.
Mogelijk vindt u dat u absoluut niet zonder een bepaalde API kunt doen en geen vervanging kunt vinden die geschikt is voor Windows Store-apps. In dat geval moet u minimaal:
Test, test, test het levende daglicht uit uw gebruik van die API.
Begrijp dat de API plotseling uitvalt of verdwijnt als deze wordt aangeroepen vanuit Windows Store-apps in toekomstige versies van Windows. Dit wordt niet beschouwd als een compatibiliteitsprobleem van Microsoft en het ondersteunen van uw gebruik ervan is geen prioriteit.
Beperkte machtigingen
Het valt buiten het bereik van dit onderwerp om alle manieren weer te geven waarop machtigingen voor Windows Store-apps verschillen van bureaublad-apps. Maar het gedrag zal zeker verschillen telkens wanneer uw Profiler-DLL (wanneer deze in een Windows Store-app wordt geladen in vergelijking met een bureaublad-app) toegang probeert te krijgen tot alle resources. Het bestandssysteem is het meest voorkomende voorbeeld. Er zijn maar een paar plaatsen op schijf waartoe een bepaalde Windows Store-app toegang heeft (zie Bestandstoegang en -machtigingen (Windows Runtime-apps) en uw Profiler-DLL valt onder dezelfde beperkingen. Test uw code grondig.
Communicatie tussen processen
Zoals wordt weergegeven in het diagram aan het begin van dit document, moet uw Profiler-DLL (geladen in de procesruimte van de Windows Store-app) waarschijnlijk communiceren met uw Profiler-gebruikersinterface (uitgevoerd in een afzonderlijke procesruimte voor desktop-apps) via uw eigen aangepaste IPC-kanaal (Inter-Process Communication). De Profiler-gebruikersinterface verzendt signalen naar het Profiler-DLL-bestand om het gedrag te wijzigen en de Profiler-DLL verzendt gegevens van de geanalyseerde Windows Store-app terug naar de Profiler-gebruikersinterface voor naverwerking en weergave naar de profilergebruiker.
De meeste profilers moeten op deze manier werken, maar uw keuzes voor IPC-mechanismen zijn beperkter wanneer uw Profiler-DLL wordt geladen in een Windows Store-app. Benoemde pijpen maken bijvoorbeeld geen deel uit van de Windows Store App SDK, dus u kunt ze niet gebruiken.
Maar natuurlijk zijn bestanden nog steeds in, zij het op een beperktere manier. Er zijn ook gebeurtenissen beschikbaar.
Communiceren via bestanden
De meeste van uw gegevens worden waarschijnlijk via bestanden doorgegeven tussen de profiler-DLL en profiler-gebruikersinterface. De sleutel is om een bestandslocatie te kiezen waartoe zowel uw Profiler-DLL (in de context van een Windows Store-app) als de gebruikersinterface van Profiler lees- en schrijftoegang heeft. Het pad naar de tijdelijke map is bijvoorbeeld een locatie waartoe zowel uw Profiler-DLL als de gebruikersinterface van Profiler toegang heeft, maar geen ander Windows Store-app-pakket heeft toegang (waardoor alle gegevens die u hebt vastgelegd vanuit andere Windows Store-app-pakketten worden afgeschermd).
Zowel uw Profiler-gebruikersinterface als de Profiler-DLL kunnen dit pad onafhankelijk bepalen. Wanneer uw Profiler-gebruikersinterface alle pakketten doorloopt die zijn geïnstalleerd voor de huidige gebruiker (zie de voorbeeldcode eerder), krijgt u toegang tot de PackageId
klasse, waaruit het pad tijdelijke map kan worden afgeleid met code die vergelijkbaar is met dit fragment. (Zoals altijd wordt foutcontrole weggelaten voor beknoptheid.)
// C# code for the Profiler UI.
ApplicationData appData =
ApplicationDataManager.CreateForPackageFamily(
packageId.FamilyName);
tempDir = appData.TemporaryFolder.Path;
Ondertussen kan uw Profiler-DLL eigenlijk hetzelfde doen, hoewel het eenvoudiger bij de ApplicationData klasse kan komen met behulp van de eigenschap ApplicationData.Current .
Communiceren via gebeurtenissen
Als u eenvoudige signaleringssemantiek tussen uw Profiler UI en Profiler DLL wilt, kunt u gebeurtenissen in Windows Store-apps en bureaublad-apps gebruiken.
Vanuit uw Profiler DLL kunt u gewoon de functie CreateEventEx aanroepen om een benoemde gebeurtenis te maken met elke gewenste naam. Voorbeeld:
// Profiler DLL in Windows Store app (C++).
CreateEventEx(
NULL, // Not inherited
"MyNamedEvent"
CREATE_EVENT_MANUAL_RESET, /* explicit ResetEvent() required; leave initial state unsignaled */
EVENT_ALL_ACCESS);
Uw Profiler-gebruikersinterface moet die benoemde gebeurtenis vervolgens vinden onder de naamruimte van de Windows Store-app. Uw Profiler-gebruikersinterface kan bijvoorbeeld CreateEventEx aanroepen, waarbij de naam van de gebeurtenis wordt opgegeven als
AppContainerNamedObjects\<acSid>\MyNamedEvent
<acSid>
is de AppContainer-SID van de Windows Store-app. In een eerdere sectie van dit onderwerp hebt u gezien hoe u de pakketten kunt herhalen die zijn geïnstalleerd voor de huidige gebruiker. Vanuit die voorbeeldcode kunt u de packageId verkrijgen. En via de packageId kunt u de <acSid>
code verkrijgen die vergelijkbaar is met de volgende:
IntPtr acPSID;
DeriveAppContainerSidFromAppContainerName(packageId.FamilyName, out acPSID);
string acSid;
ConvertSidToStringSid(acPSID, out acSid);
string acDir;
GetAppContainerFolderPath(acSid, out acDir);
Geen afsluitmeldingen
Wanneer uw Profiler-DLL wordt uitgevoerd in een Windows Store-app, moet u niet vertrouwen op ICorProfilerCallback ::Shutdown or zelfs DllMain (met DLL_PROCESS_DETACH
) die wordt aangeroepen om uw Profiler-DLL op de hoogte te stellen dat de Windows Store-app wordt afgesloten. In feite zou je moeten verwachten dat ze nooit zullen worden gebeld. In het verleden hebben veel Profiler-DLL's deze meldingen gebruikt als handige plaatsen om caches naar schijf te wissen, bestanden te sluiten, meldingen terug te sturen naar de Profiler-gebruikersinterface, enzovoort. Maar nu moet uw Profiler-DLL iets anders worden georganiseerd.
Uw Profiler-DLL moet gegevens vastleggen zoals deze wordt uitgevoerd. Om prestatieredenen kunt u gegevens in het geheugen batcheren en naar schijf leegmaken naarmate de batch groter wordt dan een bepaalde drempelwaarde. Maar ga ervan uit dat alle gegevens die nog niet naar de schijf zijn leeggemaakt, verloren kunnen gaan. Dit betekent dat u uw drempelwaarde verstandig wilt kiezen en dat uw Profiler-gebruikersinterface moet worden beperkt om te kunnen omgaan met onvolledige informatie die is geschreven door de Profiler DLL.
Windows Runtime-metagegevensbestanden
Het valt buiten het bereik van dit document om gedetailleerde informatie te krijgen over wat WinMD-bestanden (Windows Runtime metadata) zijn. Deze sectie is beperkt tot hoe de CLR-profilerings-API reageert wanneer WinMD-bestanden worden geladen door de Windows Store-app die uw Profiler-DLL analyseert.
Beheerde en niet-beheerde WinMD's
Als een ontwikkelaar Visual Studio gebruikt om een nieuw Windows Runtime Component-project te maken, produceert een build van dat project een WinMD-bestand dat de metagegevens beschrijft (de typebeschrijvingen van klassen, interfaces, enzovoort) die zijn geschreven door de ontwikkelaar. Als dit project een beheerd taalproject is dat is geschreven in C# of Visual Basic, bevat hetzelfde WinMD-bestand ook de implementatie van deze typen (wat betekent dat het alle IL bevat die is gecompileerd vanuit de broncode van de ontwikkelaar). Dergelijke bestanden worden beheerde WinMD-bestanden genoemd. Ze zijn interessant omdat ze zowel Windows Runtime-metagegevens als de onderliggende implementatie bevatten.
Als een ontwikkelaar daarentegen een Windows Runtime Component-project voor C++maakt, produceert een build van dat project een WinMD-bestand met alleen metagegevens en wordt de implementatie gecompileerd in een afzonderlijke systeemeigen DLL. Op dezelfde manier bevatten de WinMD-bestanden die worden verzonden in de Windows SDK alleen metagegevens, waarbij de implementatie is gecompileerd in afzonderlijke systeemeigen DLL's die als onderdeel van Windows worden verzonden.
De onderstaande informatie is van toepassing op zowel beheerde WinMD's, die metagegevens en implementatie bevatten, en op niet-beheerde WinMD's, die alleen metagegevens bevatten.
WinMD-bestanden zien eruit als CLR-modules
Wat de CLR betreft, zijn alle WinMD-bestanden modules. De CLR-profilerings-API vertelt uw Profiler-DLL daarom wanneer WinMD-bestanden worden geladen en wat hun module-id's zijn, op dezelfde manier als voor andere beheerde modules.
Uw Profiler DLL kan WinMD-bestanden onderscheiden van andere modules door de methode ICorProfilerInfo3::GetModuleInfo2 aan te roepen en de pdwModuleFlags
uitvoerparameter voor de COR_PRF_MODULE_WINDOWS_RUNTIME vlag te controleren. (Deze wordt ingesteld als en alleen als de ModuleID een WinMD vertegenwoordigt.)
Metagegevens van WinMD's lezen
WinMD-bestanden, zoals gewone modules, bevatten metagegevens die kunnen worden gelezen via de metagegevens-API's. De CLR wijst Echter Windows Runtime-typen toe aan .NET Framework-typen wanneer er WinMD-bestanden worden gelezen, zodat ontwikkelaars die programma's uitvoeren in beheerde code en het WinMD-bestand gebruiken, een natuurlijkere programmeerervaring kunnen hebben. Zie .NET Framework-ondersteuning voor Windows Store-apps en Windows Runtime voor enkele voorbeelden van deze toewijzingen.
Welke weergave krijgt uw profiler dan wanneer deze gebruikmaakt van de metagegevens-API's: de onbewerkte Windows Runtime-weergave of de toegewezen .NET Framework-weergave? Het antwoord: het is aan jou.
Wanneer u de methode ICorProfilerInfo::GetModuleMetaData aanroept op een WinMD om een metagegevensinterface te verkrijgen, zoals IMetaDataImport, kunt u ervoor kiezen om een set vanNoTransform in de dwOpenFlags
parameter uit te schakelen om deze toewijzing uit te schakelen. Anders wordt de toewijzing standaard ingeschakeld. Normaal gesproken houdt een profiler de toewijzing ingeschakeld, zodat de tekenreeksen die de Profiler-DLL verkrijgt van de WinMD-metagegevens (bijvoorbeeld namen van typen) er vertrouwd en natuurlijk uitzien voor de profilergebruiker.
Metagegevens wijzigen van WinMD's
Het wijzigen van metagegevens in WinMD's wordt niet ondersteund. Als u de methode ICorProfilerInfo::GetModuleMetaData aanroept voor een WinMD-bestand en in de dwOpenFlags
parameter opgeeft of vraagt om een beschrijfbare metagegevensinterface zoals IMetaDataEmit, mislukt GetModuleMetaData. Dit is van bijzonder belang voor IL-herschrijven van profilers, die metagegevens moeten wijzigen om hun instrumentatie te ondersteunen (bijvoorbeeld om AssemblyRefs of nieuwe methoden toe te voegen). Controleer daarom eerst op COR_PRF_MODULE_WINDOWS_RUNTIME (zoals besproken in de vorige sectie) en vraag niet om schrijfbare metagegevensinterfaces voor dergelijke modules.
Assemblyverwijzingen oplossen met WinMD's
Veel profilers moeten metagegevensverwijzingen handmatig oplossen om te helpen bij instrumentatie of typeinspectie. Dergelijke profilers moeten zich bewust zijn van hoe de CLR assemblyverwijzingen die verwijzen naar WinMD's, oplost, omdat deze verwijzingen op een volledig andere manier worden omgezet dan standaardassemblyverwijzingen.
Geheugen profilers
De garbagecollector en beheerde heap zijn niet fundamenteel anders in een Windows Store-app en een desktop-app. Er zijn echter enkele subtiele verschillen waar profilerauteurs rekening mee moeten houden.
ForceGC maakt een beheerde thread
Wanneer u geheugenprofilering uitvoert, maakt uw Profiler-DLL doorgaans een afzonderlijke thread van waaruit de methode ForceGC-methode moet worden aangeroepen. Dit is niets nieuws. Maar wat misschien verrassend is, is dat het uitvoeren van een garbagecollection in een Windows Store-app uw thread kan transformeren in een beheerde thread (bijvoorbeeld een Profilering-API ThreadID wordt gemaakt voor die thread).
Als u de gevolgen hiervan wilt begrijpen, is het belangrijk om inzicht te hebben in de verschillen tussen synchrone en asynchrone aanroepen, zoals gedefinieerd door de CLR-profilerings-API. Houd er rekening mee dat dit heel anders is dan het concept van asynchrone aanroepen in Windows Store-apps. Zie het blogbericht Waarom hebben we CORPROF_E_UNSUPPORTED_CALL_SEQUENCE voor meer informatie.
Het relevante punt is dat aanroepen die worden gedaan op threads die door uw profiler zijn gemaakt, altijd synchroon worden beschouwd, zelfs als deze aanroepen worden uitgevoerd van buiten een implementatie van een van de ICorProfilerCallback-methoden van uw Profiler DLL. Dat was tenminste het geval. Nu de CLR de thread van uw profiler heeft omgezet in een beheerde thread vanwege uw aanroep naar forceGC-methode, wordt die thread niet langer beschouwd als de thread van uw profiler. Als zodanig dwingt de CLR een strengere definitie af van wat als synchroon voor die thread wordt aangemerkt, namelijk dat een aanroep afkomstig moet zijn van binnen een van de ICorProfilerCallback-methoden van uw Profiler DLL om in aanmerking te komen als synchroon.
Wat betekent dit in de praktijk? De meeste ICorProfilerInfo-methoden zijn alleen veilig om synchroon aan te roepen en zullen anders onmiddellijk mislukken. Dus als uw Profiler-DLL uw ForceGC-methodethread opnieuw gebruikt voor andere aanroepen die doorgaans worden uitgevoerd op door profiler gemaakte threads (bijvoorbeeld voor RequestProfilerDetach, RequestReJIT of RequestRevert), hebt u problemen. Zelfs een asynchrone veilige functie zoals DoStackSnapshot heeft speciale regels wanneer deze vanuit beheerde threads wordt aangeroepen. (Zie het blogbericht Profiler stack walking: Basics and beyond for more information.)
Daarom raden we aan dat elke thread die uw Profiler DLL maakt om forceGC-methode aan te roepen, alleen moet worden gebruikt om GCs te activeren en vervolgens te reageren op de GC-callbacks. Er mag geen verbinding worden gemaakt met de profilerings-API om andere taken uit te voeren, zoals stacksampling of loskoppelen.
ConditionalWeakTableReferences
Vanaf .NET Framework 4.5 is er een nieuwe GC-callback, ConditionalWeakTableElementReferences, waarmee de profiler meer volledige informatie over afhankelijke ingangen krijgt. Deze ingangen voegen effectief een verwijzing van een bronobject toe aan een doelobject voor het beheer van de levensduur van GC. Afhankelijke ingangen zijn niets nieuws en ontwikkelaars die in beheerde code programmeren, hebben hun eigen afhankelijke ingangen kunnen maken met behulp van de System.Runtime.CompilerServices.ConditionalWeakTable<TKey,TValue> klasse, zelfs vóór Windows 8 en .NET Framework 4.5.
Beheerde XAML Windows Store-apps maken nu echter intensief gebruik van afhankelijke ingangen. De CLR gebruikt deze met name om te helpen bij het beheren van referentiecycli tussen beheerde objecten en onbeheerde Windows Runtime-objecten. Dit betekent dat het nu belangrijker is dat geheugen profilers op de hoogte worden gesteld van deze afhankelijke ingangen, zodat ze samen met de rest van de randen in de heap-grafiek kunnen worden gevisualiseerd. Uw Profiler DLL moet RootReferences2, ObjectReferences en ConditionalWeakTableElementReferences samen gebruiken om een volledige weergave van de heap-grafiek te vormen.
Conclusie
Het is mogelijk om de CLR-profilerings-API te gebruiken om beheerde code te analyseren die wordt uitgevoerd in Windows Store-apps. U kunt zelfs een bestaande profiler gebruiken die u ontwikkelt en een aantal specifieke wijzigingen aanbrengt, zodat deze gericht is op Windows Store-apps. Uw Profiler-gebruikersinterface moet de nieuwe API's gebruiken voor het activeren van de Windows Store-app in de foutopsporingsmodus. Zorg ervoor dat uw Profiler-DLL alleen de API's gebruikt die van toepassing zijn op Windows Store-apps. Het communicatiemechanisme tussen uw Profiler DLL en Profiler-gebruikersinterface moet worden geschreven met de API-beperkingen van de Windows Store-app in gedachten en met kennis van de beperkte machtigingen voor Windows Store-apps. Uw Profiler DLL moet op de hoogte zijn van hoe de CLR WinMD's behandelt en hoe het gedrag van de garbagecollector verschilt met betrekking tot beheerde threads.
Resources
De Common Language Runtime
De interactie van de CLR met Windows Runtime
Windows Store-apps