Udostępnij za pośrednictwem


Sposoby lokalizowania zestawów przez środowisko uruchomieniowe

Uwaga

Ten artykuł jest specyficzny dla programu .NET Framework. Nie ma zastosowania do nowszych implementacji platformy .NET, w tym .NET 6 i nowszych wersji.

Aby pomyślnie wdrożyć aplikację .NET Framework, musisz zrozumieć, w jaki sposób środowisko uruchomieniowe języka wspólnego lokalizuje zestawy tworzące aplikację i wiąże je z zestawami. Domyślnie środowisko uruchomieniowe próbuje powiązać z dokładną wersją zestawu, za pomocą którego utworzono aplikację. To domyślne zachowanie może zostać zastąpione przez ustawienia pliku konfiguracji.

Środowisko uruchomieniowe języka wspólnego wykonuje szereg kroków podczas próby zlokalizowania zestawu i rozwiązania odwołania do zestawu. Każdy krok jest objaśniony w poniższych sekcjach. Termin sondowania jest często używany podczas opisywania sposobu lokalizowania zestawów przez środowisko uruchomieniowe; odnosi się do zestawu heurystyki używanego do lokalizowania zestawu na podstawie jego nazwy i kultury.

Uwaga

Informacje o powiązaniu można wyświetlić w pliku dziennika przy użyciu podglądu dziennika powiązań zestawów (Fuslogvw.exe), który jest dołączony do zestawu Windows SDK.

Inicjowanie powiązania

Proces lokalizowania i wiązania z zestawem rozpoczyna się, gdy środowisko uruchomieniowe próbuje rozpoznać odwołanie do innego zestawu. Odwołanie może być statyczne lub dynamiczne. Kompilator rejestruje odwołania statyczne w metadanych manifestu zestawu w czasie kompilacji. Odwołania dynamiczne są tworzone na bieżąco w wyniku wywoływania różnych metod, takich jak Assembly.Load.

Preferowanym sposobem odwołowania się do zestawu jest użycie pełnego odwołania, w tym nazwy zestawu, wersji, kultury i tokenu klucza publicznego (jeśli istnieje). Środowisko uruchomieniowe używa tych informacji do zlokalizowania zestawu, wykonując kroki opisane w dalszej części tej sekcji. Środowisko uruchomieniowe używa tego samego procesu rozwiązywania, niezależnie od tego, czy odwołanie dotyczy zestawu statycznego, czy dynamicznego.

Można również utworzyć dynamiczne odwołanie do zestawu, podając metodę wywołującą tylko częściowe informacje o zestawie, takie jak określanie tylko nazwy zestawu. W takim przypadku tylko katalog aplikacji jest wyszukiwany dla zestawu i nie ma innego sprawdzania. Należy utworzyć częściowe odwołanie przy użyciu dowolnej z różnych metod ładowania zestawów, takich jak Assembly.Load lub AppDomain.Load.

Na koniec możesz utworzyć odwołanie dynamiczne przy użyciu metody, takiej jak Assembly.Load i podać tylko częściowe informacje. Następnie należy zakwalifikować odwołanie przy użyciu <elementu qualifyAssembly> w pliku konfiguracji aplikacji. Ten element umożliwia podanie pełnych informacji referencyjnych (nazwa, wersja, kultura i, jeśli ma to zastosowanie, token klucza publicznego) w pliku konfiguracji aplikacji zamiast w kodzie. Ta technika jest używana, jeśli chcesz w pełni zakwalifikować odwołanie do zestawu spoza katalogu aplikacji lub jeśli chcesz odwołać się do zestawu w globalnej pamięci podręcznej zestawów, ale chcesz, aby wygoda określenia pełnego odwołania w pliku konfiguracji zamiast w kodzie.

Uwaga

Tego typu odwołania częściowego nie należy używać z zestawami, które są współużytkowane przez kilka aplikacji. Ponieważ ustawienia konfiguracji są stosowane dla aplikacji, a nie na zestaw, zestaw współużytkowany korzystający z tego typu odwołania częściowego wymagałby, aby każda aplikacja używająca zestawu udostępnionego miała informacje kwalifikacyjne w pliku konfiguracji.

