Udostępnij za pośrednictwem


Profilery CLR i aplikacje sklepu Windows Store

W tym temacie omówiono, co należy wziąć pod uwagę podczas pisania narzędzi diagnostycznych, które analizują kod zarządzany uruchomiony w aplikacji ze Sklepu Windows. Zawiera również wskazówki dotyczące modyfikowania istniejących narzędzi programistycznych, aby nadal działały po uruchomieniu ich w aplikacjach ze Sklepu Windows. Aby zrozumieć te informacje, najlepiej jest zapoznać się z interfejsem API profilowania środowiska uruchomieniowego języka wspólnego, ten interfejs API został już użyty w narzędziu diagnostycznym, które działa poprawnie w aplikacjach klasycznych systemu Windows, a teraz interesuje Cię modyfikowanie narzędzia w celu poprawnego uruchamiania względem aplikacji ze Sklepu Windows.

Wprowadzenie

Jeśli został on wklejony w akapicie wprowadzającym, znasz interfejs API profilowania CLR. Utworzono już narzędzie diagnostyczne, które działa dobrze w przypadku zarządzanych aplikacji klasycznych. Teraz zastanawiasz się, co zrobić, aby narzędzie działało z zarządzaną aplikacją ze Sklepu Windows. Być może już próbowano wykonać tę pracę i odkryliśmy, że nie jest to proste zadanie. Rzeczywiście, istnieje wiele zagadnień, które mogą nie być oczywiste dla wszystkich deweloperów narzędzi. Na przykład:

  • Aplikacje ze Sklepu Windows działają w kontekście z poważnie ograniczonymi uprawnieniami.

  • Pliki metadanych systemu Windows mają unikatowe cechy w porównaniu z tradycyjnymi modułami zarządzanymi.

  • Aplikacje ze Sklepu Windows mają zwyczaj zawieszania się, gdy interakcyjność spada.

  • Mechanizmy komunikacji między procesami mogą już nie działać z różnych powodów.

W tym temacie wymieniono rzeczy, o których należy pamiętać, oraz o tym, jak prawidłowo sobie z nimi poradzić.

Jeśli dopiero zaczynasz korzystać z interfejsu API profilowania CLR, przejdź do sekcji Zasoby na końcu tego tematu, aby znaleźć lepsze informacje wprowadzające.

Podawanie szczegółowych informacji na temat określonych interfejsów API systemu Windows i sposobu ich użycia jest również poza zakresem tego tematu. Zapoznaj się z tym tematem punktem wyjścia i zapoznaj się z witryną MSDN, aby dowiedzieć się więcej o wszelkich interfejsach API systemu Windows, do których odwołuje się tutaj.

Architektura i terminologia

Zazwyczaj narzędzie diagnostyczne ma architekturę podobną do przedstawionej na poniższej ilustracji. Używa on terminu "profiler", ale wiele takich narzędzi wykracza daleko poza typową wydajność lub profilowanie pamięci w takich obszarach, jak pokrycie kodu, pozorowanie struktur obiektów, debugowanie podróży czasowych, monitorowanie aplikacji itd. Dla uproszczenia ten temat będzie nadal odnosić się do wszystkich tych narzędzi jako profilatorów.

W tym temacie jest używana następująca terminologia:

Aplikacja

Jest to aplikacja, którą analizuje profiler. Zazwyczaj deweloper tej aplikacji używa profilera do diagnozowania problemów z aplikacją. Tradycyjnie ta aplikacja będzie aplikacją klasyczną systemu Windows, ale w tym temacie przyjrzymy się aplikacjom ze Sklepu Windows.

Biblioteka DLL profilera

Jest to składnik, który ładuje się do przestrzeni procesowej analizowanej aplikacji. Ten składnik, znany również jako profiler "agent", implementuje interfejsY ICorProfilerCallbackICorProfilerCallback Interface(2,3 itp.) i korzysta z interfejsów ICorProfilerInfo(2,3 itp.), aby zbierać dane dotyczące analizowanej aplikacji i potencjalnie modyfikować aspekty zachowania aplikacji.

Interfejs użytkownika profilera

Jest to aplikacja klasyczna, z którą użytkownik profilera wchodzi w interakcję. Jest on odpowiedzialny za wyświetlanie stanu aplikacji użytkownikowi i nadanie użytkownikowi środków kontrolowania zachowania analizowanej aplikacji. Ten składnik zawsze działa we własnym obszarze procesu, niezależnie od obszaru procesu profilowanego aplikacji. Interfejs użytkownika profilera może również działać jako "wyzwalacz dołączania", który jest procesem wywołującym metodę ICLRProfiling::AttachProfiler , aby spowodować załadowanie analizowanej aplikacji dll profilera w tych przypadkach, gdy biblioteka DLL profilera nie została załadowana podczas uruchamiania.

Ważne

Interfejs użytkownika profilera powinien pozostać aplikacją klasyczną systemu Windows, nawet jeśli jest używany do kontrolowania i raportowania w aplikacji ze Sklepu Windows. Nie spodziewaj się, że będzie można spakować i wysłać narzędzie diagnostyczne w Sklepie Windows. Narzędzie musi wykonywać czynności, których aplikacje ze Sklepu Windows nie mogą wykonywać, a wiele z tych elementów znajduje się w interfejsie użytkownika profilera.

