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


Обнаружение доступности набора 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;
}