Мелкомягкие в последних версиях винды для чего-то испоганили функцию GetVersionEx() из kernel32.dll. Программа с пустым манифестом будет через GetVersionEx() неизменно получать версию NT 6.2 (Windows 8) под Windows 8, 8.1, 10 и так далее. Что будет получать DLLка — зависит от того, какой процесс её загрузил.
Сомнительная фича с точки зрения например, crash reporter'а, который собирает сведения о системе в файл дампа, который юзер будет отправлять техподдержке по e-mail'у.
Возможный обходной путь, использующие документированные API: GetModuleHandle("kernel32") → FindResource(hMod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION)) → LoadResource() → VerQueryValue(pBlock, "\", ...) → struct VS_FIXEDFILEINFO. Кстати, функцию LockResource() вызывать не нужно. Последний раз она не была пустой заглушкой ещё в Windows 3.11. Ну а LoadResource() с тех же пор ничего никуда не загружает, а просто совершает прогулку по PE-заголовкам, уже загруженным ранее в виртуальную память процесса. Вообще, вся эта цепочка вызовов ни разу не переходит в режим ядра, а только "бродит" по структурам, ранее загруженным в ОЗУ, начиная с Thread Information Block.
Кратчайший обходной путь, использующие недокументированные API: напрямую из KUSER_SHARED_DATA.
Сомнительная фича с точки зрения например, crash reporter'а, который собирает сведения о системе в файл дампа, который юзер будет отправлять техподдержке по e-mail'у.
Возможный обходной путь, использующие документированные API: GetModuleHandle("kernel32") → FindResource(hMod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION)) → LoadResource() → VerQueryValue(pBlock, "\", ...) → struct VS_FIXEDFILEINFO. Кстати, функцию LockResource() вызывать не нужно. Последний раз она не была пустой заглушкой ещё в Windows 3.11. Ну а LoadResource() с тех же пор ничего никуда не загружает, а просто совершает прогулку по PE-заголовкам, уже загруженным ранее в виртуальную память процесса. Вообще, вся эта цепочка вызовов ни разу не переходит в режим ядра, а только "бродит" по структурам, ранее загруженным в ОЗУ, начиная с Thread Information Block.
Кратчайший обходной путь, использующие недокументированные API: напрямую из KUSER_SHARED_DATA.