通过GetVersionEx和ntoskrnl.exe获取操作系统版本号

#include 
#include 
#include 
#include 
#include 
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Version.lib")

#ifdef UNICODE
typedef std::wstring	tstring;
#else
typedef std::string		tstring;
#endif // UNICODE

typedef struct __tagLANGANDCODEPAGE
{
	WORD   wLanguage;
	WORD   wCodePage;
}LANGANDCODEPAGE;
typedef LANGANDCODEPAGE*		PLANGANDCODEPAGE;
#define VERSION_UNKNOWN			TEXT("Unknown")
#define VERSION_UNCORRECT		TEXT("Uncorrect")

//校验 是否处于 WOW64模式下 
//如果 是 WOW64 即 32位应用程序运行在 64位操作系统下,这时如果要获取 system32真实路径需要关闭 操作系统文件重定向功能
//微软 提供两种 WOW64模式检测机制

//IsWow64Process 方式
BOOL IsWow64WithIsWow64Process(PBOOL bIsWow64)
{
	*bIsWow64 = FALSE;
	HMODULE hKernel32 = NULL;
	BOOL bRes = FALSE;

	//IsWow64Process 最小支持的操作系统为 Windows XP with SP2 
	//所以需要作出兼容性处理
	typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
	do 
	{
		//1.获取kernel32句柄
		hKernel32 = ::LoadLibrary(TEXT("Kernel32.dll"));
		if ( NULL == hKernel32 )
		{
			::OutputDebugStringA("--> IsWow64WithIsWow64Process Error 1");
			break;
		}

		//2.获取 IsWow64Process 函数地址
		LPFN_ISWOW64PROCESS lpIsWow64Process = (LPFN_ISWOW64PROCESS)::GetProcAddress(hKernel32, "IsWow64Process");
		if ( NULL == lpIsWow64Process )
		{
			::OutputDebugStringA("--> IsWow64WithIsWow64Process Error 2");
			break;
		}

		//3.调用 IsWow64Process
		bRes = lpIsWow64Process(::GetCurrentProcess(), bIsWow64);
		
	} while (FALSE);
	
	if (NULL != hKernel32)
	{
		::FreeLibrary(hKernel32);
		hKernel32 = NULL;
	}

	return bRes;
}

//GetNativeSystemInfo 方式
BOOL IsWow64WithGetNativeSystemInfo(PBOOL bIsWow64)
{
	*bIsWow64 = FALSE;
	HMODULE hKernel32 = NULL;
	SYSTEM_INFO sysInfo = { 0 };
	SYSTEM_INFO sysNativeInfo = { 0 };
	BOOL bRes = FALSE;

	//GetSystemInfo 最小要求系统为 Windows 2000 Professional 
	//GetNativeSystemInfo 最小要求系统为 Windows XP 
	//所以不需要作出任何兼容性处理,直接使用两个函数
	typedef void (WINAPI *LPFN_GetNativeSystemInfo)(LPSYSTEM_INFO);

	do 
	{
		//1.调用 GetSystemInfo
		::GetSystemInfo(&sysInfo);

		//2.调用 GetNativeSystemInfo获取kernel32句柄
		hKernel32 = ::LoadLibrary(TEXT("Kernel32.dll"));
		if ( NULL == hKernel32 )
		{
			::OutputDebugStringA("--> IsWow64WithGetNativeSystemInfo Error 1");
			break;
		}
		
		LPFN_GetNativeSystemInfo lpGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)::GetProcAddress(hKernel32, "GetNativeSystemInfo");
		if ( NULL == lpGetNativeSystemInfo )
		{
			::OutputDebugStringA("--> IsWow64WithGetNativeSystemInfo Error 2");
			break;
		}
		lpGetNativeSystemInfo(&sysNativeInfo);

		//3.分析
		/*
		根据MSDN的解释:SYSTEM_INFO 中的 wProcessorArchitecture 成员 此值为0时是 IA32,为9 时 是 AMD64
		如果32位程序 在 win32系统中 运行,则两个值都是 0,如果在win64 系统运行,则是GetSystemInfo 返回0, 
		GetNativeSystemInfo 返回9,简而言之 当着两个值不同时就认为程序在 win64系统上运行.
		*/
		if ( sysInfo.wProcessorArchitecture != sysNativeInfo.wProcessorArchitecture)
		{
			::OutputDebugStringA("IsWow64WithGetNativeSystemInfo --> WOW64!!");
			*bIsWow64 = TRUE;
		}
		else
		{
			::OutputDebugStringA("IsWow64WithGetNativeSystemInfo --> NOT WOW64!!");
			*bIsWow64 = FALSE;
		}

		bRes = TRUE;

	} while (FALSE);

	if (NULL != hKernel32)
	{
		::FreeLibrary(hKernel32);
		hKernel32 = NULL;
	}
	
	return bRes;
}