Środowisko uruchomieniowe używa następujących kroków, aby rozwiązać problem z odwołaniem do zestawu:

  1. Określa poprawną wersję zestawu, sprawdzając odpowiednie pliki konfiguracji, w tym plik konfiguracji aplikacji, plik zasad wydawcy i plik konfiguracji maszyny. Jeśli plik konfiguracji znajduje się na maszynie zdalnej, środowisko uruchomieniowe musi najpierw zlokalizować i pobrać plik konfiguracji aplikacji.

  2. Sprawdza, czy nazwa zestawu została powiązana z poprzednią wersją i, jeśli tak, używa wcześniej załadowanego zestawu. Jeśli poprzednie żądanie załadowania zestawu nie powiodło się, żądanie nie powiedzie się natychmiast bez próby załadowania zestawu.

    Uwaga

    Buforowanie błędów powiązań zestawów jest nowe w programie .NET Framework w wersji 2.0.

  3. Sprawdza globalną pamięć podręczną zestawów. Jeśli zestaw zostanie tam znaleziony, środowisko uruchomieniowe używa tego zestawu.

  4. Sondy dla zestawu , wykonując następujące czynności:

    1. Jeśli zasady konfiguracji i wydawcy nie mają wpływu na oryginalne odwołanie i jeśli żądanie powiązania zostało utworzone przy użyciu Assembly.LoadFrom metody , środowisko uruchomieniowe sprawdza wskazówki dotyczące lokalizacji.

    2. Jeśli baza kodu zostanie znaleziona w plikach konfiguracji, środowisko uruchomieniowe sprawdza tylko tę lokalizację. Jeśli ta sonda nie powiedzie się, środowisko uruchomieniowe ustali, że żądanie powiązania nie powiodło się i nie wystąpi żadne inne sondowanie.

    3. Sondy dla zestawu przy użyciu heurystyki opisanej w sekcji sondowania. Jeśli zestaw nie zostanie znaleziony po sondowaniu, środowisko uruchomieniowe zażąda Instalatora Windows dostarczenia zestawu. Działa to jako funkcja instalacji na żądanie.

      Uwaga

      Nie ma sprawdzania wersji zestawów bez silnych nazw ani nie sprawdza środowiska uruchomieniowego w globalnej pamięci podręcznej zestawów dla zestawów bez silnych nazw.

Krok 1. Badanie plików konfiguracji

Zachowanie powiązania zestawu można skonfigurować na różnych poziomach na podstawie trzech plików XML:

  • Plik konfiguracji aplikacji.

  • Plik zasad wydawcy.

  • Plik konfiguracji maszyny.

Te pliki są zgodne z tą samą składnią i zawierają informacje, takie jak przekierowania powiązań, lokalizacja kodu i tryby powiązania dla określonych zestawów. Każdy plik konfiguracji może zawierać <element assemblyBinding>, który przekierowuje proces powiązania. Elementy podrzędne <elementu assemblyBinding> zawierają <element dependentAssembly>. Elementy podrzędne <elementu dependentAssembly> obejmują< element assemblyIdentity>,< element bindingRedirect> i< element codeBase>.

Uwaga

Informacje o konfiguracji można znaleźć w trzech plikach konfiguracji; nie wszystkie elementy są prawidłowe we wszystkich plikach konfiguracji. Na przykład informacje o trybie powiązania i ścieżce prywatnej mogą znajdować się tylko w pliku konfiguracji aplikacji. Aby uzyskać pełną listę informacji zawartych w każdym pliku, zobacz Konfigurowanie aplikacji przy użyciu plików konfiguracji.

Plik konfiguracji aplikacji

Najpierw środowisko uruchomieniowe języka wspólnego sprawdza plik konfiguracji aplikacji pod kątem informacji, które zastępują informacje o wersji przechowywane w manifeście zestawu wywołującego. Plik konfiguracji aplikacji można wdrożyć za pomocą aplikacji, ale nie jest wymagany do wykonywania aplikacji. Zazwyczaj pobieranie tego pliku jest niemal natychmiastowe, ale w sytuacjach, gdy baza aplikacji znajduje się na komputerze zdalnym, takim jak w scenariuszu opartym na sieci Web, należy pobrać plik konfiguracji.

