检测 API 集可用性

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

测试 Win32 API 是否可用的传统方法是使用 LoadLibraryGetProcAddress。 但是,由于 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;
}