从Win8.1开始使用GetVersionEX获取版本号出现问题了,微软又开始挖坑,这里笔者实现了一个类,直接使用就完事大吉了,先讲原理后放代码就是这么溜~

说明

在Win8以前获取Windows版本号,一般都使用GetVersionEx,如winXP(5.1),Win7(6.1),Win8(6.2)。但是到了Win8.1开始就不行了,这时候使用GetVersionEx会发现Win8.1和Win10开始都是6.2,这怎么能行。

为了解决这个问题,首先我们需要知道版本信息是GetVersionEx从进程PEB中拿取的,用工具查看会发现PEB中的信息是正确的,但是GetVersionEx却不正确,这是微软取数据机制发生了变化。在这种情况下,我们可以换用RtlGetVersion,这是一个内核函数,会发现他的结果还是对的。另外如果从ntdll.dll中导出RtlGetVersion失败的话,我们还可以通过判断系统文件如kernel32.dll的版本来判断当前操作系统版本。

总结来说,获取Windows版本号方法如下:
1.Windows2000~Win 7 GetVersionEx
2.Win8*~ RtlGetVersion
3.GetFileVersionInfo获取kerne32.dll的版本进而判断系统版本

核心代码

//计算系统版本信息
WIN_VER CalcWinVerInfo()
{
    //获得系统主次版本号
    ULONG dwMajorVersion=0;
    ULONG dwMinorVersion=0;

    //Win8以前可使用GetVersionEx,适用于Windows 2000~Windows 7
    OSVERSIONINFO osvi={0};
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    GetVersionEx (&osvi);
    dwMajorVersion = osvi.dwMajorVersion;
    dwMinorVersion = osvi.dwMinorVersion;

    AtlTrace(L"GetVersionEx-%d-%d", dwMajorVersion, dwMinorVersion);

    //判断系统版本
    if (dwMajorVersion==5 && dwMinorVersion==0)
    {
        m_WinVer = WIN_VER_2000;
    }
    else if (dwMajorVersion==5 && dwMinorVersion==1)
    {
        m_WinVer = WIN_VER_XP;
    }
    else if (dwMajorVersion==5 && dwMinorVersion==2)
    {
        m_WinVer = WIN_VER_2003;
    }
    else if (dwMajorVersion==6 && dwMinorVersion==0)
    {
        m_WinVer = WIN_VER_VISTA;
    }
    else if (dwMajorVersion==6 && dwMinorVersion==1)
    {
        m_WinVer = WIN_VER_WIN7;
    }
    else 
    {
        //win8开始使用RtlGetVersion(适用于>=XP)
        RTL_OSVERSIONINFOW rtl_vi={0};
        rtl_vi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
        pfnRtlGetVersion fnRtlGetVersion = NULL;

        fnRtlGetVersion = (pfnRtlGetVersion)GetProcAddress( GetModuleHandleW( L"ntdll.dll" ), "RtlGetVersion" );

        if (fnRtlGetVersion)
        {
            fnRtlGetVersion(&rtl_vi);
            dwMajorVersion = rtl_vi.dwMajorVersion;
            dwMinorVersion = rtl_vi.dwMinorVersion;

            AtlTrace(L"RtlGetVersion-%d-%d", dwMajorVersion, dwMinorVersion);

            if (dwMajorVersion==6 && dwMinorVersion==2)
            {
                m_WinVer = WIN_VER_WIN8;
            }
            else if (dwMajorVersion==6 && dwMinorVersion==3)
            {
                m_WinVer = WIN_VER_WIN81;
            }
            else if ((dwMajorVersion==10 && dwMinorVersion==0) ||
                     (dwMajorVersion==6 && dwMinorVersion==4))//Win10版本号可能为6.4或10.0
            {
                m_WinVer = WIN_VER_WIN10;
            }
        }
        else//RtlGetVersion不行的话该取kernel.dll版本
        {
            TCHAR szSystemDir[MAX_PATH]={0};

            //获得system32下kernel.dll文件路径
            GetSystemDirectory(szSystemDir, MAX_PATH);
            //ATLASSERT(szSystemDir!=NULL);
            PathCombine(szSystemDir, szSystemDir, _T("kernel32.dll"));

            //获得文件版本从而计算操作系统版本
            DWORD dwMajorVer = 0;
            DWORD dwMinorVer = 0;
            if (GetFileVersion(szSystemDir, dwMajorVer, dwMinorVer))
            {
                AtlTrace(L"GetFileVersion-%d-%d", dwMajorVer, dwMinorVer);

                if (dwMajorVer == MAKELONG(2,6))
                {
                    m_WinVer = WIN_VER_WIN8;
                }
                else if (dwMajorVer == MAKELONG(3,6))
                {
                    m_WinVer = WIN_VER_WIN81;
                }
                else if (dwMajorVer == MAKELONG(0,10) || 
                         dwMajorVer == MAKELONG(4,6))
                {
                    m_WinVer = WIN_VER_WIN10;
                }
            }
        }
    }

    return m_WinVer;
}

下载

演示程序和CSystemInfo类的代码下载链接