W przypadku plików wykonywalnych klienta plik konfiguracji aplikacji znajduje się w tym samym katalogu co plik wykonywalny aplikacji i ma taką samą nazwę bazową jak plik wykonywalny z rozszerzeniem config. Na przykład plik konfiguracji C:\Program Files\Myapp\Myapp.exe to C:\Program Files\Myapp\Myapp.exe.config. W scenariuszu opartym na przeglądarce plik HTML musi używać elementu linku<>, aby jawnie wskazać plik konfiguracji.

Poniższy kod zawiera prosty przykład pliku konfiguracji aplikacji. W tym przykładzie Listeners dodano TextWriterTraceListener element do kolekcji w celu włączenia rejestrowania informacji debugowania do pliku.

<configuration>
   <system.diagnostics>
      <trace useGlobalLock="false" autoflush="true" indentsize="0">
         <listeners>
            <add name="myListener" type="System.Diagnostics.TextWriterTraceListener, system version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" initializeData="c:\myListener.log" />
         </listeners>
      </trace>
   </system.diagnostics>
</configuration>

Plik zasad wydawcy

Po drugie, środowisko uruchomieniowe sprawdza plik zasad wydawcy, jeśli istnieje. Pliki zasad wydawcy są dystrybuowane przez wydawcę składników jako poprawkę lub aktualizację do udostępnionego składnika. Te pliki zawierają informacje o zgodności wydane przez wydawcę składnika udostępnionego, który kieruje odwołanie do zestawu do nowej wersji. W przeciwieństwie do plików konfiguracji aplikacji i maszyny pliki zasad wydawcy są zawarte we własnym zestawie, który musi być zainstalowany w globalnej pamięci podręcznej zestawów.

Poniżej przedstawiono przykład pliku konfiguracji zasad wydawcy:

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

            <dependentAssembly>
                <assemblyIdentity name="asm6" publicKeyToken="c0305c36380ba429" />
                <bindingRedirect oldVersion="3.0.0.0" newVersion="2.0.0.0"/>
            </dependentAssembly>

        </assemblyBinding>
    </runtime>
</configuration>

Aby utworzyć zestaw, możesz użyć narzędzia Al.exe (konsolidatora zestawów) za pomocą polecenia takiego jak:

Al.exe /link:asm6.exe.config /out:policy.3.0.asm6.dll /keyfile: compatkey.dat /v:3.0.0.0

compatkey.dat jest plikiem klucza o silnej nazwie. To polecenie tworzy zestaw o silnej nazwie, który można umieścić w globalnej pamięci podręcznej zestawów.

Uwaga

Zasady wydawcy mają wpływ na wszystkie aplikacje korzystające ze składnika udostępnionego.

Plik konfiguracji zasad wydawcy zastępuje informacje o wersji pochodzące z aplikacji (czyli z manifestu zestawu lub pliku konfiguracji aplikacji). Jeśli w pliku konfiguracji aplikacji nie ma instrukcji w celu przekierowania wersji określonej w manifeście zestawu, plik zasad wydawcy zastępuje wersję określoną w manifeście zestawu. Jeśli jednak w pliku konfiguracji aplikacji istnieje instrukcja przekierowania, zasady wydawcy zastępują tę wersję, a nie określoną w manifeście.

Plik zasad wydawcy jest używany podczas aktualizowania składnika udostępnionego, a nowa wersja składnika udostępnionego powinna zostać odebrana przez wszystkie aplikacje korzystające z tego składnika. Ustawienia w pliku zasad wydawcy zastępują ustawienia w pliku konfiguracji aplikacji, chyba że plik konfiguracji aplikacji wymusza tryb awaryjny.

Tryb awaryjny

Pliki zasad wydawcy są zwykle jawnie instalowane w ramach dodatku Service Pack lub aktualizacji programu. Jeśli wystąpił problem z uaktualnionym składnikiem udostępnionym, możesz zignorować przesłonięcia w pliku zasad wydawcy przy użyciu trybu bezpiecznego. Tryb awaryjny jest określany przez <element publisherPolicy apply="yes|no"/> znajdujący się tylko w pliku konfiguracji aplikacji. Określa, czy informacje o konfiguracji zasad wydawcy powinny zostać usunięte z procesu powiązania.