BOOL IsWow64(void)
{
	BOOL bIsWow64First = FALSE;
	BOOL bIsWow64Second = FALSE;
	BOOL bIsWow64 = FALSE;

	//1.先使用第一种方式
	BOOL bResFirst = IsWow64WithIsWow64Process(&bIsWow64First);

	//2.第二种方式
	BOOL bResSecond = IsWow64WithGetNativeSystemInfo(&bIsWow64Second);

	//3.校验
	if ( TRUE == bResFirst )
	{
		if ( bIsWow64First == bIsWow64Second )
		{
			::OutputDebugStringA("--> IsWow64 : The same results for the two time.");
			bIsWow64 = bIsWow64First;
		}
		else
		{//如果第一个函数执行成功,但是第一个函数返回的结果与第二个不一致时
         //以第二种方式检测为准
			::OutputDebugStringA("--> IsWow64 : The two execution results are not the same, using the results of the second.");
			bIsWow64 = bIsWow64Second;
		}
	}
	else
	{//如果第一个函数执行失败,直接使用第二种方式
		::OutputDebugStringA("--> IsWow64 : The first failure, using the results of the second.");
		bIsWow64 = bIsWow64Second;
	}

	return bIsWow64;
}


//文件重定向相关
BOOL TWow64EnableWow64FsRedirection(BOOLEAN bWow64FsEnableRedirection)
{
	BOOL bRes = FALSE;
	HMODULE hKernel32dll = NULL;
	do 
	{
		//1.获取 Kernel32.dll 模块句柄
		hKernel32dll = ::LoadLibraryA("Kernel32.dll");
		if ( NULL == hKernel32dll )
		{
			::OutputDebugStringA("--> GetWow64EnableWow64FsRedirectionAddr. Get [Kernel32.dll] error.");
			break;
		}

		//2.获取 Wow64EnableWow64FsRedirection 函数地址
		typedef BOOLEAN(WINAPI *pFunWow64EnableWow64FsRedirection)(BOOLEAN);
		pFunWow64EnableWow64FsRedirection	lpWow64EnableWow64FsRedirection = (pFunWow64EnableWow64FsRedirection)::GetProcAddress(hKernel32dll, "Wow64EnableWow64FsRedirection");
		if ( NULL == lpWow64EnableWow64FsRedirection )
		{
			::OutputDebugStringA("--> GetWow64EnableWow64FsRedirectionAddr. Get [Wow64EnableWow64FsRedirection] error.");
			break;
		}

		//3.执行
		bRes = lpWow64EnableWow64FsRedirection(bWow64FsEnableRedirection);
		if ( FALSE == bRes )
		{
			DWORD dwCode = ::GetLastError();
			char szLog[512] = { 0 };
			sprintf_s(szLog, 511, "--> TWow64EnableWow64FsRedirection Call API Error code = %u", dwCode);
			::OutputDebugStringA(szLog);
			break;
		}

		::OutputDebugStringA("--> TWow64EnableWow64FsRedirection End(ok)");

	} while (FALSE);

	if ( NULL != hKernel32dll )
	{
		::FreeLibrary(hKernel32dll);
		hKernel32dll = NULL;
	}

	return bRes;
}