W tym dokumencie przykładowy kod zakłada, że:

  • Biblioteka DLL profilera jest napisana w języku C++, ponieważ musi być natywną biblioteką DLL zgodnie z wymaganiami interfejsu API profilowania CLR.

  • Interfejs użytkownika profilera jest napisany w języku C#. Nie jest to konieczne, ale ponieważ nie ma żadnych wymagań dotyczących języka procesu interfejsu użytkownika profilera, dlaczego nie wybieraj języka, który jest zwięzły i prosty?

Urządzenia z systemem Windows RT

Urządzenia z systemem Windows RT są dość zablokowane. Profilerzy innych firm po prostu nie mogą być ładowane na takich urządzeniach. Ten dokument koncentruje się na komputerach z systemem Windows 8.

Korzystanie z interfejsów API środowisko wykonawcze systemu Windows

W wielu scenariuszach omówionych w poniższych sekcjach aplikacja klasyczna interfejsu użytkownika profilera musi korzystać z nowych interfejsów API środowisko wykonawcze systemu Windows. Warto zapoznać się z dokumentacją, aby zrozumieć, które interfejsy API środowisko wykonawcze systemu Windows mogą być używane z aplikacji klasycznych, oraz czy ich zachowanie różni się w przypadku wywołania z aplikacji klasycznych i aplikacji ze Sklepu Windows.

Jeśli interfejs użytkownika profilera jest napisany w kodzie zarządzanym, należy wykonać kilka kroków, aby ułatwić korzystanie z tych interfejsów API środowisko wykonawcze systemu Windows. Aby uzyskać więcej informacji, zobacz artykuł Managed Desktop apps and środowisko wykonawcze systemu Windows (Aplikacje klasyczne zarządzane i środowisko wykonawcze systemu Windows).

Ładowanie biblioteki DLL profilera

W tej sekcji opisano sposób, w jaki interfejs użytkownika profilera powoduje załadowanie biblioteki DLL profilera przez aplikację Ze Sklepu Windows. Kod omówiony w tej sekcji należy do aplikacji klasycznej interfejsu użytkownika profilera i dlatego obejmuje korzystanie z interfejsów API systemu Windows, które są bezpieczne dla aplikacji klasycznych, ale niekoniecznie bezpieczne dla aplikacji ze Sklepu Windows.

Interfejs użytkownika profilera może spowodować załadowanie biblioteki DLL profilera do przestrzeni procesowej aplikacji na dwa sposoby:

  • Podczas uruchamiania aplikacji, zgodnie ze zmiennymi środowiskowymi.

  • Dołączając do aplikacji po zakończeniu uruchamiania, wywołując metodę ICLRProfiling::AttachProfiler .

Jednym z pierwszych przeszkód będzie pobieranie ładowania początkowego i dołączania biblioteki DLL profilera do prawidłowej pracy z aplikacjami ze Sklepu Windows. Obie formy ładowania współdzielą pewne szczególne zagadnienia, więc zacznijmy od nich.

Typowe zagadnienia dotyczące uruchamiania i dołączania obciążeń

Podpisywanie biblioteki DLL profilera

Gdy system Windows próbuje załadować bibliotekę DLL profilera, sprawdza, czy biblioteka DLL profilera jest poprawnie podpisana. Jeśli tak nie jest, ładowanie nie powiedzie się domyślnie. Istnieją dwa sposoby wykonania tej czynności:

  • Upewnij się, że biblioteka DLL profilera jest podpisana.

  • Przed użyciem narzędzia poinformuj użytkownika, że musi zainstalować licencję dewelopera na swoim komputerze z systemem Windows 8. Można to zrobić automatycznie z poziomu programu Visual Studio lub ręcznie z poziomu wiersza polecenia. Aby uzyskać więcej informacji, zobacz Uzyskiwanie licencji dewelopera.

Uprawnienia systemu plików

Aplikacja Ze Sklepu Windows musi mieć uprawnienia do ładowania i wykonywania biblioteki DLL profilera z lokalizacji w systemie plików, w którym znajduje się Domyślnie, aplikacja Ze Sklepu Windows nie ma takich uprawnień do większości katalogów, a każda nieudana próba załadowania biblioteki DLL profilera spowoduje utworzenie wpisu w dzienniku zdarzeń aplikacji systemu Windows, który wygląda następująco:

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].

Ogólnie rzecz biorąc, aplikacje ze Sklepu Windows mogą uzyskiwać dostęp tylko do ograniczonego zestawu lokalizacji na dysku. Każda aplikacja ze Sklepu Windows może uzyskiwać dostęp do własnych folderów danych aplikacji, a także kilku innych obszarów w systemie plików, dla których udzielono dostępu wszystkim aplikacjom ze Sklepu Windows. Najlepiej zainstalować bibliotekę DLL profilera i jej zależności w obszarze Program Files lub Program Files (x86), ponieważ wszystkie aplikacje ze Sklepu Windows domyślnie mają uprawnienia do odczytu i wykonywania.

