检测 API 集可用性

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

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

为了检测这种情况,可以使用 IsApiSetImplemented 函数查询给定 API 实现的基础可用性。 此测试验证调用此函数是否将导致执行 API 的函数实现。

以下代码示例显示如何在调用 WTSEnumerateSessions 函数之前,使用 IsApiSetImplemented 来确定该函数在当前设备上是否可用。

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