//获取 system32 文件夹 路径("C:\windows\system32")
BOOL GetSystem32DirPath(LPTSTR lpFullPath, DWORD dwSize)
{
	TCHAR szBuf[MAX_PATH + 1] = { 0 };

	do 
	{
		//0.GetSystemDirectory
		if (0 != ::GetSystemDirectory(lpFullPath, dwSize))
		{
			::OutputDebugString(lpFullPath);

			return TRUE;
		}

		//1.使用 SHGetSpecialFolderPath  //C:\windows
		if (TRUE == ::SHGetSpecialFolderPath(NULL, szBuf, CSIDL_WINDOWS, FALSE))
		{
			::OutputDebugString(szBuf);
			break;
		}

		//2.如果失败使用GetWindowsDirectory //C:\windows
		if ( 0 != ::GetWindowsDirectory(szBuf, MAX_PATH) )
		{
			::OutputDebugString(szBuf);
			break;
		}

		//3.如果都失败 直接认为 c:\\windows
		::ZeroMemory(lpFullPath, (MAX_PATH+1)* sizeof(TCHAR));
		_tcscpy_s(szBuf, MAX_PATH, TEXT("C:\\windows"));

	} while (FALSE);

	DWORD dwBufSize = _tcslen(szBuf);
	if ( (NULL == lpFullPath) || ( dwSize < dwBufSize) )
	{
		TCHAR szLog[512] = { 0 };
		_stprintf_s(szLog, 511, TEXT("GetSystem32DirPath Failed. Size=%d, OurSize=%d"), dwSize, dwBufSize);
		::OutputDebugString(szLog);

		return FALSE;
	}

	_stprintf_s(lpFullPath, dwSize - 1, TEXT("%s\\system32"), szBuf);
	::OutputDebugString(lpFullPath);

	return TRUE; 
}


//获取 ntoskrnl.exe 文件的 “产品版本号”
tstring GetNtosKrnlFileVersion(LPCTSTR lpFullPath)
{
	DWORD dwHandle = 0;
	DWORD dwFileInfoSize = ::GetFileVersionInfoSize(lpFullPath, &dwHandle);
	if (0 == dwFileInfoSize)
	{
		return tstring(TEXT(""));
	}

	std::vector sResult(dwFileInfoSize /** sizeof(WCHAR)*/, 0x00);
	if (FALSE == ::GetFileVersionInfo(lpFullPath, 0, dwFileInfoSize, &sResult.front()))
	{
		return tstring(TEXT(""));
	}

	PLANGANDCODEPAGE lpTranslationPtr = NULL;
	UINT uLen = 0;
	if (FALSE == ::VerQueryValue(&sResult.front(), TEXT("VarFileInfo\\Translation"), (LPVOID*)&lpTranslationPtr, &uLen))
	{
		return tstring(TEXT(""));
	}

	TCHAR szVersionValue[512] = TEXT("");
	_stprintf_s(szVersionValue, 511, TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslationPtr[0].wLanguage, lpTranslationPtr[0].wCodePage);

	LPTSTR lpInformationPtr = NULL;
	if (FALSE == ::VerQueryValue(&sResult.front(), szVersionValue, (LPVOID*)&lpInformationPtr, &uLen))
	{
		return tstring(TEXT(""));
	}

	if (_tcslen(lpInformationPtr) <= 0)
	{
		return tstring(TEXT(""));
	}

	return tstring(lpInformationPtr);
}


