web-dev-qa-db-fra.com

avertissement C4996: «GetVersionExW»: a été déclaré obsolète

Je travaille sur VS 2013 dans Win 8.1. Comment résoudre cet avertissement?

31
yemans

La question de base est "pourquoi appelez-vous GetVersionExW en premier lieu?" La réponse à cette question détermine ce que vous devez faire à la place.

L'avertissement de dépréciation est là pour informer les développeurs du changement de comportement compatible avec l'application qui a commencé dans Windows 8.1. Voir Livre de recettes de compatibilité Windows et Windows Server: Windows 8, Windows 8.1 et Windows Server 2012 . En bref, cette fonction ne retourne pas ce que vous pensez qu'elle retourne par défaut.

Historiquement, les vérifications de version de système d'exploitation mal écrites sont la principale source de bogues compatibles avec les applications pour les mises à niveau du système d'exploitation Windows. Il y a eu un certain nombre d'approches différentes pour essayer d'atténuer ce problème (la version d'AppVerifier lie, l'API VerifyVersionInfo, etc.), et c'est la plus agressive à ce jour.

Le VersionHelpers.h mentionnés dans les commentaires se trouvent dans le SDK Windows 8.1 fourni avec Visual Studio 2013. Il ne s'agit pas d'une nouvelle API; ce sont juste des codes utilitaires qui utilisent l'API VerifyVersionInfo introduite dans Windows 2000. Ces fonctions sont destinées à effectuer des vérifications de style "Vous devez être aussi haut pour monter cette course" qui sont la classe des vérifications de version qui sont le plus souvent mal écrit. Le code est assez simple. Par exemple, le IsWindowsVistaSP2OrGreater le test est:

VERSIONHELPERAPI
IsWindowsVersionOrGreater(Word wMajorVersion, Word wMinorVersion, Word wServicePackMajor)
{
    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
    DWORDLONG        const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
            0, VER_MAJORVERSION, VER_GREATER_EQUAL),
               VER_MINORVERSION, VER_GREATER_EQUAL),
               VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    osvi.dwMajorVersion = wMajorVersion;
    osvi.dwMinorVersion = wMinorVersion;
    osvi.wServicePackMajor = wServicePackMajor;

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}

VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater()
{
    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_Vista), LOBYTE(_WIN32_WINNT_Vista), 2);
}

Vous n'avez pas besoin d'utiliser VersionHelpers.h comme vous pouvez le faire vous-même, mais ils sont pratiques si vous utilisez déjà le compilateur VS 2013. Pour les jeux, j'ai un article Qu'y a-t-il dans un numéro de version? qui utilise VerifyVersionInfo pour faire le genre de vérifications raisonnables que l'on devrait pour le déploiement du jeu.

Notez que si vous utilisez VS 2013 avec le v120_xp jeu d'outils de plateforme pour cibler Windows XP, vous utiliserez en fait le SDK Windows 7.1A et #include <VersionHelpers.h> ne fonctionnera pas. Vous pouvez bien sûr utiliser VerifyVersionInfo directement.

L'autre utilisation majeure de GetVersionExW est les journaux de diagnostic et la télémétrie. Dans ce cas, une option consiste à continuer à utiliser cette API et à vous assurer que vous disposez des entrées de manifeste appropriées dans votre application pour garantir des résultats raisonnablement précis. Voir Manifest Madness pour plus de détails sur ce que vous faites ici pour y parvenir. La principale chose à garder à l'esprit est qu'à moins que vous ne mettiez régulièrement à jour votre code, vous cesserez éventuellement d'obtenir des informations entièrement précises dans une future version du système d'exploitation.

Notez qu'il est recommandé de mettre le <compatibility> section dans un manifeste intégré, que vous vous souciez ou non des résultats de GetVersionEx en tant que meilleure pratique générale. Cela permet au système d'exploitation d'appliquer automatiquement les futurs correctifs compatibles avec l'application en fonction de la façon dont l'application a été testée à l'origine.

Pour les journaux de diagnostic, une autre approche qui pourrait être un peu plus robuste consiste à extraire le numéro de version d'un système DLL comme kernel32.dll en utilisant GetFileVersionInfoW. Cette approche a un caveau majeur: N'essayez pas d'analyser, de faire des comparaisons ou de faire des hypothèses de code basées sur la version de fichier que vous obtenez de cette façon; écrivez-le quelque part. Sinon, vous risquez de recréer le même problème de vérification de la mauvaise version du système d'exploitation qui est mieux résolu avec VerifyVersionInfo. Cette option n'est pas disponible pour les applications Windows Store, les applications Windows Phone, etc. mais devrait fonctionner pour les applications de bureau Win32.

#include <windows.h>
#include <stdint.h>
#include <memory>

#pragma comment(lib, "version.lib" )

