假设我正在编写一个多用途dll,其中包含获取操作系统版本的功能:
void get_os_version(DWORD *major, DWORD *minor)
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOsVersionInfoSize = sizeof(OSVERSIONINFOEX);
// deprecated but easier to use for this example's sake
GetVersionEx((OSVERSIONINFO*)&osvi);
*major = osvi.dwMajorVersion;
*minor = osvi.dwMinorVersion;
}
要为高于Windows 8的版本正确检索Windows版本,需要嵌入指定支持平台的清单(请参阅详细信息here)。
所以我在编译时禁用使用/MANIFEST:NO
标志自动生成我的dll文件的清单,而是添加以下清单:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>
,使用mt工具:
mt -manifest GetOsVersion.dll.manifest -outputresource:GetOsVersion.dll;#2
一切都好,没有错误。现在使用dll,我创建一个简单的App.exe,它加载dll并调用它的函数:
int _tmain(int argc, _TCHAR* argv[])
{
DWORD major, minor;
get_os_version(&major, &minor);
printf("%d.%d\n", major, minor);
return 0;
}
但是当在Windows 10上运行App.exe时,出乎意料的是,输出是:
6.2
,这是Windows 8的版本。如果我也将清单应用于App.exe:
mt -manifest GetOsVersion.dll.manifest -outputresource:App.exe;#1
,输出是预期的输出:
10.0
为什么会这样?如果不向可执行文件添加清单,我可以解决这个问题吗?
我无法控制将使用我的库的应用程序,但我仍然想要正确检索操作系统版本。
答案 0 :(得分:2)
确定实际操作系统版本的另一种方法记录在MSDN页面"Getting the System Version"上:
要获取操作系统的完整版本号,请在其中一个系统DLL上调用GetFileVersionInfo函数,例如Kernel32.dll,然后调用VerQueryValue以获取文件版本信息的
\\StringFileInfo\\<lang><codepage>\\ProductVersion
子块。 / p>
无论应用程序是否有清单,这都可以在DLL中使用。
(当然,有一个原因是GetVersionInfo和朋友不会返回实际的操作系统版本:程序员有一种滥用这些信息的恶劣倾向。你应该认真考虑是否在你的系统中提供这样的功能DLL真的是个好主意。)
答案 1 :(得分:2)
补充accepted answer,以下是其他任何想要实现它的人的初码:
#pragma comment(lib, "version")
static void print_version()
{
DWORD buffer_size = GetFileVersionInfoSize(_T("kernel32.dll"), NULL);
if (buffer_size == 0)
{
// get error from GetLastError()
return;
}
VOID *buffer = malloc(buffer_size);
if (buffer == NULL)
{
// out of memory
return;
}
if (!GetFileVersionInfo(_T("kernel32.dll"), 0, buffer_size, buffer))
{
goto error;
}
VS_FIXEDFILEINFO *version = NULL;
UINT version_len = 0;
if (!VerQueryValue(buffer,
_T("\\"),
(LPVOID*)&version,
&version_len))
{
goto error;
}
_tprintf(_T("Version is: %u.%u\n"),
HIWORD(version->dwProductVersionMS),
LOWORD(version->dwProductVersionMS));
error:
free(buffer);
}
Windows 10上的输出是:
Version is 10.0
答案 2 :(得分:1)
App (executable) manifest MSDN page相当明确地描述了这个问题:
Windows中引入的应用程序(可执行文件)清单的兼容性部分可帮助操作系统确定应用程序旨在定位的Windows版本。
如果清单不是可执行清单,则完全忽略兼容性(以及其他应用程序设置,例如DPI感知)。这是有道理的,否则在不同的dll中的清单之间可能会出现明显的冲突。
答案 3 :(得分:0)
清单中的大多数节点都适用于整个进程,只能从主.exe模块中读取:
Windows中引入的compatibility section of the app (executable) manifest可帮助操作系统确定应用程序旨在定位的Windows版本。
您应该使用GetProcAddress
和CoCreateInstance
来检查您所需的功能是否存在,而不是Windows版本。
如果您真的需要这些信息,只需要做一些工作,GetProcAddress
也可用于确定您所使用的版本。查看MSDN上各种kernel32和user32函数的最低操作系统版本......