Ładowanie uruchamiania

Zazwyczaj w aplikacji klasycznej interfejs użytkownika profilera monituje o uruchomienie biblioteki DLL profilera, inicjując blok środowiska zawierający wymagane zmienne środowiskowe interfejsu API profilowania CLR (tj COR_PROFILER. , COR_ENABLE_PROFILINGi COR_PROFILER_PATH), a następnie tworząc nowy proces z tym blokiem środowiska. To samo dotyczy aplikacji ze Sklepu Windows, ale mechanizmy są różne.

Nie uruchamiaj podwyższonego poziomu uprawnień

Jeśli proces A próbuje zduplikować proces aplikacji ze Sklepu Windows B, proces A powinien być uruchamiany na średnim poziomie integralności, a nie na wysokim poziomie integralności (czyli nie podwyższonym poziomem uprawnień). Oznacza to, że interfejs użytkownika profilera powinien działać na średnim poziomie integralności lub musi zduplikować inny proces pulpitu na średnim poziomie integralności, aby dbać o uruchomienie aplikacji Ze Sklepu Windows.

Wybieranie aplikacji ze Sklepu Windows do profilowania

Najpierw należy poprosić użytkownika profilera o uruchomienie aplikacji ze Sklepu Windows. W przypadku aplikacji klasycznych być może zostanie wyświetlone okno dialogowe Przeglądania pliku, a użytkownik znajdzie i wybierze plik .exe. Ale aplikacje ze Sklepu Windows są różne, a korzystanie z okna dialogowego Przeglądania nie ma sensu. Zamiast tego lepiej jest wyświetlić użytkownikowi listę aplikacji ze Sklepu Windows zainstalowanych dla tego użytkownika do wyboru.

Możesz użyć PackageManager klasy , aby wygenerować tę listę. PackageManagerto klasa środowisko wykonawcze systemu Windows, która jest dostępna dla aplikacji klasycznych, a w rzeczywistości jest dostępna tylko dla aplikacji klasycznych.

Poniższy przykład kodu z hipotetycznego interfejsu użytkownika profilera napisanego jako aplikacja klasyczna w języku C# używa elementu PackageManager do generowania listy aplikacji systemu Windows:

string currentUserSID = WindowsIdentity.GetCurrent().User.ToString();
IAppxFactory appxFactory = (IAppxFactory) new AppxFactory();
PackageManager packageManager = new PackageManager();
IEnumerable<Package> packages = packageManager.FindPackagesForUser(currentUserSID);

Określanie niestandardowego bloku środowiska

Nowy interfejs COM IPackageDebug Ustawienia umożliwia dostosowanie zachowania wykonywania aplikacji ze Sklepu Windows, aby ułatwić wykonywanie niektórych form diagnostyki. Jedną z jego metod, EnableDebugging, umożliwia przekazanie bloku środowiska do aplikacji Ze Sklepu Windows po jej uruchomieniu, wraz z innymi przydatnymi efektami, takimi jak wyłączenie automatycznego zawieszenia procesów. Blok środowiska jest ważny, ponieważ w tym miejscu należy określić zmienne środowiskowe (COR_PROFILER, COR_ENABLE_PROFILINGi COR_PROFILER_PATH)) używane przez clR do załadowania biblioteki DLL profilera.

Rozważmy następujący fragment kodu:

IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, debuggerCommandLine,
                                                                 (IntPtr)fixedEnvironmentPzz);

Istnieje kilka elementów, które należy uzyskać prawidłowo:

  • packageFullName można określić podczas iteracji pakietów i chwytania package.Id.FullName.

  • debuggerCommandLine jest nieco bardziej interesujące. Aby przekazać blok środowiska niestandardowego do aplikacji Ze Sklepu Windows, musisz napisać własny, uproszczony debuger fikcyjny. System Windows zduplikuje zawieszoną aplikację ze Sklepu Windows, a następnie dołącza debuger, uruchamiając debuger przy użyciu wiersza polecenia, jak w tym przykładzie:

    MyDummyDebugger.exe -p 1336 -tid 1424
    

    gdzie -p 1336 oznacza, że aplikacja ze Sklepu Windows ma identyfikator procesu 1336 i -tid 1424 oznacza, że wątek o identyfikatorze 1424 jest wątek, który jest zawieszony. Fikcyjny debuger przeanalizuje identyfikator ThreadID z wiersza polecenia, wznowi ten wątek, a następnie zamknij.

    Oto przykładowy kod C++, aby to zrobić (pamiętaj, aby dodać sprawdzanie błędów!):

    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;
    }
    

    Ten fikcyjny debuger należy wdrożyć w ramach instalacji narzędzia diagnostycznego, a następnie określić ścieżkę do tego debugera w parametrze debuggerCommandLine .

Uruchamianie aplikacji ze Sklepu Windows

Nadszedł moment na uruchomienie aplikacji ze Sklepu Windows. Jeśli już próbowano to zrobić samodzielnie, być może zauważysz, że metoda CreateProcess nie jest sposobem tworzenia procesu aplikacji ze Sklepu Windows. Zamiast tego należy użyć metody IApplicationActivationManager::ActivateApplication . W tym celu należy pobrać identyfikator modelu użytkownika aplikacji ze Sklepu Windows, która jest uruchamiana. Oznacza to, że musisz trochę zagłębić się w manifest.