Tryb awaryjny można ustawić dla całej aplikacji lub dla wybranych zestawów. Oznacza to, że można wyłączyć zasady dla wszystkich zestawów tworzących aplikację lub włączyć je dla niektórych zestawów, ale nie innych. Aby selektywnie zastosować zasady wydawcy do zestawów tworzących aplikację, ustaw wartość publisherPolicy apply=no/> i określ zestawy, których chcesz dotyczyć przy użyciu <elementu dependentAssembly>.< Aby zastosować zasady wydawcy do wszystkich zestawów tworzących aplikację, ustaw <wartość publisherPolicy apply=no/> bez elementów zestawu zależnego. Aby uzyskać więcej informacji na temat konfiguracji, zobacz Konfigurowanie aplikacji przy użyciu plików konfiguracji.

Plik konfiguracji maszyny

Po trzecie, środowisko uruchomieniowe sprawdza plik konfiguracji maszyny. Ten plik o nazwie Machine.config znajduje się na komputerze lokalnym w podkatalogu Config katalogu głównego, w którym zainstalowano środowisko uruchomieniowe. Ten plik może być używany przez administratorów do określania ograniczeń powiązań zestawów, które są lokalne dla tego komputera. Ustawienia w pliku konfiguracji maszyny mają pierwszeństwo przed wszystkimi innymi ustawieniami konfiguracji; nie oznacza to jednak, że wszystkie ustawienia konfiguracji powinny zostać umieszczone w tym pliku. Wersja określona przez plik zasad administratora jest ostateczna i nie można jej zastąpić. Przesłonięcia określone w pliku Machine.config mają wpływ na wszystkie aplikacje. Aby uzyskać więcej informacji na temat plików konfiguracji, zobacz Konfigurowanie aplikacji przy użyciu plików konfiguracji.

Krok 2. Sprawdzanie zestawów poprzednio występujących w odwołaniu

Jeśli żądany zestaw został również żądany w poprzednich wywołaniach, środowisko uruchomieniowe języka wspólnego używa już załadowanego zestawu. Może to mieć konsekwencje podczas nazewnictwa zestawów tworzących aplikację. Aby uzyskać więcej informacji na temat nazewnictwa zestawów, zobacz Nazwy zestawów.

Jeśli poprzednie żądanie zestawu nie powiodło się, kolejne żądania dotyczące zestawu zostaną natychmiast nieudane bez próby załadowania zestawu. Począwszy od programu .NET Framework w wersji 2.0, błędy powiązań zestawów są buforowane, a buforowane informacje służą do określania, czy próbuje załadować zestaw.

Uwaga

Aby przywrócić zachowanie programu .NET Framework w wersji 1.0 i 1.1, które nie zawierały błędów powiązań pamięci podręcznej, dołącz <element disableCachingBindingFailures> w pliku konfiguracji.

Krok 3. Sprawdzanie globalnej pamięci podręcznej zestawów

W przypadku zestawów o silnych nazwach proces powiązania jest kontynuowany, patrząc w globalnej pamięci podręcznej zestawów. Globalna pamięć podręczna zestawów przechowuje zestawy, które mogą być używane przez kilka aplikacji na komputerze. Wszystkie zestawy w globalnej pamięci podręcznej zestawów muszą mieć silne nazwy.

Krok 4. Lokalizowanie zestawu za pośrednictwem ścieżek bazowych kodu lub sondowania

Po ustaleniu prawidłowej wersji zestawu przy użyciu informacji w odwołaniu zestawu wywołującego i w plikach konfiguracji oraz po zaewidencjonowaniu globalnej pamięci podręcznej zestawów (tylko dla zestawów o silnych nazwach), środowisko uruchomieniowe języka wspólnego próbuje znaleźć zestaw. Proces lokalizowania zestawu obejmuje następujące kroki:

  1. <Jeśli element codeBase> znajduje się w pliku konfiguracji aplikacji, środowisko uruchomieniowe sprawdza określoną lokalizację. Jeśli zostanie znalezione dopasowanie, zostanie użyty zestaw i nie nastąpi sondowanie. Jeśli zestaw nie zostanie tam znaleziony, żądanie powiązania zakończy się niepowodzeniem.

  2. Następnie środowisko uruchomieniowe sonduje przywoływalny zestaw przy użyciu reguł określonych w dalszej części tej sekcji.

