Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ważny
Informacje w tym temacie dotyczą wszystkich wersji systemu Windows 10 i nowszych. W tym miejscu będziemy odwoływać się do tych wersji jako "Windows", wywołując wszelkie wyjątki w razie potrzeby.
Zestawy interfejsów API korzystają z obsługi systemu operacyjnego w module ładujący biblioteki w celu wprowadzenia przekierowania przestrzeni nazw modułu do procesu powiązania biblioteki. Nazwa kontraktu zestawu interfejsu API nie nazywa pliku. Moduł ładujący wykonuje przekierowanie w czasie wykonywania z tej nazwy kontraktu do pliku binarnego hosta zawierającego implementację.
Gdy moduł ładujący napotka zależność od zestawu interfejsu API w czasie wykonywania, skonsultuje dane konfiguracji na obrazie, aby zidentyfikować plik binarny hosta dla tego zestawu interfejsów API. Te dane konfiguracji są nazywane schematem zestawu interfejsu API . Schemat jest zestawiony jako właściwość systemu operacyjnego, a mapowanie między zestawami interfejsów API i plikami binarnymi może się różnić w zależności od tego, które pliki binarne są uwzględniane na danym urządzeniu. Schemat umożliwia poprawne kierowanie zaimportowanej funkcji w jednym pliku binarnym na różnych urządzeniach nawet wtedy, gdy moduł hostujący implementację został zmieniony, podzielony lub refaktoryzowany.
Jak importy docierają do implementacji
Plik binarny może osiągnąć implementację zestawu interfejsu API na dwa sposoby, wybierając nazwę w tabeli importu:
- Importowanie zestawu interfejsu API bezpośredniego. Plik binarny importuje nazwę kontraktu zestawu interfejsu API. Moduł ładujący rozpoznaje tę nazwę za pomocą schematu zestawu interfejsu API do pliku binarnego hosta na bieżącym urządzeniu.
- Importowanie starszego modułu. Plik binarny importuje starszą nazwę modułu Windows, taką jak samplefeature.dll. W wersji dostarczanej przez ten moduł moduł modułu jest powiązany bezpośrednio z nim. W wersji, która go zastąpiła, usługa przesyłania dalej odwrotnego o tej samej nazwie przekierowuje import do zestawu interfejsu API, który moduł ładujący następnie rozpoznaje za pomocą schematu.
Które z tych nazw kończy się w tabeli importu jest zwykle określane przez bibliotekę, względem której łączysz, a nie przez źródło, względem którego piszesz. Zobacz Windows biblioteki parasolowe.
Preferuj nazwę kontraktu zestawu interfejsu API dla kodu, który jest przeznaczony dla bieżących wersji Windows. Moduł ładujący rozwiązuje go prosto z hostem bez usługi przesyłania dalej między. Zaimportuj starszą nazwę modułu, jeśli potrzebujesz pojedynczego pliku binarnego, który jest również uruchamiany w wersjach Windows wydanych przed utworzeniem zestawu interfejsu API. Przekazywanie wsteczne utrzymuje, że dane binarne działają w wersjach, w których zastąpiono starszy moduł.
Importowanie zestawu interfejsów API bezpośrednich
Rozwiązanie to sekwencja trzyetapowa:
- Plik binarny importuje nazwę kontraktu zestawu interfejsu API lub przekazuje go do biblioteki LoadLibrary.
- Moduł ładujący wyszukuje kontrakt w schemacie zestawu interfejsu API na bieżącym urządzeniu i znajduje plik binarny hosta mapowania go na.
- Moduł ładujący ładuje ten host binarny i wiąże zaimportowaną funkcję z eksportem hosta.
Ponieważ mapowanie znajduje się w schemacie, a nie w systemie plików, ten sam import może być rozpoznawany jako różne pliki binarne na różnych urządzeniach:
| Urządzenie |
api-win-core-samplefeature mapuje na |
|---|---|
| Urządzenie, które zawiera funkcję | samplefeature.dll |
| Urządzenie, które dostarcza refaktoryzowaną implementację | samplefeaturecore.dll |
| Urządzenie, które nie zawiera funkcji | Niezmapowane |
Nazwy samplefeature używane w tym miejscu to ilustracyjne nazwy fikcyjnego składnika Windows.
Zużywający plik binarny nie jest świadomy tego, z którym hostem był powiązany. Jest to punkt mechanizmu: kontrakt jest stabilny, podczas gdy moduł, który implementuje, można go zmienić z jednego urządzenia na następne.
Importowanie nazwy kontraktu jest rozpoznawane w ramach jednej operacji, bez modułu pośredniczącego usługi przesyłania dalej. Jest to najbardziej wydajna forma i normalna ścieżka kodu napisanego względem zestawów interfejsów API.
Nazwy zestawów interfejsów API i sufiks .dll
Ponieważ mapowania są przechowywane w schemacie, a nie na dysku, nazwa zestawu interfejsu API kończąca się .dll nie odnosi się do pliku tej nazwy. Część .dll jest tylko konwencją nazewnictwa przenoszoną ze sposobu, w jaki nazwy modułów są zapisywane w tabeli importu. Nazwa zestawu interfejsu API jest bardziej podobna do aliasu lub nazwy wirtualnej dla fizycznego pliku DLL.
Gdy operacja modułu ładującego odbiera nazwę rozpoczynającą się od api- lub ext-, moduł ładujący kieruje go do środowiska uruchomieniowego zestawu interfejsów API, rozszerzenie modułu ładującego, które rozpoznaje kontrakty za pośrednictwem schematu. Środowisko uruchomieniowe zestawu interfejsów API analizuje nazwę według reguł nazewnictwa zestawów interfejsów API, a nie jako nazwę pliku, więc sufiks.dll nie jest częścią nazwy kontraktu, która zostanie rozpoznana. Dołącz sufiks podczas pracy z nazwą wyświetlaną w tabeli importu; w przeciwnym razie można go opuścić.
Moduł ładujący rozpoznaje obie formy nazwy kontraktu, nazwę kontraktu w wersji i alias kontraktu za pomocą tego samego schematu. Aby zapoznać się z konwencjami rządzącymi tymi nazwami, zobacz Api set contract names (Nazwy kontraktów zestawów interfejsów API).
Stabilność nazw nie jest taka sama jak dostępność
Nazwa zestawu interfejsu API jest stabilna na urządzeniach Windows, w tym sensie, że ta sama nazwa zawsze identyfikuje ten sam kontrakt niezależnie od tego, gdzie jest rozpoznawany. Jest to właściwość przestrzeni nazw, a nie gwarancja dotycząca żadnego konkretnego urządzenia.
Dany kontrakt może być nieobecny na urządzeniu lub obecny, ale nie jest mapowany na hosta. Nic o nazwie nie informuje o tym. Aby dowiedzieć się, czy implementacja jest rzeczywiście dostępna, zobacz Detect API set availability (Wykrywanie dostępności zestawu interfejsu API).
Jakiego rozwiązania wymaga rozwiązanie
W przypadku wywołania za pośrednictwem interfejsu API ustawionego w celu osiągnięcia implementacji wszystkie następujące elementy muszą być przechowywane:
- Kontrakt znajduje się w schemacie na bieżącym urządzeniu.
- Schemat mapuje kontrakt na plik binarny hosta i można załadować go.
- Host eksportuje konkretną funkcję, która jest wywoływana przez plik binarny.
Jeśli jeden z tych elementów nie jest przechowywany, miejsce, w którym występuje awaria, zależy od sposobu zaimportowania zestawu interfejsu API:
| Styl importu | Zachowanie, gdy nie można rozpoznać kontraktu |
|---|---|
| Importowanie statyczne | Nie można uruchomić procesu. Moduł ładujący rozwiązuje operacje importowania statycznego przed uruchomieniem jakiegokolwiek kodu. |
| Importowanie ładowane z opóźnieniem | Proces rozpoczyna się normalnie. Rozwiązanie jest odroczone do pierwszego wywołania interfejsu API, w którym kod może obsłużyć błąd. |
Brakujący eksport jest zgłaszany oddzielnie od brakującego kontraktu; plik binarny, który importuje funkcję, która nie eksportuje hosta, kończy się niepowodzeniem z powodu brakującego błędu punktu wejścia.
Co kończy się powodzeniem ładowania, nie informuje o tym
Rozwiązanie wiąże kontrakt z hostem. Nie ocenia stanu poszczególnych możliwości w ramach tego kontraktu.
Kontrakt może organizować indywidualnie dostępne możliwości w nazwanych grupach. Grupa może być niedostępna na urządzeniu, mimo że kontrakt, który go prowadzi, jest rozpoznawany normalnie, ponieważ moduł ładujący wiąże się z stopniem szczegółowości kontraktu i nie konsultuje się ze stanem grupy w przypadku powiązania. To celowe: odmowa powiązania hosta jest śmiertelna dla importu statycznego, więc moduł ładujący pobiera ścieżkę permissywną i pozostawia bardziej szczegółowe pytanie do wywołującego.
Konsekwencją kodu jest to, że pomyślne załadowanie lub pomyślne wywołanie LoadLibrary nie jest dowodem na to, że dana funkcja jest dostępna. Zadaj to pytanie jawnie za pomocą zapytania dostępności. Zobacz Wykrywanie dostępności zestawu interfejsu API.
Opcjonalne zestawy interfejsów API i ładowanie opóźnione
Jeśli aplikacja wywołuje zestaw interfejsu API, który może nie być obecny, sprawdzanie dostępności samodzielnie nie wystarczy: przy statycznym importowaniu proces nie zostanie uruchomiony, więc wykonanie nigdy nie osiągnie sprawdzenia.
Aby zachować dostęp do opcjonalnej ścieżki kodu, skonfiguruj moduł, który obsługuje opcjonalny interfejs API na potrzeby ładowania opóźnień, lub rozwiąż element docelowy dynamicznie przy użyciu parametrów LoadLibrary i GetProcAddress po pomyślnym wykonaniu zapytania dotyczącego dostępności. Aby uzyskać szczegółowe informacje o obu podejściach, zobacz Detect API set availability (Wykrywanie dostępności zestawu interfejsu API).
Przekierowywanie odwrotne
Chociaż nazwy zestawów interfejsów API zapewniają stabilną przestrzeń nazw dla modułów na urządzeniach, nie zawsze jest praktyczne konwertowanie każdego pliku binarnego na ten system. Aplikacja mogła być często używana przez wiele lat i ponowne komkompilowanie jego plików binarnych może nie być możliwe. Niektóre aplikacje muszą również działać w systemach utworzonych przed wprowadzeniem określonych zestawów interfejsów API.
W tym celu wersje, które nie zawierają oryginalnych modułów, obejmują zestaw usług przesyłania dalej odwrotnego: pliki binarne zgodności, które zawierają nazwy modułów pierwotnie wprowadzone na komputerach Windows i które przekierowują eksporty do zestawów interfejsów API.
Pełna wersja klasyczna dostarcza oryginalne moduły, więc importowanie starszej nazwy modułu wiąże się z modułem, tak jak zawsze. W wersji, która zastąpiła ten moduł, odwrotny moduł przekazujący o tej samej nazwie obejmuje lukę.
Operacja modułu ładującego zachowuje się następująco:
- Moduł ładujący jest przedstawiany z zależnością od starszej Windows nazwy modułu pc, która nie jest obecna na urządzeniu.
- Moduł ładujący lokalizuje odwrotny moduł przesyłania dalej, który przenosi tę nazwę modułu i ładuje go.
- Usługa przesyłania dalej odwrotnego przekierowuje zaimportowaną funkcję do zestawu interfejsów API.
- Moduł ładujący rozpoznaje ten interfejs API ustawiony za pośrednictwem schematu, zgodnie z opisem we wcześniejszej części tego tematu.
Koncepcyjnie mapowanie wygląda następująco:
Zaimportowana biblioteka DLL: samplefeature.dll
- W wersji z oryginalnym modułem: samplefeature.dll
- W wydaniu, który go zastąpił: samplefeature.dll odwrotnego przesyłania dalej -samplefeaturecore.dll>>
api-win-core-samplefeature
Limit tej ścieżki to pokrycie eksportu. Usługa przesyłania dalej odwrotnego przenosi tylko eksporty z zestawem interfejsu API, więc niekoniecznie eksportuje każdą funkcję, którą wykonał oryginalny moduł. Plik binarny, który importuje funkcję, która nie przenosi usługi przesyłania dalej odwrotnego, nie może załadować z powodu brakującego błędu punktu wejścia.
Przekierowanie odwrotne jest również powodem, dla którego nie należy traktować pomyślnego rozwiązania jako dowodu obecności implementacji. Wywołanie GetProcAddress względem starszej nazwy modułu może zwrócić prawidłowy wskaźnik funkcji, który rozwiązuje problem z wycinkiem zwracającym błąd. Zamiast tego należy jawnie wykonywać zapytania dotyczące dostępności. Zobacz Wykrywanie dostępności zestawu interfejsu API.
Nuta
Przekazywanie wsteczne obejmuje tylko podzbiór powierzchni interfejsu API Win32. Nie zezwala na uruchamianie aplikacji przeznaczonych dla wersji klasycznych Windows na wszystkich urządzeniach Windows. Jeśli dane binarne są przeznaczone dla bieżących wersji Windows, bardziej bezpośredni wybór jest nazwą kontraktu zestawu interfejsu API.