Claudiu Claudiu - 4 days ago 4
C Question

Get the Windows version correctly from a dll function call?

Suppose I'm writing a multi-purpose dll which includes a function for getting the OS version:

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


For the Windows version to be retrieved correctly for versions higher than Windows 8, it is required to embed a manifest that specifies the supported platforms (see details here).

So I disable automatic generation of a manifest for my dll file using the
/MANIFEST:NO
flag when compiling, and instead add the following manifest:

<?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>


, using the mt tool:

mt -manifest GetOsVersion.dll.manifest -outputresource:GetOsVersion.dll;#2


All good and no errors. Now to use the dll, I create a simple App.exe which loads the dll and calls its function:

int _tmain(int argc, _TCHAR* argv[])
{
DWORD major, minor;
get_os_version(&major, &minor);
printf("%d.%d\n", major, minor);
return 0;
}


But when running App.exe on Windows 10, surprise surprise, the output is:

6.2


, which is the version for Windows 8. If I apply the manifest to the App.exe too:

mt -manifest GetOsVersion.dll.manifest -outputresource:App.exe;#1


, the output is the expected one:

10.0


Why is this happening? And can I solve this problem without adding a manifest to the executable?

I don't have control over the applications that will use my library, but I still want to correctly retrieve the OS version.

Answer

Most of the nodes in a manifest applies to the whole process and is only read from the main .exe module:

The compatibility section of the app (executable) manifest introduced in Windows helps the operating system determine the versions of Windows an app was designed to target.

You should use GetProcAddress and CoCreateInstance to check if the feature you need is present, not the Windows version.

With a little work, GetProcAddress can also be used to figure out what version you are on if you really need that information. Look at the minimum OS version of various kernel32 and user32 functions on MSDN...