Поделиться через


Определение доступности набора API

В некоторых случаях заданное имя контракта набора API может быть намеренно сопоставлено с пустым именем модуля на некоторых устройствах Windows. Причины этого зависят, но распространенный пример заключается в том, что ресурсоемкая функция с точки зрения системных ресурсов может быть удалена из ОС Windows при настройке для устройства с ограниченными ресурсами. Это создает проблему для приложений для корректной обработки необязательных функций на уровне API.

Традиционный подход для тестирования доступности API Win32 — использовать LoadLibrary или GetProcAddress. Однако это не надежные средства для тестирования наборов API из-за поддержки обратной пересылки в Windows 10 и более поздних версий. Если обратная пересылка применяется к заданному API, LoadLibrary или GetProcAddress может разрешаться в допустимый указатель функции даже в тех случаях, когда внутренняя реализация была удалена. В этом случае указатель функции будет указывать на заглушку, которая просто возвращает ошибку.

Чтобы обнаружить этот случай, можно использовать функцию IsApiSetImplemented для запроса базовой доступности данной реализации API. Этот тест проверяет, что вызов этой функции приведет к выполнению функциональной реализации API.

В следующем примере кода показано, как использовать IsApiSetImplemented , чтобы определить, доступна ли функция WTSEnumerateSessions на текущем устройстве перед вызовом.

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