Podczas iteracji nad pakietami (zobacz "Wybieranie aplikacji ze Sklepu Windows do profilu" w sekcji Ładowanie uruchamiania wcześniej), należy pobrać zestaw aplikacji zawartych w manifeście bieżącego pakietu:

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();

Tak, jeden pakiet może mieć wiele aplikacji, a każda aplikacja ma własny identyfikator modelu użytkownika aplikacji. Dlatego należy poprosić użytkownika, który aplikacja ma profilować, i pobrać identyfikator modelu użytkownika aplikacji z tej konkretnej aplikacji:

while (appsEnum.GetHasCurrent() != 0)
{
    IAppxManifestApplication app = appsEnum.GetCurrent();
    string appUserModelId = app.GetAppUserModelId();
    //...
}

Na koniec masz teraz elementy potrzebne do uruchomienia aplikacji ze Sklepu Windows:

IApplicationActivationManager appActivationMgr = new ApplicationActivationManager();
appActivationMgr.ActivateApplication(appUserModelId, appArgs, ACTIVATEOPTIONS.AO_NONE, out pid);

Pamiętaj, aby wywołać polecenie DisableDebugging

Po wywołaniu metody IPackageDebug Ustawienia::EnableDebugging otrzymasz obietnicę, że wyczyścisz je samodzielnie, wywołując metodę IPackageDebug Ustawienia::D isableDebugging, więc pamiętaj, aby to zrobić, gdy sesja profilowania się skończyła.

Dołączanie ładowania

Gdy interfejs użytkownika profilera chce dołączyć bibliotekę DLL profilera do aplikacji, która została już uruchomiona, używa biblioteki ICLRProfiling::AttachProfiler. To samo dotyczy aplikacji ze Sklepu Windows. Oprócz typowych zagadnień wymienionych wcześniej upewnij się, że docelowa aplikacja ze Sklepu Windows nie jest zawieszona.

EnableDebugging

Podobnie jak w przypadku ładowania uruchamiania, wywołaj metodę IPackageDebug Ustawienia::EnableDebugging. Nie potrzebujesz go do przekazywania bloku środowiskowego, ale potrzebujesz jednej z innych funkcji: wyłączania automatycznego zawieszenia procesów. W przeciwnym razie, gdy interfejs użytkownika profilera wywołuje funkcję AttachProfiler, docelowa aplikacja ze Sklepu Windows może zostać zawieszona. W rzeczywistości jest to prawdopodobne, jeśli użytkownik korzysta teraz z interfejsu użytkownika profilera, a aplikacja ze Sklepu Windows nie jest aktywna na żadnym ekranie użytkownika. Jeśli aplikacja ze Sklepu Windows jest zawieszona, nie będzie mogła odpowiedzieć na żaden sygnał, który CLR wysyła do niej w celu dołączenia biblioteki DLL profilera.

W związku z tym należy wykonać następujące czynności:

IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, null /* debuggerCommandLine */,
                                                                 IntPtr.Zero /* environment */);

Jest to to samo wywołanie, które należy wykonać w przypadku ładowania uruchamiania, z wyjątkiem tego, że nie określasz wiersza polecenia debugera ani bloku środowiskowego.

DisableDebugging

Jak zawsze, nie zapomnij wywołać elementu IPackageDebug Ustawienia::D isableDebugging po zakończeniu sesji profilowania.

Uruchamianie wewnątrz aplikacji ze Sklepu Windows

Dlatego aplikacja Ze Sklepu Windows w końcu załadowała bibliotekę DLL profilera. Teraz biblioteka DLL profilera musi być nauczona sposobu odtwarzania przez różne reguły wymagane przez aplikacje ze Sklepu Windows, w tym interfejsy API, które są dozwolone i jak uruchamiać z ograniczonymi uprawnieniami.

Trzymanie się interfejsów API aplikacji ze Sklepu Windows

Podczas przeglądania interfejsu API systemu Windows zauważysz, że każdy interfejs API jest udokumentowany jako odpowiedni dla aplikacji klasycznych, aplikacji ze Sklepu Windows lub obu tych elementów. Na przykład sekcja Wymagania dokumentacji funkcji InitializeCriticalSectionAndSpinCount wskazuje, że funkcja ma zastosowanie tylko do aplikacji klasycznych. Natomiast funkcja InitializeCriticalSectionEx jest dostępna zarówno dla aplikacji klasycznych, jak i aplikacji ze Sklepu Windows.

Podczas tworzenia biblioteki DLL profilera należy traktować ją tak, jakby była aplikacją ze Sklepu Windows i używać tylko interfejsów API, które są udokumentowane jako dostępne dla aplikacji ze Sklepu Windows. Przeanalizuj zależności (na przykład możesz uruchomić link /dump /imports z biblioteką DLL profilera w celu przeprowadzenia inspekcji), a następnie przeszukaj dokumenty, aby zobaczyć, które z zależności są prawidłowe i które nie są. W większości przypadków naruszenia można naprawić, zastępując je nowszą formą interfejsu API udokumentowaną jako bezpieczną (na przykład zastępując element InitializeCriticalSectionAndSpinCount wartością InitializeCriticalSectionAndSpinCount wartością InitializeCriticalSectionEx).