//根据 ntoskrnl产品版本号 获取 主版本号、次版本号、Build号
BOOL GetVersionInfos(tstring tstrVer, LPDWORD lpdwMajorVersion, LPDWORD lpdwMinorVersion, LPDWORD lpdwBuildNumber)
{
	//1.主版本号
	int nMajorVersionIndex = tstrVer.find(TEXT("."));
	if ( tstring::npos == nMajorVersionIndex )
	{
		return FALSE;
	}

	tstring tstrMajorVersion = tstrVer.substr(0, nMajorVersionIndex);

	//2.次版本号
	tstrVer = tstrVer.substr(nMajorVersionIndex + 1);
	int nMinorVersionIndex = tstrVer.find(TEXT("."));
	if ( tstring::npos == nMinorVersionIndex )
	{
		return FALSE;
	}

	tstring tstrMinorVersion = tstrVer.substr(0, nMinorVersionIndex);

	//3.Build号
	tstrVer = tstrVer.substr(nMinorVersionIndex + 1);
	int nBuildIndex = tstrVer.find(TEXT("."));
	if ( tstring::npos == nBuildIndex )
	{
		return FALSE;
	}

	tstring tstrBuild = tstrVer.substr(0, nBuildIndex);

	//4.生成
	*lpdwMajorVersion = _ttoi(tstrMajorVersion.c_str());
	*lpdwMinorVersion = _ttoi(tstrMinorVersion.c_str());
	*lpdwBuildNumber = _ttoi(tstrBuild.c_str());

	return TRUE;
}


//获取 ntoskrnl.exe 文件的 “产品版本号”
BOOL GetNtosKrnlFileVersion(LPDWORD lpdwMajorVersion, LPDWORD lpdwMinorVersion, LPDWORD lpdwBuildNumber)
{
	BOOL bIsCloseWow64 = FALSE;
	BOOL bRes = FALSE;

	do 
	{
		//1.校验 WOW64模式
		//2.如果处于WOW64模式,禁用文件重定向
		if (TRUE == IsWow64())
		{
			if (FALSE == TWow64EnableWow64FsRedirection(FALSE))
			{
				break;
			}

			bIsCloseWow64 = TRUE;
		}

		//3.获取system32目录路径
		TCHAR szPath[MAX_PATH + 1] = { 0 };
		if (FALSE == GetSystem32DirPath(szPath, MAX_PATH) )
		{
			break;
		}

		tstring tstrNtosKrnl(szPath);
		tstrNtosKrnl += TEXT("\\ntoskrnl.exe");
		::OutputDebugString(tstrNtosKrnl.c_str());

		//4.获取ntoskrnl版本号
		tstring tstrResult = GetNtosKrnlFileVersion(tstrNtosKrnl.c_str());
		if ((tstring(VERSION_UNKNOWN) == tstrResult) || (tstring(VERSION_UNCORRECT) == tstrResult))
		{
			break;
		}

		//////////////////////////////////////////////////////////////////////////
		//5.读取 主版本号、次版本号、Build号
		if (FALSE == GetVersionInfos(tstrResult, lpdwMajorVersion, lpdwMinorVersion, lpdwBuildNumber))
		{
			break;
		}

		//6. 成功 设置标记位
		bRes = TRUE;

		//LOG
		TCHAR szLog[512] = { 0 };
		_stprintf_s(szLog, 511, TEXT("Version: %d.%d  Build : %d"), *lpdwMajorVersion, *lpdwMinorVersion, *lpdwBuildNumber);
		::OutputDebugString(szLog);
	} while (FALSE);

	if (TRUE == bIsCloseWow64)
	{
		TWow64EnableWow64FsRedirection(TRUE);
	}

	return  bRes;
}


// 获取 操作系统版本号
DWORD GetVersion(void)
{
	OSVERSIONINFO osInfo = { 0 };
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (FALSE == GetVersionEx(&osInfo))
	{
		return ::GetVersion();
	}
	
	DWORD dwMajorVersion = osInfo.dwMajorVersion & 0xFFFFFFFF;
	DWORD dwMinorVersion = (osInfo.dwMinorVersion & 0xFFFFFFFF) << 8;
	DWORD dwVerTemp = dwMajorVersion | dwMinorVersion;
	DWORD dwBuild = (osInfo.dwBuildNumber & 0xFFFFFFFF) << 16;
	
	return (dwBuild | dwVerTemp);
}

 

你可能感兴趣的:(工作随笔篇,VC++(初级篇))