Uwaga

Jeśli masz wiele wersji zestawu w katalogu i chcesz odwołać się do określonej wersji tego zestawu, musisz użyć elementu codeBase> zamiast privatePath atrybutu< elementu sondowania>.< Jeśli używasz elementu sondowania>, środowisko uruchomieniowe zatrzymuje sondowanie przy pierwszym znalezieniu <zestawu zgodnego z prostą nazwą zestawu, do którego odwołuje się odwołanie, niezależnie od tego, czy jest to poprawne dopasowanie, czy nie. Jeśli jest to poprawne dopasowanie, używany jest ten zestaw. Jeśli nie jest to poprawne dopasowanie, sondowanie zatrzymuje się i wiązanie kończy się niepowodzeniem.

Lokalizowanie zestawu za pomocą baz kodu

Informacje o bazie kodu można dostarczyć przy użyciu <elementu codeBase> w pliku konfiguracji. Ta baza kodu jest zawsze sprawdzana przed próbą sondowania przez środowisko uruchomieniowe dla przywoływalego zestawu. Jeśli plik zasad wydawcy zawierający przekierowanie wersji ostatecznej zawiera również element codeBase, ten <element codeBase>> jest tym, który jest używany.< Jeśli na przykład plik konfiguracji aplikacji określa element codeBase>, a plik zasad wydawcy, który zastępuje informacje o aplikacji, określa< również element codeBase, <element codeBase>> w pliku zasad wydawcy jest używany.<

Jeśli nie zostanie znalezione dopasowanie w lokalizacji określonej przez <element codeBase> , żądanie powiązania zakończy się niepowodzeniem i nie zostaną wykonane żadne dalsze kroki. Jeśli środowisko uruchomieniowe ustali, że zestaw jest zgodny z kryteriami zestawu wywołującego, używa tego zestawu. Po załadowaniu pliku określonego przez dany <element codeBase> środowisko uruchomieniowe sprawdza, czy nazwa, wersja, kultura i klucz publiczny są zgodne z odwołaniem zestawu wywołującego.

Uwaga

Przywoływane zestawy spoza katalogu głównego aplikacji muszą mieć silne nazwy i muszą być zainstalowane w globalnej pamięci podręcznej zestawów lub określone przy użyciu elementu codeBase>.<

Lokalizowanie zestawu za pomocą sondowania

Jeśli w pliku konfiguracji aplikacji nie <ma elementu codeBase> , sondy środowiska uruchomieniowego dla zestawu przy użyciu czterech kryteriów:

  • Baza aplikacji, czyli lokalizacja główna, w której jest wykonywana aplikacja.

  • Kultura, która jest atrybutem kultury przywoływanego zestawu.

  • Nazwa, czyli nazwa przywołytowanego zestawu.

  • Atrybut privatePath<elementu sondowania> , który jest zdefiniowaną przez użytkownika listą podkatalogów w lokalizacji głównej. Tę lokalizację można określić w pliku konfiguracji aplikacji i w kodzie zarządzanym przy użyciu AppDomainSetup.PrivateBinPath właściwości dla domeny aplikacji. Po określeniu w kodzie zarządzanym kod privatePath zarządzany jest najpierw sondowany, a następnie ścieżkę określoną w pliku konfiguracji aplikacji.

Sondowanie katalogów bazy aplikacji i kultury

Środowisko uruchomieniowe zawsze rozpoczyna sondowanie w bazie aplikacji, co może być adresem URL lub katalogiem głównym aplikacji na komputerze. Jeśli nie można odnaleźć przywoływalnego zestawu w bazie aplikacji i nie podano informacji o kulturze, środowisko uruchomieniowe przeszukuje wszystkie podkatalogi z nazwą zestawu. Katalogi sondowane obejmują:

  • [baza aplikacji] / [nazwa zestawu].dll

  • [baza aplikacji] / [nazwa zestawu] / [nazwa zestawu].dll

Jeśli informacje o kulturze są określone dla przywoływanego zestawu, sondowane są tylko następujące katalogi:

  • [baza aplikacji] / [kultura] / [nazwa zestawu].dll

  • [baza aplikacji] / [kultura] / [nazwa zestawu] / [nazwa zestawu].dll

Sondowanie za pomocą atrybutu privatePath