Możesz zauważyć, że biblioteka DLL profilera wywołuje niektóre interfejsy API, które mają zastosowanie tylko do aplikacji klasycznych, a jednak wydają się działać nawet wtedy, gdy biblioteka DLL profilera jest ładowana wewnątrz aplikacji ze Sklepu Windows. Pamiętaj, że ryzykowne jest użycie żadnego interfejsu API, który nie został udokumentowany do użycia z aplikacjami ze Sklepu Windows w pliku DLL profilera podczas ładowania do procesu aplikacji ze Sklepu Windows:

  • Takie interfejsy API nie mają gwarancji, że działają po wywołaniu w unikatowym kontekście, w jakim działają aplikacje ze Sklepu Windows.

  • Takie interfejsy API mogą nie działać spójnie, gdy są wywoływane z różnych procesów aplikacji ze Sklepu Windows.

  • Takie interfejsy API mogą wydawać się działać prawidłowo z aplikacji ze Sklepu Windows w bieżącej wersji systemu Windows, ale mogą zostać przerwane lub wyłączone w przyszłych wersjach systemu Windows.

Najlepszą radą jest naprawienie wszystkich naruszeń i uniknięcie ryzyka.

Może się okazać, że absolutnie nie można wykonać bez określonego interfejsu API i nie można odnaleźć zamiennika odpowiedniego dla aplikacji ze Sklepu Windows. W takim przypadku co najmniej:

  • Przetestuj, przetestuj dzienne światło dzienne z użycia tego interfejsu API.

  • Dowiedz się, że interfejs API może nagle przerwać lub zniknąć w przypadku wywołania z poziomu aplikacji ze Sklepu Windows w przyszłych wersjach systemu Windows. Nie zostanie to uznane za problem ze zgodnością firmy Microsoft i wspieranie korzystania z niego nie będzie priorytetem.

Ograniczone uprawnienia

