Identifiera tillgänglighet för API-uppsättningar

I vissa fall kan ett angivet API-uppsättningskontraktsnamn avsiktligt mappas till ett tomt modulnamn på vissa Windows enheter. Orsakerna till detta varierar, men ett vanligt exempel är att en dyr funktion när det gäller systemresurser kan tas bort från Windows operativsystem när den konfigureras för en resursbegränsad enhet. Detta innebär en utmaning för program att hantera valfria funktioner på API-nivå på ett smidigt sätt.

Den traditionella metoden för att testa om ett Win32-API är tillgängligt är att använda LoadLibrary eller GetProcAddress. Dessa är dock inte ett tillförlitligt sätt att testa API-uppsättningar på grund av omvänd vidarebefordran. Om omvänd vidarebefordran tillämpas på ett visst API kan LoadLibrary eller GetProcAddress matchas mot en giltig funktionspekare även om den interna implementeringen har tagits bort. I det här fallet pekar funktionspekaren på en stub-funktion som helt enkelt returnerar ett fel.

För att identifiera det här fallet kan du använda funktionen IsApiSetImplemented för att fråga den underliggande tillgängligheten för en viss API-implementering. Det här testet rapporterar om API-uppsättningen finns i det sammansatta API-uppsättningsschemat på den enhet som körs och om den mappas till en implementeringsmodul.

Important

En lyckad tillgänglighetsfråga är inte en garanti för att ett visst anrop lyckas. Fortsätt att hantera modulinläsningsfel, saknade exporter och API:ets egna dokumenterade felresultat.

I följande kodexempel visas hur du använder IsApiSetImplemented för att avgöra om DEN API-uppsättning som innehåller WTSEnumerateSessionsW är tillgänglig på den aktuella enheten innan den anropas.

#include <windows.h>
#include <apiquery2.h>
#include <stdio.h>
#include <wtsapi32.h>

#pragma comment(lib, "OneCore.lib")
#pragma comment(lib, "Wtsapi32.lib")

int __cdecl wmain(int /* argc */, PCWSTR /* argv */ [])
{
    PWTS_SESSION_INFOW pInfo = nullptr;
    DWORD count = 0;

    if (!IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0"))
    {
        wprintf(L"ext-ms-win-session-wtsapi32-l1-1-0 is not available.\n");
        return 0;
    }

    if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count))
    {
        wprintf(L"SessionCount = %lu\n", count);

        for (DWORD i = 0; i < count; i++)
        {
            PWTS_SESSION_INFOW pCurInfo = &pInfo[i];
            wprintf(L"    %ls: ID = %lu, state = %d\n", pCurInfo->pWinStationName,
                pCurInfo->SessionId, static_cast<int>(pCurInfo->State));
        }

        WTSFreeMemory(pInfo);
    }
    else
    {
        wprintf(L"WTSEnumerateSessionsW failure: %lu\n", GetLastError());
    }

    return 0;
}

IsApiSetImplemented deklareras i apiquery2.h, och den normala offentliga SDK-länksökvägen tillhandahåller den från OneCore.lib. Biblioteket är separat från alla importbibliotek som behövs för att anropa själva det valfria mål-API:et.

Exemplet ovan länkar Wtsapi32.lib för en statisk import, vilket håller exemplet kort. Ett produktionsprogram som måste köras där API-uppsättningen saknas bör också använda vägledningen i Behåll den valfria kodsökvägen nåbar.

Välj frågenamnet

Skicka namnet på den API-uppsättning som du testar. API-uppsättningsnamn skrivs konventionellt utan suffix .dll , och exemplen på den här sidan använder formuläret. Suffixet är inte en del av API-uppsättningens namn.

Information om hur du hittar namnet som ska skickas finns i tabellen Krav på referenssidan för det API som du vill anropa. Om tabellen har en API-uppsättningsrad ger den kontraktnamnet. Annars använder du DLL-raden , men bara när namnet där är ett kontraktnamn som börjar med api- eller ext-; ett fysiskt modulnamn som Wtsapi32.dll inte är ett kontrakt och frågan returnerar FALSE.

Namnets form beror på hur API:et hanteras.

API-gränssnitt Frågeformulär Example
Namngiven grupp <contract>~<group> api-win-core-samplefeature~AdvancedOperations
Standardgrupp Kontraktalias, utan ~Default api-win-core-samplefeature
Versionskontrakt Fullständigt versionshanterat kontraktnamn ext-ms-win-core-samplefeature-l1-1-0

Namnen samplefeature är illustrativa namn för en fiktiv Windows komponent. Namnprefixet (api- eller ext-) spelar ingen roll i tillgänglighetsbeteendet.

För en namngiven grupp innebär en lyckad fråga att gruppen finns, att dess kontrakt mappas till en implementeringsmodul, att värden kan användas i den aktuella körningsmiljön, att gruppen inte är inaktiverad och att alla systemfunktioner som är associerade med gruppen är aktiverade. En fråga som använder ett kontraktalias tillämpar kontrakt- och värdkontrollerna.

Om API:ets offentliga huvud tillhandahåller en Is<APIName>Present hjälp, föredrar du den här hjälpen. Den innehåller redan rätt namn för API-uppsättningen eller gruppen som bär API:et.

Resultatet av en fråga är contract- eller group-granular, inte function-granular. Två hjälpare som backas upp av samma namngivna grupp returnerar alltid samma resultat, även om varje hjälphjälpare namnges för ett annat API.

Håll den valfria kodsökvägen nåbar

En tillgänglighetskontroll kan inte skydda processens start om det valfria API:et är länkat som en statisk import. Inläsaren löser statiska importer innan koden körs, så en modul som saknas misslyckas innan körningen når kontrollen.

Använd någon av följande metoder:

  • Konfigurera modulen som har det valfria API:et för fördröjningsinläsning. Fördröjningsinläsning är en länkinställning: ange /DELAYLOAD:<module> och länka delayimp.lib. Ange modulnamnet som visas i binärfilens importtabell, vilket kan vara det klassiska DLL-namnet i stället för api-uppsättningens kontraktnamn. I föregående exempel är namnet WTSAPI32.dll.
  • Eller lös målet dynamiskt med LoadLibrary och GetProcAddress när tillgänglighetsfrågan har slutförts.

Använd inte LoadLibrary eller GetProcAddress som ersättning för tillgänglighetsfrågan. De svarar på modul- och exportfrågor, de utvärderar inte namngivet grupptillstånd och kan matcha till en omvänd vidarebefordran enligt beskrivningen tidigare. Använd dem efter frågan för att hantera den separata modulen och exportera kontroller.

Beteende på tidigare versioner av Windows

Implementeringen som tillhandahålls av OneCore.lib väljer en tillgänglig frågemekanism vid körning, så ett program som anropar IsApiSetImplemented kan fortfarande köras på ett system som föregår det underliggande frågestödet.

I ett system där ingen frågemekanism är tillgänglig:

  • Ett gruppkvalificerat namn som innehåller returnerar ~FALSE. Ett system som inte kan utvärdera namngivna grupper kan inte rapportera att en grupp är tillgänglig.
  • Ett namn som inte är gruppkvalificerat kan returnera TRUE. Detta bevarar kompatibiliteten med program som tillhandahöll sina egna DLL:er för vidarebefordrare på tidiga versioner av Windows, där kontraktet faktiskt uppfylldes av vidarebefordraren.

Använd inte en API-uppsättningstillgänglighetsfråga som en säkerhets- eller auktoriseringskontroll.

Se även