bool GetOSVersionString( WCHAR* version, size_t maxlen )
{
    WCHAR path[ _MAX_PATH ];
    if ( !GetSystemDirectoryW( path, _MAX_PATH ) )
        return false;

    wcscat_s( path, L"\\kernel32.dll" );

    //
    // Based on example code from this article
    // http://support.Microsoft.com/kb/167597
    //

    DWORD handle;
#if (_WIN32_WINNT >= _WIN32_WINNT_Vista)
    DWORD len = GetFileVersionInfoSizeExW( FILE_VER_GET_NEUTRAL, path, &handle );
#else
    DWORD len = GetFileVersionInfoSizeW( path, &handle );
#endif
    if ( !len )
        return false;

    std::unique_ptr<uint8_t> buff( new (std::nothrow) uint8_t[ len ] );
    if ( !buff )
        return false;

#if (_WIN32_WINNT >= _WIN32_WINNT_Vista)
    if ( !GetFileVersionInfoExW( FILE_VER_GET_NEUTRAL, path, 0, len, buff.get() ) )
#else
    if ( !GetFileVersionInfoW( path, 0, len, buff.get() ) )
#endif
        return false;

    VS_FIXEDFILEINFO *vInfo = nullptr;
    UINT infoSize;

    if ( !VerQueryValueW( buff.get(), L"\\", reinterpret_cast<LPVOID*>( &vInfo ), &infoSize ) )
        return false;

    if ( !infoSize )
        return false;

    swprintf_s( version, maxlen, L"%u.%u.%u.%u",
                HIWORD( vInfo->dwFileVersionMS ),
                LOWORD(vInfo->dwFileVersionMS),
                HIWORD(vInfo->dwFileVersionLS),
                LOWORD(vInfo->dwFileVersionLS) );

    return true;
}

S'il y a une autre raison pour laquelle vous appelez GetVersionExW, vous ne devriez probablement pas l'appeler. La vérification d'un composant qui pourrait être manquant ne doit pas être liée à une vérification de version. Par exemple, si votre application nécessite Media Foundation, vous devez définir un "Vous devez être aussi haut pour effectuer ce contrôle de parcours" comme VersionHelpers.h IsWindowsVistaOrGreater pour le déploiement, mais lors de l'exécution, vous devez utiliser une liaison explicite via LoadLibrary ou LoadLibaryEx pour signaler une erreur ou utiliser une solution de secours si MFPLAT.DLL n'est pas trouvé.

La liaison explicite n'est pas une option pour les applications du Windows Store. Windows 8.x résout ce problème particulier en ayant un stub MFPLAT.DLL et MFStartUp renverra E_NOTIMPL. Voir "Qui a déplacé mon fromage [Windows Media]"?

Un autre exemple: si votre application souhaite utiliser Direct3D 11.2 s'il est disponible et utilise DirectX 11.0 autrement, vous utiliserez set a IsWindowsVistaSP2OrGreater barre minimale pour le déploiement en utilisant peut-être D3D11InstallHelper . Ensuite, lors de l'exécution, vous créez le périphérique DirectX 11.0 et s'il échoue, vous signalez une erreur. Si vous obtenez un ID3D11Device, alors vous auriez QueryInterface pour un ID3D11Device2 qui, s'il réussit, signifie que vous utilisez un système d'exploitation prenant en charge DirectX 11.2. Voir Anatomie de Direct3D 11 Create Device .

Si cette hypothétique application Direct3D prend en charge Windows XP, vous utiliseriez une barre de déploiement de IsWindowsXPSP2OrGreater ou IsWindowsXPSP3OrGreater, puis au moment de l'exécution, utilisez une liaison explicite pour essayer de trouver le D3D11.DLL. S'il n'était pas présent, vous reviendriez à l'utilisation de Direct3D 9 - puisque nous avons défini la barre minimale, nous savons que DirectX 9.0c ou version ultérieure est toujours présent.

Leur point clé ici est que dans la plupart des cas, vous ne devez pas utiliser GetVersionEx.

Notez qu'avec Windows 10 , VerifyVersionInfo et l'obtention du tampon de version de fichier via GetFileVersionInfo pour kernel32.lib sont désormais soumis au même comportement basé sur le manifeste que GetVersionEx (c'est-à-dire sans le manifeste GUID pour Windows 10, il renvoie des résultats comme si la version du système d'exploitation était 6.2 plutôt que 10.0).

Pour les applications Windows universelles sur Windows 10, vous pouvez une nouvelle API WinRT AnalyticsInfo pour obtenir une chaîne de tampon de version pour les journaux de diagnostic et la télémétrie.

51
Chuck Walbourn

Bien que GetVersionEx ait été déclaré obsolète, si vous lancez un manifeste de compatibilité approprié déclarant la compatibilité avec Windows 8.1 et Windows 10, GetVersionEx renverra le numéro de version correct. J'utilise GetVersionEx pour détecter Windows 8 ou supérieur, et parce que Windows 8 est la dernière version de Windows à ne pas nécessiter de manifeste pour renvoyer la bonne version de Windows, mon code fonctionne correctement, que l'API renvoie Windows 6.2, 6.3, 6.4 (pour versions antérieures de Windows 10) ou 10.0.

Cela dit, Microsoft a déconseillé cette API en partie à cause d'une mauvaise utilisation de celle-ci. Prenez par exemple cette tentative de détection de Windows XP ou supérieur:

BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;

Cet exemple retournerait TRUE sur Windows XP, Server 2003, 7, 8 et 8.1 mais retournerait FALSE sur Windows Vista ou 10. L'ajout d'une ligne résoudrait ceci:

BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else if(osver.dwMajorVersion >= 6) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;

Cet exemple fonctionnerait correctement car il sait que si la version principale est supérieure ou égale à 6, elle est supérieure à XP.

3
William

vous pouvez désactiver cet avertissement et utiliser GetVersionEx de toute façon en ajoutant:

#pragma warning(disable : 4996)
3
user1438233