检测 API 集可用性

在某些情况下,给定的 API 集协定名称可能会有意映射到某些 Windows 设备上的空模块名称。 原因各不相同,但一个常见示例是,在为资源受限的设备配置时,系统资源方面的成本高昂功能可能会从 Windows OS 中删除。 这为应用程序在 API 级别正常处理可选功能带来了挑战。

用于测试 Win32 API 是否可用的传统方法是使用 LoadLibrary 还是 GetProcAddress。 但是,由于 Windows 10 及更高版本中 反向转发 支持,因此测试 API 集并不是可靠的方法。 向给定 API 应用反向转发时,LoadLibraryGetProcAddress 可以解析为有效的函数指针,即使在删除内部实现的情况下也是如此。 在这种情况下,函数指针将指向仅返回错误的存根函数。

为了检测这种情况,可以使用 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;
}