Znajduje się on poza zakresem tego tematu, aby wyświetlić listę wszystkich sposobów, w jaki uprawnienia aplikacji ze Sklepu Windows różnią się od aplikacji klasycznych. Jednak z pewnością zachowanie będzie się różnić za każdym razem, gdy biblioteka DLL profilera (po załadowaniu do aplikacji ze Sklepu Windows w porównaniu z aplikacją klasyczną) próbuje uzyskać dostęp do dowolnych zasobów. System plików jest najbardziej typowym przykładem. Istnieje jednak kilka miejsc na dysku, do których dana aplikacja ze Sklepu Windows może uzyskać dostęp (zobacz Dostęp do plików i uprawnienia (środowisko wykonawcze systemu Windows aplikacje), a biblioteka DLL profilera będzie mieć takie same ograniczenia. Dokładnie przetestuj kod.

Komunikacja między procesami

Jak pokazano na diagramie na początku tego dokumentu, biblioteka DLL profilera (załadowana do obszaru procesów aplikacji Sklepu Windows) prawdopodobnie będzie musiała komunikować się z interfejsem użytkownika profilera (uruchomionym w oddzielnej przestrzeni procesów aplikacji klasycznych) za pośrednictwem własnego niestandardowego kanału komunikacji między procesami (IPC). Interfejs użytkownika profilera wysyła sygnały do biblioteki DLL profilera w celu zmodyfikowania jego zachowania, a biblioteka DLL profilera wysyła dane z przeanalizowanej aplikacji Ze Sklepu Windows z powrotem do interfejsu użytkownika profilera na potrzeby przetwarzania końcowego i wyświetlania użytkownikowi profilera.

Większość profilatorów musi działać w ten sposób, ale wybrane mechanizmy IPC są bardziej ograniczone, gdy biblioteka DLL profilera jest ładowana do aplikacji ze Sklepu Windows. Na przykład nazwane potoki nie są częścią zestawu SDK aplikacji ze Sklepu Windows, więc nie można ich używać.

Ale oczywiście pliki są nadal w, choć w bardziej ograniczony sposób. Dostępne są również zdarzenia.

Komunikacja za pośrednictwem plików

Większość danych prawdopodobnie przejdzie między biblioteką DLL profilera i interfejsem użytkownika profilera za pośrednictwem plików. Kluczem jest wybranie lokalizacji pliku, do której zarówno biblioteka DLL profilera (w kontekście aplikacji ze Sklepu Windows) jak i interfejs użytkownika profilera mają dostęp do odczytu i zapisu. Na przykład ścieżka folderu tymczasowego to lokalizacja, do której może uzyskać dostęp zarówno biblioteka DLL profilera, jak i interfejs użytkownika profilera, ale żaden inny pakiet aplikacji ze Sklepu Windows nie może uzyskać dostępu (w związku z tym osłona wszelkich informacji logujących się z innych pakietów aplikacji ze Sklepu Windows).

Zarówno interfejs użytkownika profilera, jak i biblioteka DLL profilera mogą niezależnie określić tę ścieżkę. Interfejs użytkownika profilera, gdy iteruje wszystkie pakiety zainstalowane dla bieżącego użytkownika (zobacz przykładowy kod wcześniej), uzyskuje dostęp do PackageId klasy, z której może pochodzić ścieżka folderu tymczasowego z kodem podobnym do tego fragmentu kodu. (Jak zawsze sprawdzanie błędów jest pomijane w celu zwięzłości).

// C# code for the Profiler UI.
ApplicationData appData =
    ApplicationDataManager.CreateForPackageFamily(
        packageId.FamilyName);

tempDir = appData.TemporaryFolder.Path;

W międzyczasie biblioteka DLL profilera może w zasadzie zrobić to samo, choć może łatwiej przejść do ApplicationData klasy przy użyciu właściwości ApplicationData.Current .

Komunikacja za pośrednictwem zdarzeń

Jeśli chcesz uzyskać prostą semantykę sygnalizacyjną między interfejsem użytkownika profilera i biblioteką DLL profilera, możesz użyć zdarzeń w aplikacjach ze Sklepu Windows, a także w aplikacjach klasycznych.

Z biblioteki DLL profilera można po prostu wywołać funkcję CreateEventEx , aby utworzyć nazwane zdarzenie o dowolnej nazwie. Na przykład:

// 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);

Następnie interfejs użytkownika profilera musi znaleźć to nazwane zdarzenie w przestrzeni nazw aplikacji Sklepu Windows. Na przykład interfejs użytkownika profilera może wywołać metodę CreateEventEx, określając nazwę zdarzenia jako

AppContainerNamedObjects\<acSid>\MyNamedEvent

<acSid> to identyfikator SID aplikacji ze Sklepu Windows AppContainer. We wcześniejszej sekcji tego tematu pokazano, jak iterować pakiety zainstalowane dla bieżącego użytkownika. Z tego przykładowego kodu można uzyskać identyfikator packageId. Z parametru packageId można uzyskać kod <acSid> podobny do następującego:

IntPtr acPSID;
DeriveAppContainerSidFromAppContainerName(packageId.FamilyName, out acPSID);

string acSid;
ConvertSidToStringSid(acPSID, out acSid);

string acDir;
GetAppContainerFolderPath(acSid, out acDir);

Brak powiadomień o zamknięciu

W przypadku uruchamiania wewnątrz aplikacji ze Sklepu Windows biblioteka DLL profilera nie powinna polegać na wywołaniu biblioteki DLL ICorProfilerCallback::Shutdown , a nawet dllMain (z DLL_PROCESS_DETACH) w celu powiadomienia biblioteki DLL profilera o zakończeniu działania aplikacji Ze Sklepu Windows. W rzeczywistości należy się spodziewać, że nigdy nie będą one wywoływane. W przeszłości wiele bibliotek DLL profilera używało tych powiadomień jako wygodnych miejsc do opróżniania pamięci podręcznych na dysk, zamykania plików, wysyłania powiadomień z powrotem do interfejsu użytkownika profilera itp. Jednak teraz biblioteka DLL profilera musi być zorganizowana nieco inaczej.

Biblioteka DLL profilera powinna rejestrować informacje w miarę ich żywienia. Ze względu na wydajność możesz chcieć umieścić informacje wsadowe w pamięci i opróżnić je na dysk w miarę wzrostu rozmiaru partii po pewnym progu. Załóżmy jednak, że wszystkie informacje, które nie zostały jeszcze opróżnione na dysk, mogą zostać utracone. Oznacza to, że należy odpowiednio wybrać próg i że interfejs użytkownika profilera musi być wzmocniony, aby poradzić sobie z niekompletnymi informacjami napisanymi przez bibliotekę DLL profilera.

środowisko wykonawcze systemu Windows plików metadanych

Ten dokument znajduje się poza zakresem tego dokumentu, aby szczegółowo poznać pliki metadanych środowisko wykonawcze systemu Windows (WinMD). Ta sekcja jest ograniczona do sposobu, w jaki interfejs API profilowania ŚRODOWISKA CLR reaguje, gdy pliki WinMD są ładowane przez aplikację ze Sklepu Windows, którą analizuje biblioteka DLL profilera.

Zarządzane i niezarządzane dyski WinMD

Jeśli deweloper używa programu Visual Studio do utworzenia nowego projektu składnika środowisko wykonawcze systemu Windows, kompilacja tego projektu tworzy plik WinMD opisujący metadane (opisy typów klas, interfejsów itp.) utworzony przez dewelopera. Jeśli ten projekt jest projektem języka zarządzanego napisanym w języku C# lub Visual Basic, ten sam plik WinMD zawiera również implementację tych typów (co oznacza, że zawiera on wszystkie il skompilowane z kodu źródłowego dewelopera). Takie pliki są nazywane zarządzanymi plikami WinMD. Są one interesujące, ponieważ zawierają zarówno metadane środowisko wykonawcze systemu Windows, jak i podstawową implementację.

Natomiast jeśli deweloper tworzy projekt składnika środowisko wykonawcze systemu Windows dla języka C++, kompilacja tego projektu tworzy plik WinMD zawierający tylko metadane, a implementacja jest kompilowana w oddzielnej natywnej biblioteki DLL. Podobnie pliki WinMD dostarczane w zestawie Windows SDK zawierają tylko metadane, a implementacja skompilowana w oddzielne natywne biblioteki DLL dostarczane w ramach systemu Windows.

Poniższe informacje dotyczą zarówno zarządzanych dysków WinMD, które zawierają metadane i implementację, jak i do niezarządzonych dysków WinMD, które zawierają tylko metadane.

Pliki WinMD wyglądają jak moduły CLR

Jeśli chodzi o CLR, wszystkie pliki WinMD są modułami. W związku z tym interfejs API profilowania CLR informuje bibliotekę DLL profilera o załadowaniu plików WinMD i ich identyfikatorach modułów w taki sam sposób jak w przypadku innych zarządzanych modułów.

Biblioteka DLL profilera może odróżnić pliki WinMD z innych modułów, wywołując metodę ICorProfilerInfo3::GetModuleInfo2 i sprawdzając pdwModuleFlags parametr wyjściowy flagi COR_PRF_MODULE_WINDOWS_RUNTIME . (Jest on ustawiany tylko wtedy, gdy identyfikator ModuleID reprezentuje winMD).

Odczytywanie metadanych z dysków WinMD

Pliki WinMD, takie jak zwykłe moduły, zawierają metadane, które można odczytywać za pośrednictwem interfejsów API metadanych. Jednak clR mapuje środowisko wykonawcze systemu Windows typów na typy .NET Framework podczas odczytywania plików WinMD, aby deweloperzy, którzy programowali w kodzie zarządzanym i używają pliku WinMD, mogą mieć bardziej naturalne środowisko programowania. Aby zapoznać się z przykładami tych mapowań, zobacz .NET Framework Support for Windows Store Apps and środowisko wykonawcze systemu Windows (Obsługa programu .NET Framework dla aplikacji ze Sklepu Windows i środowisko wykonawcze systemu Windows).

Więc który widok będzie uzyskiwany przez profilera w przypadku korzystania z interfejsów API metadanych: nieprzetworzonego widoku środowisko wykonawcze systemu Windows lub zamapowanego widoku programu .NET Framework? Odpowiedź: to do Ciebie.

Gdy wywołasz metodę ICorProfilerInfo::GetModuleMetaData w usłudze WinMD w celu uzyskania interfejsu metadanych, takiego jak IMetaDataImport, możesz wybrać ustawienie elementuNoTransform w parametrze dwOpenFlags , aby wyłączyć to mapowanie. W przeciwnym razie domyślnie mapowanie zostanie włączone. Zazwyczaj profiler zachowa włączone mapowanie, tak aby ciągi, które biblioteka DLL profilera uzyskuje z metadanych WinMD (na przykład nazwy typów), wyglądały znajomo i naturalnie dla użytkownika profilera.

Modyfikowanie metadanych z dysków WinMD

Modyfikowanie metadanych w identyfikatorach WinMD nie jest obsługiwane. Jeśli wywołasz metodę ICorProfilerInfo::GetModuleMetaData dla pliku WinMD i określisz wartośćWrite w parametrze dwOpenFlags lub poprosisz o zapisywalny interfejs metadanych, taki jak IMetaDataEmit, getModuleMetaData zakończy się niepowodzeniem. Jest to szczególnie ważne dla profilatorów ponownego zapisywania w języku IL, które muszą modyfikować metadane w celu obsługi instrumentacji (na przykład w celu dodania elementów AssemblyRefs lub nowych metod). Dlatego należy najpierw sprawdzić COR_PRF_MODULE_WINDOWS_RUNTIME (zgodnie z opisem w poprzedniej sekcji) i powstrzymać się od monitowania o interfejsy metadanych z możliwością zapisu w takich modułach.

Rozpoznawanie odwołań do zestawów za pomocą dysków WinMD

Wielu profilatorów musi ręcznie rozpoznać odwołania do metadanych, aby ułatwić instrumentację lub inspekcję typów. Takie profileery muszą mieć świadomość, w jaki sposób CLR rozpoznaje odwołania do zestawów, które wskazują na dyski WinMD, ponieważ odwołania te są rozpoznawane w zupełnie inny sposób niż standardowe odwołania do zestawów.

Profileery pamięci

Moduł odśmiecaczy i zarządzana sterta nie różnią się zasadniczo w aplikacji ze Sklepu Windows i aplikacji klasycznej. Istnieją jednak pewne subtelne różnice, o których muszą wiedzieć autorzy profilera.

ForceGC tworzy zarządzany wątek

Podczas profilowania pamięci biblioteka DLL profilera zwykle tworzy oddzielny wątek, z którego ma być wywoływana metoda ForceGC . To nic nowego. Ale co może być zaskakujące, że działanie wykonywania odzyskiwania pamięci w aplikacji Ze Sklepu Windows może przekształcić wątek zarządzany (na przykład identyfikator ThreadID interfejsu API profilowania zostanie utworzony dla tego wątku).

Aby zrozumieć konsekwencje tego, należy zrozumieć różnice między synchronicznymi i asynchronicznymi wywołaniami zdefiniowanymi przez interfejs API profilowania CLR. Należy pamiętać, że różni się to bardzo od koncepcji wywołań asynchronicznych w aplikacjach ze Sklepu Windows. Aby uzyskać więcej informacji, zobacz wpis w blogu Dlaczego mamy CORPROF_E_UNSUPPORTED_CALL_SEQUENCE .

Istotnym punktem jest to, że wywołania wykonywane w wątkach utworzonych przez profilera są zawsze traktowane jako synchroniczne, nawet jeśli te wywołania są wykonywane spoza implementacji jednej z metod ICorProfilerCallback biblioteki DLL profilera. Przynajmniej tak było. Teraz, gdy clR zamienił wątek profilera w zarządzany wątek ze względu na wywołanie metody ForceGC, ten wątek nie jest już uważany za wątek profilera. W związku z tym clR wymusza bardziej rygorystyczną definicję tego, co kwalifikuje się jako synchroniczne dla tego wątku — mianowicie, że wywołanie musi pochodzić z wewnątrz jednej z metod ICorProfilerCallback biblioteki PROFILEr, aby kwalifikować się jako synchroniczne.

Co to oznacza w praktyce? Większość metod ICorProfilerInfo jest bezpieczna tylko do wywołania synchronicznego i natychmiast zakończy się niepowodzeniem. Dlatego jeśli biblioteka DLL profilera ponownie używa wątku metody ForceGC dla innych wywołań zwykle wykonanych w wątkach utworzonych przez profilera (na przykład w celu requestProfilerDetach, RequestReJIT lub RequestRevert), będziesz mieć problem. Nawet asynchroniczna funkcja bezpieczna, taka jak DoStackSnapshot , ma specjalne reguły wywoływane z zarządzanych wątków. (Zobacz wpis w bloguPrzechodzenie stosu profilera: Podstawy i nie tylko , aby uzyskać więcej informacji).

Dlatego zalecamy, aby dowolny wątek tworzony przez bibliotekę DLL profilera w celu wywołania metody ForceGC był używany tylko do celów wyzwalania kontrolerów domeny, a następnie odpowiadania na wywołania zwrotne GC. Nie należy wywoływać interfejsu API profilowania w celu wykonywania innych zadań, takich jak próbkowanie stosu lub odłączanie.

ConditionalWeakTableReferences

Począwszy od programu .NET Framework 4.5, istnieje nowe wywołanie zwrotne GC, ConditionalWeakTableElementReferences, które daje profilerowi bardziej kompletne informacje o zależnych dojściach. Te dojścia skutecznie dodają odwołanie z obiektu źródłowego do obiektu docelowego w celu zarządzania okresem istnienia GC. Dojścia zależne nie są niczym nowym, a deweloperzy, którzy programują w kodzie zarządzanym, mogli tworzyć własne dojścia zależne przy użyciu System.Runtime.CompilerServices.ConditionalWeakTable<TKey,TValue> klasy jeszcze przed systemem Windows 8 i .NET Framework 4.5.

Jednak zarządzane aplikacje ze Sklepu Windows XAML teraz intensywnie korzystają z zależnych dojść. W szczególności clR używa ich do zarządzania cyklami referencyjnymi między zarządzanymi obiektami i niezarządzanymi obiektami środowisko wykonawcze systemu Windows. Oznacza to, że teraz jest ważniejsze niż kiedykolwiek, aby profileery pamięci były informowane o tych zależnych uchwytach, aby można je było wizualizować wraz z resztą krawędzi na grafie stert. Biblioteka DLL profilera powinna używać elementów RootReferences2, ObjectReferences i ConditionalWeakTableElementReferences razem, aby utworzyć pełny widok grafu sterty.

Podsumowanie

Za pomocą interfejsu API profilowania CLR można analizować kod zarządzany uruchomiony w aplikacjach ze Sklepu Windows. W rzeczywistości możesz podjąć istniejący profiler, który tworzysz i wprowadzać określone zmiany, aby umożliwić mu kierowanie aplikacji ze Sklepu Windows. Interfejs użytkownika profilera powinien używać nowych interfejsów API do aktywowania aplikacji ze Sklepu Windows w trybie debugowania. Upewnij się, że biblioteka DLL profilera używa tylko tych interfejsów API, które mają zastosowanie do aplikacji ze Sklepu Windows. Mechanizm komunikacji między biblioteką DLL profilera i interfejsem użytkownika profilera powinien być napisany z uwzględnieniem ograniczeń interfejsu API aplikacji ze Sklepu Windows i świadomości ograniczonych uprawnień w aplikacjach ze Sklepu Windows. Biblioteka DLL profilera powinna być świadoma sposobu, w jaki clR traktuje dyski WinMD i jak zachowanie modułu odśmiecania pamięci różni się w odniesieniu do zarządzanych wątków.

Zasoby

Środowisko uruchomieniowe języka wspólnego

Interakcja środowiska CLR z środowisko wykonawcze systemu Windows

Aplikacje ze Sklepu Windows