API-Satz-Verfügbarkeit erkennen

In einigen Fällen kann der Vertragsname eines bestimmten API-Satzes absichtlich einem leeren Modulnamen auf einigen Windows-Geräten zugeordnet werden. Die Gründe dafür variieren, aber ein häufiges Beispiel ist, dass ein teures Feature in Bezug auf Systemressourcen aus dem Windows-Betriebssystem entfernt werden kann, wenn es für ein gerät mit eingeschränkter Ressource konfiguriert wird. Dies stellt eine Herausforderung für Anwendungen dar, optionale Features auf API-Ebene ordnungsgemäß zu behandeln.

Der herkömmliche Ansatz zum Testen, ob eine Win32-API verfügbar ist, ist die Verwendung von LoadLibrary oder GetProcAddress. Dies ist jedoch aufgrund der Reverse-Weiterleitungsunterstützung in Windows 10 und höher kein zuverlässiges Mittel zum Testen von API-Sätzen. Wenn die reverse Weiterleitung auf eine bestimmte API angewendet wird, kann LoadLibrary oder GetProcAddress in einen gültigen Funktionszeiger aufgelöst werden, auch wenn die interne Implementierung entfernt wurde. In diesem Fall zeigt der Funktionszeiger auf eine Stubfunktion, die einfach einen Fehler zurückgibt.

Um diesen Fall zu erkennen, können Sie die IsApiSetImplemented-Funktion verwenden, um die zugrunde liegende Verfügbarkeit einer bestimmten API-Implementierung abzufragen. Dieser Test überprüft, ob der Aufruf dieser Funktion zur Ausführung einer funktionalen Implementierung der API führt.

Im folgenden Codebeispiel wird veranschaulicht, wie Mithilfe von IsApiSetImplemented ermittelt wird, ob die FUNKTION WTSEnumerateSessions auf dem aktuellen Gerät verfügbar ist, bevor sie aufgerufen wird.

#include <windows.h>
#include <stdio.h>
#include <Wtsapi32.h>

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

    if (!IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0"))
    {
        wprintf(L"IsApiSetImplemented on ext-ms-win-session-wtsapi32-l1-1-0 returns FALSE\n");
    }
    else
    {
        if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count))
        {
            wprintf(L"SessionCount = %d\n", count);

            for (ULONG i = 0; i < count; i++)
            {
                PWTS_SESSION_INFO pCurInfo = &pInfo[i];
                wprintf(L"    %s: ID = %d, state = %d\n", pCurInfo->pWinStationName, 
                    pCurInfo->SessionId, pCurInfo->State);
            }

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

    return 0;
}