Oprócz podkatalogów kultury i podkatalogów nazwanych dla zestawu, do którego odwołuje się zestaw, środowisko uruchomieniowe sonduje również katalogi określone przy użyciu privatePath atrybutu< elementu sondowania>. Katalogi określone przy użyciu atrybutu privatePath muszą być podkatalogami katalogu głównego aplikacji. Katalogi sondowane różnią się w zależności od tego, czy informacje o kulturze są zawarte w odwołanym żądaniu zestawu.

Środowisko uruchomieniowe zatrzymuje sondowanie przy pierwszym znalezieniu zestawu zgodnego z prostą nazwą zestawu, do którego odwołuje się, niezależnie od tego, czy jest to poprawne dopasowanie, czy nie. Jeśli jest to poprawne dopasowanie, używany jest ten zestaw. Jeśli nie jest to poprawne dopasowanie, sondowanie zatrzymuje się i wiązanie kończy się niepowodzeniem.

Jeśli jest uwzględniona kultura, następujące katalogi są sondowane:

  • [baza aplikacji] / [binpath] / [kultura] / [nazwa zestawu].dll

  • [application base] / [binpath] / [kultura] / [nazwa zestawu] / [nazwa zestawu].dll

Jeśli informacje o kulturze nie są uwzględnione, następujące katalogi są sondowane:

  • [baza aplikacji] / [binpath] / [nazwa zestawu].dll

  • [application base] / [binpath] / [nazwa zestawu] / [nazwa zestawu].dll

Przykłady sondowania

Biorąc pod uwagę następujące informacje:

  • Nazwa zestawu, do których odwołuje się odwołanie: myAssembly

  • Katalog główny aplikacji: http://www.code.microsoft.com

  • <element sondowania> w pliku konfiguracji określa: bin

  • Kultura: de

Środowisko uruchomieniowe sonduje następujące adresy URL:

  • http://www.code.microsoft.com/de/myAssembly.dll

  • http://www.code.microsoft.com/de/myAssembly/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly/myAssembly.dll

Wiele zestawów o tej samej nazwie

W poniższym przykładzie pokazano, jak skonfigurować wiele zestawów o tej samej nazwie.

<dependentAssembly>
   <assemblyIdentity name="Server" publicKeyToken="c0305c36380ba429" />
   <codeBase version="1.0.0.0" href="v1/Server.dll" />
   <codeBase version="2.0.0.0" href="v2/Server.dll" />
</dependentAssembly>

Inne lokalizacje sondowane

Lokalizację zestawu można również określić przy użyciu bieżącego kontekstu powiązania. Najczęściej występuje to, gdy Assembly.LoadFrom metoda jest używana i w scenariuszach międzyoperacyjności modelu COM. Jeśli zestaw używa LoadFrom metody do odwoływanie się do innego zestawu, lokalizacja wywołującego zestawu jest uważana za wskazówkę dotyczącą tego, gdzie można znaleźć przywoływał zestaw. Jeśli zostanie znalezione dopasowanie, zestaw zostanie załadowany. Jeśli nie zostanie znalezione dopasowanie, środowisko uruchomieniowe będzie nadal używać semantyki wyszukiwania, a następnie wysyła zapytanie do Instalatora Windows w celu udostępnienia zestawu. Jeśli nie podano zestawu zgodnego z żądaniem powiązania, zgłaszany jest wyjątek. Ten wyjątek jest w kodzie zarządzanym TypeLoadException , jeśli typ został przywoływany lub FileNotFoundException jeśli nie znaleziono załadowanego zestawu.

Jeśli na przykład zestaw1 odwołuje się do zestawu Assembly2 i Assembly1 został pobrany z http://www.code.microsoft.com/utilswitryny , ta lokalizacja jest uważana za wskazówkę dotyczącą tego, gdzie znaleźć Assembly2.dll. Następnie środowisko uruchomieniowe sonduje zestaw w systemach http://www.code.microsoft.com/utils/Assembly2.dll i http://www.code.microsoft.com/utils/Assembly2/Assembly2.dll. Jeśli zestaw2 nie zostanie znaleziony w żadnej z tych lokalizacji, środowisko uruchomieniowe wysyła zapytanie do Instalatora Windows.

Zobacz też