941d28df75
git-svn-id: svn://10.65.10.50/branches/R_10_00@23147 c028cbd2-c16b-5b4b-a496-9718f37d4682
677 lines
19 KiB
C++
Executable File
677 lines
19 KiB
C++
Executable File
// XFont.cpp Version 1.1
|
|
//
|
|
// Author: Philip Patrick (GetFontProperties)
|
|
//
|
|
// Version 1.0 - Initial release of GetFontProperties()
|
|
//
|
|
// Modified by: Hans Dietrich
|
|
// hdietrich2@hotmail.com
|
|
//
|
|
// Version 1.1: - Removed MFC dependency from GetFontProperties()
|
|
// - Converted CFile file I/O to memory mapped file
|
|
// - Added Unicode support
|
|
// - Combined with my GetFontFile() routine
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "XTrace.h"
|
|
#include "XFont.h"
|
|
|
|
#include <crtdbg.h>
|
|
#include <shlobj.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// If you do not want TRACE output you can
|
|
// uncomment the following lines:
|
|
//
|
|
#undef TRACE
|
|
#if _MSC_VER > 1300
|
|
#define TRACE __noop
|
|
#else
|
|
#define TRACE ((void)0)
|
|
#endif
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma warning(disable : 4127) // conditional expression is constant
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// private routines
|
|
static LONG GetNextNameValue(HKEY key, LPCTSTR subkey, LPTSTR szName, LPTSTR szData);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// defines used by GetWinVer()
|
|
#define WUNKNOWNSTR _T("unknown Windows version")
|
|
|
|
#define W2KSTR _T("Windows 2000")
|
|
#define WXPSTR _T("Windows XP")
|
|
#define W2003STR _T("Windows Server 2003")
|
|
#define WVISTASTR _T("Windows Vista")
|
|
#define W2008STR _T("Windows Server 2008")
|
|
#define W2008R2STR _T("Windows Server 2008 R2")
|
|
#define W7STR _T("Windows 7")
|
|
#define W2012STR _T("Windows Server 2012")
|
|
#define W8STR _T("Windows 8")
|
|
#define W10STR _T("Windows 10")
|
|
#define W2016STR _T("Windows Server 2016")
|
|
|
|
#define WUNKNOWN 0
|
|
|
|
#define W9XFIRST 1
|
|
#define W95 1
|
|
#define W95SP1 2
|
|
#define W95OSR2 3
|
|
#define W98 4
|
|
#define W98SP1 5
|
|
#define W98SE 6
|
|
#define WME 7
|
|
#define W9XLAST 99
|
|
|
|
#define WNTFIRST 101
|
|
#define WNT351 101
|
|
#define WNT4 102
|
|
#define W2K 103
|
|
#define WXP 104
|
|
#define W2003 105
|
|
#define WVISTA 106
|
|
#define W2008 107
|
|
#define W2008R2 108
|
|
#define W7 109
|
|
#define W2012 110
|
|
#define W8 111
|
|
#define W10 112
|
|
#define W2016 103
|
|
#define WNTLAST 199
|
|
|
|
#define WCEFIRST 201
|
|
#define WCE 201
|
|
#define WCELAST 299
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// structs used by GetFontProperties()
|
|
//
|
|
typedef struct _tagFONT_PROPERTIES_ANSI
|
|
{
|
|
char csName[1024];
|
|
char csCopyright[1024];
|
|
char csTrademark[1024];
|
|
char csFamily[1024];
|
|
} FONT_PROPERTIES_ANSI;
|
|
|
|
typedef struct _tagTT_OFFSET_TABLE
|
|
{
|
|
USHORT uMajorVersion;
|
|
USHORT uMinorVersion;
|
|
USHORT uNumOfTables;
|
|
USHORT uSearchRange;
|
|
USHORT uEntrySelector;
|
|
USHORT uRangeShift;
|
|
} TT_OFFSET_TABLE;
|
|
|
|
typedef struct _tagTT_TABLE_DIRECTORY
|
|
{
|
|
char szTag[4]; //table name
|
|
ULONG uCheckSum; //Check sum
|
|
ULONG uOffset; //Offset from beginning of file
|
|
ULONG uLength; //length of the table in bytes
|
|
} TT_TABLE_DIRECTORY;
|
|
|
|
typedef struct _tagTT_NAME_TABLE_HEADER
|
|
{
|
|
USHORT uFSelector; //format selector. Always 0
|
|
USHORT uNRCount; //Name Records count
|
|
USHORT uStorageOffset; //Offset for strings storage, from start of the table
|
|
} TT_NAME_TABLE_HEADER;
|
|
|
|
typedef struct _tagTT_NAME_RECORD
|
|
{
|
|
USHORT uPlatformID;
|
|
USHORT uEncodingID;
|
|
USHORT uLanguageID;
|
|
USHORT uNameID;
|
|
USHORT uStringLength;
|
|
USHORT uStringOffset; //from start of storage area
|
|
} TT_NAME_RECORD;
|
|
|
|
#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
|
|
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetFontFile()
|
|
//
|
|
// Purpose: Find the name of font file from the font name
|
|
//
|
|
// Parameters: lpszFontName - name of font
|
|
// lpszDisplayName - pointer to buffer where font display name
|
|
// will be copied
|
|
// nDisplayNameSize - size of display name buffer in TCHARs
|
|
// lpszFontFile - pointer to buffer where font file name
|
|
// will be copied
|
|
// nFontFileSize - size of font file buffer in TCHARs
|
|
//
|
|
// Returns: BOOL - TRUE = success
|
|
//
|
|
// Notes: This is *not* a foolproof method for finding the name of a
|
|
// font file. If a font has been installed in a normal manner,
|
|
// and if it is in the Windows "Font" directory, then this method
|
|
// will probably work. It will probably work for most screen
|
|
// fonts and TrueType fonts. However, this method might not work
|
|
// for fonts that are created or installed dynamically, or that
|
|
// are specific to a particular device, or that are not installed
|
|
// into the font directory.
|
|
//
|
|
BOOL GetFontFile(LPCTSTR lpszFontName,
|
|
LPTSTR lpszDisplayName,
|
|
int nDisplayNameSize,
|
|
LPTSTR lpszFontFile,
|
|
int nFontFileSize)
|
|
{
|
|
_ASSERTE(lpszFontName && lpszFontName[0] != 0);
|
|
if (!lpszFontName || lpszFontName[0] == 0)
|
|
return FALSE;
|
|
|
|
_ASSERTE(lpszDisplayName);
|
|
if (!lpszDisplayName)
|
|
return FALSE;
|
|
|
|
_ASSERTE(lpszFontFile);
|
|
if (!lpszFontFile)
|
|
return FALSE;
|
|
|
|
lpszDisplayName[0] = _T('\0');
|
|
lpszFontFile[0] = _T('\0');
|
|
|
|
TCHAR szName[2 * MAX_PATH];
|
|
TCHAR szData[2 * MAX_PATH];
|
|
|
|
int nVersion;
|
|
TCHAR szVersion[100];
|
|
GetWinVer(szVersion, sizeof(szVersion)/sizeof(TCHAR)-1, &nVersion);
|
|
|
|
LPCTSTR szFontPath = NULL;
|
|
if ((nVersion >= WNTFIRST) && (nVersion <= WNTLAST))
|
|
szFontPath = _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
|
|
else
|
|
szFontPath = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Fonts");
|
|
|
|
BOOL bResult = FALSE;
|
|
|
|
while (GetNextNameValue(HKEY_LOCAL_MACHINE, szFontPath, szName, szData) == ERROR_SUCCESS)
|
|
{
|
|
if (_tcsnicmp(lpszFontName, szName, _tcslen(lpszFontName)) == 0)
|
|
{
|
|
TRACE(_T("found font\n"));
|
|
_tcsncpy(lpszDisplayName, szName, nDisplayNameSize-1);
|
|
_tcsncpy(lpszFontFile, szData, nFontFileSize-1);
|
|
bResult = TRUE;
|
|
break;
|
|
}
|
|
szFontPath = _T(""); // this will get next value, same key
|
|
}
|
|
|
|
GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key
|
|
|
|
return bResult;
|
|
}
|
|
|
|
bool GetFontsFolder(LPTSTR lpszFontPath, int nFontPathSize)
|
|
{
|
|
_ASSERTE(nFontPathSize >= _MAX_PATH);
|
|
*lpszFontPath = '\0';
|
|
SHGetFolderPath(NULL, CSIDL_FONTS, NULL, 0, lpszFontPath);
|
|
return *lpszFontPath != '\0';
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetFontProperties()
|
|
//
|
|
// Purpose: Get font name from font file
|
|
//
|
|
// Parameters: lpszFilePath - file path of font file
|
|
// lpFontPropsX - pointer to font properties struct
|
|
//
|
|
// Returns: BOOL - TRUE = success
|
|
//
|
|
BOOL GetFontProperties(LPCTSTR lpszFilePath, FONT_PROPERTIES * lpFontPropsX)
|
|
{
|
|
FONT_PROPERTIES_ANSI fp;
|
|
FONT_PROPERTIES_ANSI * lpFontProps = &fp;
|
|
|
|
memset(lpFontProps, 0, sizeof(FONT_PROPERTIES_ANSI));
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
hFile = ::CreateFile(lpszFilePath,
|
|
GENERIC_READ,// | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE(_T("ERROR: failed to open '%s'\n"), lpszFilePath);
|
|
TRACE(_T("ERROR: %s failed\n"), _T("CreateFile"));
|
|
return FALSE;
|
|
}
|
|
|
|
// get the file size
|
|
DWORD dwFileSize = ::GetFileSize(hFile, NULL);
|
|
|
|
if (dwFileSize == INVALID_FILE_SIZE)
|
|
{
|
|
TRACE(_T("ERROR: %s failed\n"), _T("GetFileSize"));
|
|
::CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE(_T("dwFileSize = %d\n"), dwFileSize);
|
|
|
|
// Create a file mapping object that is the current size of the file
|
|
HANDLE hMappedFile = NULL;
|
|
hMappedFile = ::CreateFileMapping(hFile,
|
|
NULL,
|
|
PAGE_READONLY, //PAGE_READWRITE,
|
|
0,
|
|
dwFileSize,
|
|
NULL);
|
|
|
|
if (hMappedFile == NULL)
|
|
{
|
|
TRACE(_T("ERROR: %s failed\n"), _T("CreateFileMapping"));
|
|
::CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
LPBYTE lpMapAddress = (LPBYTE) ::MapViewOfFile(hMappedFile, // handle to file-mapping object
|
|
FILE_MAP_READ,//FILE_MAP_WRITE, // access mode
|
|
0, // high-order DWORD of offset
|
|
0, // low-order DWORD of offset
|
|
0); // number of bytes to map
|
|
|
|
if (lpMapAddress == NULL)
|
|
{
|
|
TRACE(_T("ERROR: %s failed\n"), _T("MapViewOfFile"));
|
|
::CloseHandle(hMappedFile);
|
|
::CloseHandle(hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bRetVal = FALSE;
|
|
int index = 0;
|
|
|
|
TT_OFFSET_TABLE ttOffsetTable;
|
|
memcpy(&ttOffsetTable, &lpMapAddress[index], sizeof(TT_OFFSET_TABLE));
|
|
index += sizeof(TT_OFFSET_TABLE);
|
|
|
|
ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
|
|
ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
|
|
ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
|
|
|
|
//check is this is a true type font and the version is 1.0
|
|
if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
|
|
return bRetVal;
|
|
|
|
TT_TABLE_DIRECTORY tblDir;
|
|
memset(&tblDir, 0, sizeof(TT_TABLE_DIRECTORY));
|
|
BOOL bFound = FALSE;
|
|
char szTemp[4096];
|
|
memset(szTemp, 0, sizeof(szTemp));
|
|
|
|
for (int i = 0; i< ttOffsetTable.uNumOfTables; i++)
|
|
{
|
|
//f.Read(&tblDir, sizeof(TT_TABLE_DIRECTORY));
|
|
memcpy(&tblDir, &lpMapAddress[index], sizeof(TT_TABLE_DIRECTORY));
|
|
index += sizeof(TT_TABLE_DIRECTORY);
|
|
|
|
strncpy(szTemp, tblDir.szTag, 4);
|
|
if (_stricmp(szTemp, "name") == 0)
|
|
{
|
|
bFound = TRUE;
|
|
tblDir.uLength = SWAPLONG(tblDir.uLength);
|
|
tblDir.uOffset = SWAPLONG(tblDir.uOffset);
|
|
break;
|
|
}
|
|
else if (szTemp[0] == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
index = tblDir.uOffset;
|
|
|
|
TT_NAME_TABLE_HEADER ttNTHeader;
|
|
memcpy(&ttNTHeader, &lpMapAddress[index], sizeof(TT_NAME_TABLE_HEADER));
|
|
index += sizeof(TT_NAME_TABLE_HEADER);
|
|
|
|
ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
|
|
ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
|
|
TT_NAME_RECORD ttRecord;
|
|
bFound = FALSE;
|
|
|
|
for (int i = 0;
|
|
i < ttNTHeader.uNRCount &&
|
|
(lpFontProps->csCopyright[0] == 0 ||
|
|
lpFontProps->csName[0] == 0 ||
|
|
lpFontProps->csTrademark[0] == 0 ||
|
|
lpFontProps->csFamily[0] == 0);
|
|
i++)
|
|
{
|
|
memcpy(&ttRecord, &lpMapAddress[index], sizeof(TT_NAME_RECORD));
|
|
index += sizeof(TT_NAME_RECORD);
|
|
|
|
ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
|
|
ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
|
|
ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
|
|
|
|
if (ttRecord.uNameID == 1 || ttRecord.uNameID == 0 || ttRecord.uNameID == 7)
|
|
{
|
|
int nPos = index; //f.GetPosition();
|
|
|
|
index = tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset;
|
|
|
|
memset(szTemp, 0, sizeof(szTemp));
|
|
|
|
memcpy(szTemp, &lpMapAddress[index], ttRecord.uStringLength);
|
|
index += ttRecord.uStringLength;
|
|
|
|
if (szTemp[0] != 0)
|
|
{
|
|
_ASSERTE(strlen(szTemp) < sizeof(lpFontProps->csName));
|
|
|
|
switch (ttRecord.uNameID)
|
|
{
|
|
case 0:
|
|
if (lpFontProps->csCopyright[0] == 0)
|
|
strncpy(lpFontProps->csCopyright, szTemp,
|
|
sizeof(lpFontProps->csCopyright)-1);
|
|
break;
|
|
|
|
case 1:
|
|
if (lpFontProps->csFamily[0] == 0)
|
|
strncpy(lpFontProps->csFamily, szTemp,
|
|
sizeof(lpFontProps->csFamily)-1);
|
|
bRetVal = TRUE;
|
|
break;
|
|
|
|
case 4:
|
|
if (lpFontProps->csName[0] == 0)
|
|
strncpy(lpFontProps->csName, szTemp,
|
|
sizeof(lpFontProps->csName)-1);
|
|
break;
|
|
|
|
case 7:
|
|
if (lpFontProps->csTrademark[0] == 0)
|
|
strncpy(lpFontProps->csTrademark, szTemp,
|
|
sizeof(lpFontProps->csTrademark)-1);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
index = nPos;
|
|
}
|
|
}
|
|
}
|
|
|
|
::UnmapViewOfFile(lpMapAddress);
|
|
::CloseHandle(hMappedFile);
|
|
::CloseHandle(hFile);
|
|
|
|
if (lpFontProps->csName[0] == 0)
|
|
strcpy(lpFontProps->csName, lpFontProps->csFamily);
|
|
|
|
memset(lpFontPropsX, 0, sizeof(FONT_PROPERTIES));
|
|
|
|
#ifdef _UNICODE
|
|
::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csName, -1, lpFontPropsX->csName,
|
|
sizeof(lpFontPropsX->csName)/sizeof(TCHAR)-1);
|
|
::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csCopyright, -1, lpFontPropsX->csCopyright,
|
|
sizeof(lpFontPropsX->csCopyright)/sizeof(TCHAR)-1);
|
|
::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csTrademark, -1, lpFontPropsX->csTrademark,
|
|
sizeof(lpFontPropsX->csTrademark)/sizeof(TCHAR)-1);
|
|
::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csFamily, -1, lpFontPropsX->csFamily,
|
|
sizeof(lpFontPropsX->csFamily)/sizeof(TCHAR)-1);
|
|
#else
|
|
strcpy(lpFontPropsX->csName, lpFontProps->csName);
|
|
strcpy(lpFontPropsX->csCopyright, lpFontProps->csCopyright);
|
|
strcpy(lpFontPropsX->csTrademark, lpFontProps->csTrademark);
|
|
strcpy(lpFontPropsX->csFamily, lpFontProps->csFamily);
|
|
#endif
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetNextNameValue()
|
|
//
|
|
// Purpose: Get first/next name/value pair from registry
|
|
//
|
|
// Parameters: key - handle to open key, or predefined key
|
|
// pszSubkey - subkey name
|
|
// pszName - pointer to buffer that receives the value string
|
|
// pszData - pointer to buffer that receives the data string
|
|
//
|
|
// Returns: LONG - return code from registry function; ERROR_SUCCESS = success
|
|
//
|
|
// Notes: If pszSubkey, pszName, and pszData are all NULL, then the open
|
|
// handle will be closed.
|
|
//
|
|
// The first time GetNextNameValue is called, pszSubkey should be
|
|
// specified. On subsequent calls, pszSubkey should be NULL or
|
|
// an empty string.
|
|
//
|
|
static LONG GetNextNameValue(HKEY key, LPCTSTR pszSubkey, LPTSTR pszName, LPTSTR pszData)
|
|
{
|
|
static HKEY hkey = NULL; // registry handle, kept open between calls
|
|
static DWORD dwIndex = 0; // count of values returned
|
|
LONG retval = ERROR_SUCCESS;
|
|
|
|
// if all parameters are NULL then close key
|
|
if (pszSubkey == NULL && pszName == NULL && pszData == NULL)
|
|
{
|
|
TRACE(_T("closing key\n"));
|
|
if (hkey)
|
|
::RegCloseKey(hkey);
|
|
hkey = NULL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// if subkey is specified then open key (first time)
|
|
if (pszSubkey && *pszSubkey)
|
|
{
|
|
// retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_ALL_ACCESS, &hkey); // Incapace...
|
|
retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_READ, &hkey); // ... devi solo leggere!
|
|
if (retval != ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("ERROR: RegOpenKeyEx failed\n"));
|
|
return retval;
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("RegOpenKeyEx ok\n"));
|
|
}
|
|
dwIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
dwIndex++;
|
|
}
|
|
|
|
_ASSERTE(pszName != NULL && pszData != NULL);
|
|
|
|
*pszName = 0;
|
|
*pszData = 0;
|
|
|
|
TCHAR szValueName[MAX_PATH];
|
|
DWORD dwValueNameSize = sizeof(szValueName)-1;
|
|
BYTE szValueData[MAX_PATH];
|
|
DWORD dwValueDataSize = sizeof(szValueData)-1;
|
|
DWORD dwType = 0;
|
|
|
|
retval = ::RegEnumValue(hkey, dwIndex, szValueName, &dwValueNameSize, NULL,
|
|
&dwType, szValueData, &dwValueDataSize);
|
|
if (retval == ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("szValueName=<%s> szValueData=<%s>\n"), szValueName, szValueData);
|
|
lstrcpy(pszName, (LPTSTR)szValueName);
|
|
lstrcpy(pszData, (LPTSTR)szValueData);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("RegEnumKey failed\n"));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
// from winbase.h
|
|
#ifndef VER_PLATFORM_WIN32s
|
|
#define VER_PLATFORM_WIN32s 0
|
|
#endif
|
|
#ifndef VER_PLATFORM_WIN32_WINDOWS
|
|
#define VER_PLATFORM_WIN32_WINDOWS 1
|
|
#endif
|
|
#ifndef VER_PLATFORM_WIN32_NT
|
|
#define VER_PLATFORM_WIN32_NT 2
|
|
#endif
|
|
#ifndef VER_PLATFORM_WIN32_CE
|
|
#define VER_PLATFORM_WIN32_CE 3
|
|
#endif
|
|
|
|
|
|
/*
|
|
This table has been assembled from Usenet postings, personal
|
|
observations, and reading other people's code. Please feel
|
|
free to add to it or correct it.
|
|
|
|
|
|
dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber
|
|
95 1 4 0 950
|
|
95 SP1 1 4 0 >950 && <=1080
|
|
95 OSR2 1 4 <10 >1080
|
|
98 1 4 10 1998
|
|
98 SP1 1 4 10 >1998 && <2183
|
|
98 SE 1 4 10 >=2183
|
|
ME 1 4 90 3000
|
|
|
|
NT 3.51 2 3 51
|
|
NT 4 2 4 0 1381
|
|
2000 2 5 0 2195
|
|
XP 2 5 1 2600
|
|
2003 2 5 2
|
|
Vista 2 6 0
|
|
2008 2 6 0
|
|
2008 R2 2 6 1
|
|
Win7 2 6 1 3600
|
|
Win8 2 6 2
|
|
Win8.1 2 6 3
|
|
Win10 2 6 4
|
|
Win10 2 10 0
|
|
CE 3
|
|
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetWinVer()
|
|
//
|
|
// Purpose: Get Windows version info
|
|
//
|
|
// Parameters: lpszVersion - pointer to buffer that receives the version
|
|
// string
|
|
// nVersionSize - size of the version buffer in TCHARs
|
|
// pnVersion - pointer to int that receives the version code
|
|
//
|
|
// Returns: BOOL - TRUE = success
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetWinVer
|
|
bool GetWinVer(LPTSTR lpszVersion, int nVersionSize, int *pnVersion)
|
|
{
|
|
int nVersion = WUNKNOWN;
|
|
LPCTSTR cp = WUNKNOWNSTR;
|
|
|
|
OSVERSIONINFOEX osinfo; memset(&osinfo, 0, sizeof(osinfo));
|
|
osinfo.dwOSVersionInfoSize = sizeof(osinfo);
|
|
if (::GetVersionEx((OSVERSIONINFO*)&osinfo))
|
|
{
|
|
DWORD dwPlatformId = osinfo.dwPlatformId;
|
|
DWORD dwMinorVersion = osinfo.dwMinorVersion;
|
|
DWORD dwMajorVersion = osinfo.dwMajorVersion;
|
|
DWORD dwBuildNumber = osinfo.dwBuildNumber & 0xFFFF; // Win 95 needs this
|
|
const bool bServer = osinfo.wProductType != VER_NT_WORKSTATION;
|
|
|
|
if (dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
if (dwMajorVersion <= 5)
|
|
{
|
|
switch (dwMinorVersion)
|
|
{
|
|
case 0: cp = W2KSTR; nVersion = W2K; break;
|
|
case 1: cp = WXPSTR; nVersion = WXP; break;
|
|
case 2:
|
|
default: cp = W2003STR; nVersion = W2003; break;
|
|
}
|
|
} else
|
|
if (dwMajorVersion == 6)
|
|
{
|
|
switch (dwMinorVersion)
|
|
{
|
|
case 0:
|
|
if (bServer)
|
|
{ cp = W2008STR; nVersion = W2008; }
|
|
else
|
|
{ cp = WVISTASTR; nVersion = WVISTA; }
|
|
break;
|
|
case 1:
|
|
if (bServer)
|
|
{ cp = W2008R2STR; nVersion = W2008R2; }
|
|
else
|
|
{ cp = W7STR; nVersion = W7; }
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
if (bServer)
|
|
{ cp = W2012STR; nVersion = W2012; }
|
|
else
|
|
{ cp = W8STR; nVersion = W8; }
|
|
break;
|
|
default:
|
|
if (bServer)
|
|
{ cp = W2016STR; nVersion = W2016; }
|
|
else
|
|
{ cp = W10STR; nVersion = W10; }
|
|
break;
|
|
}
|
|
} else
|
|
if (dwMajorVersion >= 10)
|
|
{
|
|
if (bServer)
|
|
{ cp = W2016STR; nVersion = W2016; }
|
|
else
|
|
{ cp = W10STR; nVersion = W10; }
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpszVersion != NULL && nVersionSize > 0)
|
|
_tcsncpy(lpszVersion, cp, nVersionSize-1);
|
|
if (pnVersion != NULL)
|
|
*pnVersion = nVersion;
|
|
|
|
return nVersion == WUNKNOWN;
|
|
}
|