针对 OneCore 生成
使用 Visual Studio 生成适用于 Windows 10 的用户模式代码时,可以自定义针对特定版本的 Windows 的链接器选项。 请考虑下列因素:
生成的二进制文件是否只应在最新版本的 Windows 上运行? 还是应该在 Windows 7 等早期版本上运行?
项目是否有任何 UWP 依赖项?
例如,默认情况下,创建新的 UMDF v2 驱动程序项目时,Visual Studio 会链接到 OneCoreUAP.lib
。 这会生成一个在最新版本的 Windows 上运行的二进制文件,且允许添加 UWP 功能。
但是,根据要求的不同,可以选择改为链接到 OneCore.lib
。 下表显示了适用于每个库的方案:
库 | 场景 |
---|---|
OneCore.lib |
Windows 7 及更高版本的所有版本,不支持 UWP |
OneCoreUAP.lib |
Windows 7 及更高版本、Windows 10 的 UWP 版本(Desktop、IoT、HoloLens,但不包括 Nano Server) |
注意
要更改 Visual Studio 中的链接器选项,请选择项目属性,然后导航至“链接器”->“输入”->“其他依赖项”。
Windows API 的一个子集可以干净地编译,但在非 Desktop 的 OneCore 版本(例如 Mobile 或 IoT)上返回运行时错误。
例如,InstallApplication 函数在非 Desktop 的 OneCore 版本中会返回 ERROR_ NOT_SUPPORTED
。 ApiValidator 工具也会报告这些问题。 下一部分将介绍如何解决这些问题。
使用 IsApiSetImplemented 修复 ApiValidator 错误
如果代码调用非通用 API,可能会显示以下 ApiValidator 错误:
Error: <Binary Name> has unsupported API call to <Module Name><Api Name>
如果应用或基准驱动程序需要在 Windows 10 以及早期版本的 Windows 上运行,则必须删除上述类别中的 API 调用。
Error: <Binary Name> has a dependency on <Module Name><Api Name> but is missing: IsApiSetImplemented("<contract-name-for-Module>)
上述类别中的 API 调用编译良好,但在运行时可能表现不符合预期,具体取决于目标操作系统。 要传递 Windows 驱动程序的 API 分层要求,请使用 IsApiSetImplemented 包装这些调用。
这使你能够编译代码而不出错。 然后在运行时,如果目标计算机没有所需的 API,则 IsApiSetImplemented 将返回 FALSE。
以下代码示例说明了如何执行此操作。
代码示例:直接使用 API,而不评估其是否存在
此代码在 Windows 10 以前的版本上运行正常,但在 Windows 10 的 OneCore 版本上运行时,会出现 WTSEnumerateSessions 失败:78 或 ERROR_CALL_NOT_IMPLEMENTED 120 (0x78)。
此代码示例不符合 Windows 驱动程序的 API 分层要求,出现了以下 ApiValidator 错误:
ApiValidation: Error: FlexLinkTest.exe has a dependency on 'wtsapi32.dll!WTSEnumerateSessionsW' but is missing: IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0")
ApiValidation: Error: FlexLinkTest.exe has a dependency on 'wtsapi32.dll!WTSFreeMemory' but is missing: IsApiSetImplemented("ext-ms-win-session-wtsapi32-l1-1-0")
ApiValidation: NOT all binaries are Universal
代码如下:
#include <windows.h>
#include <stdio.h>
#include <Wtsapi32.h>
int __cdecl wmain(int /* argc */, PCWSTR /* argv */ [])
{
PWTS_SESSION_INFO pInfo = {};
DWORD count = 0;
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;
}
代码示例:在评估其是否存在后直接使用 API
此示例演示如何调用 IsApiSetImplemented。 此示例符合 Windows 驱动程序的 API 分层要求,生成了以下 ApiValidator 输出:
ApiValidation: All binaries are Universal
代码如下:
#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;
}
建议的操作
- 查看上面的链接器选项并相应地更新 Visual Studio 项目。
- 使用 WDK 中的 ApiValidator 工具。 在 Visual Studio 中生成驱动程序时该工具会自动运行。
- 使用运行时测试验证用户模式代码是否按照预期在非 Desktop 的 OneCore 版本上运行。 请注意,存根 API 可能会生成不同的错误代码。