정리

[MFC] Modaless Dailog - Itself destroy

저장소/VC++
Dialog를 띄우다보면 종종 Modaless로 띄워야 할 경우가 많다.
Modaless로 Dialog를 띄우는 방법은 다음과 같다.
CTestDlg*	m_pDlgTest;

void OpenDlg()
{
	m_pDlgTest = new CTestDlg;
	m_pDlgTest->Create(IDD_TEST_DIALOG, this);
	m_pDlgTest->ShowWindow(SW_SHOWNORMAL);
}
객체를 생성했기 때문에 Dialog가 닫히고나면 반드시 지워줘야 메모리 누수를 방지할 수 있다.
그런데... 종종 잊어버린다. ㅡㅡ; 문제다.

이런 문제를 사전에 방지하기 좋은 방법이 요기있넹~
기완형이 알려주셨던, 창훈형이 다시 알려준 좋은 방법 정리!!!
class CTestDlg : public CDialog
{
	DECLARE_DYNAMICCTestDlg 

public:
	CTestDlg(CTestDlg*& pOwnObjPtr);
	virtual ~CTestDlg();

	BOOL	Create(CWnd* pParentWnd = NULL);

Protected:
	...
	virtual void PostNcDestroy();
	afx_msg void OnClose();
	

private:
	CTestDlg*&	m_pOwnObjPtr;


};

CTestDlg::CTestDlg(CTestDlg*& pOwnObjPtr)
	: CDialog(CTestDlg::IDD, NULL)
	, m_pOwnObjPtr(pOwnObjPtr)
{
}

BOOL CTestDlg::Create(CWnd* pParentWnd)
{
	return CDialog::Create(IDD, pParentWnd);
}

void CTestDlg::PostNcDestroy()
{
	m_pOwnObPtr = NULL;
	delete this;
}

void CTestDlg::Close()
{
	DestoryWindow();
}

////////////////////////////////////////////////////////

CTestDlg*	m_pDlgTest;

void OpenDlg()
{
	m_pDlgTest = new CTestDlg(m_pDlgTest);
	m_pDlgTest->Create(this);
	m_pDlgTest->ShowWindow(SW_SHOWNORMAL);
}
수정이 필요한 부분만 정리했다.
중요 부분은 Constructor 수정, Create 함수 Overload, PostNcDestroy, OnClose 함수를 Override 해줘야 한다.
그리고 자신의 객체를 저장할 변수(CTestDlg*&)를 잡아주면 된다.
Dialog가 종료될 때 반드시 OnClose를 거치지는 않는다. 필요에 따라 손을 좀 봐줘야 한다.

주요 내용은 위와 같으며 요로코롬 해두면 Dialog가 닫힐 때 스스로 자신의 객체를 지우기 때문에 편리하다.
하지만 주의해야 할 것은 Modaless에만 해당된다는 것이다.
이렇게 처리한 Dialog는 Modal로 띄우면 스스로 객체를 지우는 과정 때문에 문제가 발생한다. 아마 그랬던 것 같다.
요령껏 쓰도록 합시다.

[MFC] Esc Key 또는 Return Key에 의해 Dialog가 닫힐 때 처리 방법

저장소/VC++
Dialog를 만들고 아무런 처리도 안하면 Esc Key 또는 Return Key를 누를 경우 Dialog가 종료된다.
이런게 편하다면 그냥 쓰면 되겠지만 불편할 때가 오히려 더 많다.
이 문제를 처리하기 위해서는 PreTranslateMessage를 Override해야한다.
아래와 같이 처리해주면 Esc Key나 Return Key를 눌러도 Dialog가 종료되지 않는다.

BOOL CXXXDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class

	if(NULL != pMsg)
	{
		if(WM_KEYDOWN == pMsg->message)
		{
			if( VK_RETURN == pMsg->wParam ||
			    VK_ESCAPE == pMsg->wParam )
			{
				return FALSE;
			}
		}
	}

	return CDialog::PreTranslateMessage(pMsg);
}

[MFC] OnCancel(), OnClose(), OnDestroy(), OnOK() 그리고 Dialog 소멸자

저장소/VC++

예전 스프링노트에 정리했던 내용



Dialog가 종료되는 상황

  1. IDOK 버튼을 눌렀을 때
    • OnOK() 호출 뒤 OnDestroy() 호출됨
  2. IDCANCEL 버튼을 눌렀을 때
    • OnCancel() 호출 뒤 OnDestroy() 호출됨
  3. Dialog의 우측 상단 종료 버튼(x)를 눌렀을 때
    • OnClose() 호출 뒤 OnCancel() 마지막으로 OnDestroy() 호출됨
  4. Esc 버튼을 눌러 종료할 때 - 결과만 놓고 봤을 때 'Esc = IDCANCEL' 이 된다는 말인가?? 아무튼 결과는 동일
    • OnCancel() 호출 뒤 OnDestroy() 호출됨
  5. Alt + F4 로 종료할 때
    • OnClose() 호출 뒤 OnCancel() 마지막으로 OnDestroy() 호출됨

[Win32 API] RegQueryInfoKey

저장소/VC++

RegQueryInfoKey Function

Retrieves information about the specified registry key.

LONG WINAPI RegQueryInfoKey(
  __in          HKEY hKey,
  __out         LPTSTR lpClass,
  __in_out      LPDWORD lpcClass,
  LPDWORD lpReserved,
  __out         LPDWORD lpcSubKeys,
  __out         LPDWORD lpcMaxSubKeyLen,
  __out         LPDWORD lpcMaxClassLen,
  __out         LPDWORD lpcValues,
  __out         LPDWORD lpcMaxValueNameLen,
  __out         LPDWORD lpcMaxValueLen,
  __out         LPDWORD lpcbSecurityDescriptor,
  __out         PFILETIME lpftLastWriteTime
);

Parameters

hKey

A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right. For more information, see Registry Key Security and Access Rights.

This handle is returned by the RegCreateKeyEx, RegCreateKeyTransacted, RegOpenKeyEx, or RegOpenKeyTransacted function. It can also be one of the following predefined keys:


     HKEY_CLASSES_ROOT
     HKEY_CURRENT_CONFIG
     HKEY_CURRENT_USER
     HKEY_LOCAL_MACHINE
     HKEY_PERFORMANCE_DATA
     HKEY_USERS

Windows Me/98/95:  This parameter can also be the following key:

HKEY_DYN_DATA

lpClass

A pointer to a buffer that receives the key class. This parameter can be NULL.

lpcClass

A pointer to a variable that specifies the size of the buffer pointed to by the lpClass parameter, in characters.

The size should include the terminating null character. When the function returns, this variable contains the size of the class string that is stored in the buffer. The count returned does not include the terminating null character. If the buffer is not big enough, the function returns ERROR_MORE_DATA, and the variable contains the size of the string, in characters, without counting the terminating null character.

If lpClass is NULL, lpcClass can be NULL.

If the lpClass parameter is a valid address, but the lpcClass parameter is not, for example, it is NULL, then the function returns ERROR_INVALID_PARAMETER.

Windows Me/98/95:  If the lpClass parameter is a valid address, but the lpcClass parameter is not, for example, it is NULL, then the function returns ERROR_SUCCESS instead of ERROR_INVALID_PARAMETER. To ensure compatibility with other platforms, verify that lpcClass is valid before calling the function.
lpReserved

This parameter is reserved and must be NULL.

lpcSubKeys

A pointer to a variable that receives the number of subkeys that are contained by the specified key. This parameter can be NULL.

lpcMaxSubKeyLen

A pointer to a variable that receives the size of the key's subkey with the longest name, in Unicode characters, not including the terminating null character. This parameter can be NULL.

Windows Me/98/95:  The size includes the terminating null character.
lpcMaxClassLen

A pointer to a variable that receives the size of the longest string that specifies a subkey class, in Unicode characters. The count returned does not include the terminating null character. This parameter can be NULL.

lpcValues

A pointer to a variable that receives the number of values that are associated with the key. This parameter can be NULL.

lpcMaxValueNameLen

A pointer to a variable that receives the size of the key's longest value name, in Unicode characters. The size does not include the terminating null character. This parameter can be NULL.

lpcMaxValueLen

A pointer to a variable that receives the size of the longest data component among the key's values, in bytes. This parameter can be NULL.

lpcbSecurityDescriptor

A pointer to a variable that receives the size of the key's security descriptor, in bytes. This parameter can be NULL.

lpftLastWriteTime

A pointer to a FILETIME structure that receives the last write time. This parameter can be NULL.

The function sets the members of the FILETIME structure to indicate the last time that the key or any of its value entries is modified.

Windows Me/98/95:  The function sets the members of the FILETIME structure to 0 (zero), because the system does not keep track of registry key last write time information.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is a system error code.

If the lpClass buffer is too small to receive the name of the class, the function returns ERROR_MORE_DATA.

Example Code

For an example, see Enumerating Registry Subkeys.

Requirements

Client

Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, or Windows 95.

Server

Requires Windows Server 2008, Windows Server 2003, Windows 2000 Server, or Windows NT Server.

Header

Declared in Winreg.h; include Windows.h.

Library

Use Advapi32.lib.

DLL

Requires Advapi32.dll.

Unicode

Implemented as RegQueryInfoKeyW (Unicode) and RegQueryInfoKeyA (ANSI).

[Win32 API] Registry Element Size Limits

저장소/VC++

Registry Element Size Limits

The following table identifies the size limits for the various registry elements.

Registry Element Size Limit
Key name 255 characters
Value name 16,383 characters
Windows 2000:  260 ANSI characters or 16,383 Unicode characters.
Windows Me/98/95:  255 characters
Value Available memory (latest format)

1MB (standard format)

Windows Me/98/95:  16,300 bytes.
Windows 95:  There is a 64K limit for the total size of all values of a key.
Tree A registry tree can be 512 levels deep. You can create up to 32 levels at a time through a single registry API call.

Long values (more than 2,048 bytes) should be stored as files with the file names stored in the registry. This helps the registry perform efficiently.


[Win32 API] RegEnumKeyEx

저장소/VC++

RegEnumKeyEx Function

Enumerates the subkeys of the specified open registry key. The function retrieves information about one subkey each time it is called.

LONG WINAPI RegEnumKeyEx(
  __in          HKEY hKey,
  __in          DWORD dwIndex,
  __out         LPTSTR lpName,
  __in_out      LPDWORD lpcName,
  LPDWORD lpReserved,
  __in_out      LPTSTR lpClass,
  __in_out      LPDWORD lpcClass,
  __out         PFILETIME lpftLastWriteTime
);

Parameters

hKey

A handle to an open registry key. The key must have been opened with the KEY_ENUMERATE_SUB_KEYS access right. For more information, see Registry Key Security and Access Rights.

This handle is returned by the RegCreateKeyEx, RegCreateKeyTransacted, RegOpenKeyEx, or RegOpenKeyTransacted function. It can also be one of the following predefined keys:

HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_PERFORMANCE_DATA
HKEY_USERS

Windows Me/98/95:  This parameter can also be the following value:

HKEY_DYN_DATA

dwIndex

The index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then incremented for subsequent calls.

Because subkeys are not ordered, any new subkey will have an arbitrary index. This means that the function may return subkeys in any order.

lpName

A pointer to a buffer that receives the name of the subkey, including the terminating null character. The function copies only the name of the subkey, not the full key hierarchy, to the buffer.

For more information, see Registry Element Size Limits.

lpcName

A pointer to a variable that specifies the size of the buffer specified by the lpName parameter, in TCHARs. This size should include the terminating null character. When the function returns, the variable pointed to by lpcName contains the number of characters stored in the buffer. The count returned does not include the terminating null character.

lpReserved

This parameter is reserved and must be NULL.

lpClass

A pointer to a buffer that receives the null-terminated class string of the enumerated subkey. This parameter can be NULL.

lpcClass

A pointer to a variable that specifies the size of the buffer specified by the lpClass parameter, in TCHARs. The size should include the terminating null character. When the function returns, lpcClass contains the number of characters stored in the buffer. The count returned does not include the terminating null character. This parameter can be NULL only if lpClass is NULL.

lpftLastWriteTime

A pointer to a variable that receives the time at which the enumerated subkey was last written. This parameter can be NULL.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is a system error code. If there are no more subkeys available, the function returns ERROR_NO_MORE_ITEMS.

If the lpName buffer is too small to receive the name of the key, the function returns ERROR_MORE_DATA.

Remarks

To enumerate subkeys, an application should initially call the RegEnumKeyEx function with the dwIndex parameter set to zero. The application should then increment the dwIndex parameter and call RegEnumKeyEx until there are no more subkeys (meaning the function returns ERROR_NO_MORE_ITEMS).

The application can also set dwIndex to the index of the last subkey on the first call to the function and decrement the index until the subkey with the index 0 is enumerated. To retrieve the index of the last subkey, use the RegQueryInfoKey function.

While an application is using the RegEnumKeyEx function, it should not make calls to any registration functions that might change the key being enumerated.

Note that operations that access certain registry keys are redirected. For more information, see Registry Virtualization and 32-bit and 64-bit Application Data in the Registry.

Example Code

For an example, see Enumerating Registry Subkeys.

Requirements

Client

Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, or Windows 95.

Server

Requires Windows Server 2008, Windows Server 2003, Windows 2000 Server, or Windows NT Server.

Header

Declared in Winreg.h; include Windows.h.

Library

Use Advapi32.lib.

DLL

Requires Advapi32.dll.

Unicode

Implemented as RegEnumKeyExW (Unicode) and RegEnumKeyExA (ANSI).


'저장소 > VC++' 카테고리의 다른 글

[Win32 API] RegQueryInfoKey  (0) 2010.12.16
[Win32 API] Registry Element Size Limits  (0) 2010.12.16
[Win32 API] File Version  (0) 2010.11.09
[Win32 API] System Information Functions  (0) 2010.07.16
[Win32 API] Verifying the System Version  (0) 2010.07.16

[Win32 API] File Version

저장소/VC++
DLL 또는 EXE의 File Version을 확인하는데는 3가지 API를 사용합니다.

1. DWORD GetFileVersionInfoSize(LPCTSTR lptstrFileName, LPDWORD lpdwHandle)
2. BOOL GetFileVersionInfo(LPCTSTR lptstrFileName, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
3. BOOL VerQueryValue(LPCVOID pBlock, LPCTSTR lpSubBlock, LPVOID* lplpBuffer, PUINT puLen)

그리고 VS_FIXEDFILEINFO 구조체가 필요하군요.

struct VS_FIXEDFILEINFO {
DWORD dwSignature,
DWORD dwStructVersion,
DWORD dwFileVersionMS,
DWORD dwFileVersionLS,
DWORD dwProductVersionMS,
DWORD dwProductVersionLS,
DWORD dwFileFlagMask,
DWORD dwFileFlags,
DWORD dwFileOS,
DWORD dwFileType,
DWORD dwFileSubType,
DWORD dwFileDateMS,
DWORD dwFileDateLS
};

MSDN을 살펴보면 참 복잡합니다. 몇년을 봐도 복잡하네요. 영어가 싫을 뿐입니다.

예제로 살펴봅니다.

#include <Windows.h>
#include <WinVer.h>

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

int _tmain(int argc, _TCHAR* argv[])
{
TCHAR* pszDestFilePath = _T("d:\\test.exe");

DWORD dwHandle = 0;
DWORD dwSize = 0;

dwSize = ::GetFileVersionInfoSize(pszDestFilePath, &dwHandle);
if(0 == dwSize)
return 1;

BYTE* pBlockData = new BYTE[dwSize];
ZeroMemory(pBlockData, dwSize);

if(FALSE == ::GetFileVersionInfo(pszDestFilePath, dwHandle, dwSize, pBlockData))
{
delete [] pBlockData;

return 1;
}

VS_FIXEDFILEINFO* pVerInfo = NULL;
UINT uLen = 0;

if(FALSE == ::VerQueryValue(pBlockData, _T("\\"), (LPVOID*)&pVerInfo, &uLen))
{
delete [] pBlockData;

return 1;
}

_tprintf_s(_T("Major Version : %d\n"), HIWORD(pVerInfo->dwFileVersionMS));
_tprintf_s(_T("Minor Version : %d\n"), LOWORD(pVerInfo->dwFileVersionMS));
_tprintf_s(_T("Release Version : %d\n"), HIWORD(pVerInfo->dwFileVersionLS));
_tprintf_s(_T("Test Version : %d\n"), LOWORD(pVerInfo->dwFileVersionLS));

delete [] pBlockData;

return 0;
}

아~ 잘 돌아가는군요. 이렇게 확인하면 되겠습니다.
더 붙이거나 뺄 것은 없는 것 같네요.
보다 자세한 사항은 MSDN을 보도록 합니다.

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] Registry Element Size Limits  (0) 2010.12.16
[Win32 API] RegEnumKeyEx  (0) 2010.12.16
[Win32 API] System Information Functions  (0) 2010.07.16
[Win32 API] Verifying the System Version  (0) 2010.07.16
[Win32 API] Windows OS Version  (0) 2010.07.16

[Win32 API] System Information Functions

저장소/VC++

Function Description
DnsHostnameToComputerName Converts a DNS name to a NetBIOS name.
EnumSystemFirmwareTables Enumerates all system firmware tables of the specified type.
ExpandEnvironmentStrings Replaces environment-variable strings with their defined values.
GetComputerName Retrieves the NetBIOS name of the local computer.
GetComputerNameEx Retrieves the NetBIOS or DNS name of the local computer.
GetComputerObjectName Retrieves the local computer's name in a specified format.
GetCurrentHwProfile Retrieves the current hardware profile for the local computer.
GetFirmwareEnvironmentVariable Retrieves the value of the specified firmware environment variable from NVRAM.
GetNativeSystemInfo Retrieves information about the current system for an application running under WOW64.
GetProductInfo Retrieves the product type for the operating system on the local computer, and maps the type to the product types supported by the specified operating system.
GetSystemDirectory Retrieves the path of the system directory.
GetSystemFirmwareTable Retrieves the specified firmware table from the firmware table provider.
GetSystemInfo Retrieves information about the current system.
GetSystemRegistryQuota Retrieves the current size of the registry and the maximum size that the registry is allowed to attain on the system.
GetSystemWindowsDirectory Retrieves the path of the shared Windows directory on a multi-user system.
GetSystemWow64Directory Retrieves the path of the system directory used by WOW64.
GetUserName Retrieves the user name of the current thread.
GetUserNameEx Retrieves the name of the user or other security principal associated with the calling thread. You can specify the format of the returned name.
GetVersion Retrieves the version number of the current operating system.
GetVersionEx Retrieves information about the current operating system.
GetWindowsDirectory Retrieves the path of the Windows directory.
IsProcessorFeaturePresent Determines whether a processor feature is supported by the current computer.
IsWow64Message Determines whether the last message read from the queue of the current process originated from a WOW64 process.
IsWow64Process Determines whether a process is running under WOW64.
SetComputerName Sets a new NetBIOS name for the local computer.
SetComputerNameEx Sets a new NetBIOS or DNS name for the local computer.
SetFirmwareEnvironmentVariable Sets the value of the specified firmware environment variable in NVRAM.
TranslateName Converts a directory service object name from one format to another.
VerifyVersionInfo Compares a set of version requirements to the values for the current operating system.
VerSetConditionMask Builds the condition mask for the VerifyVersionInfo function.
Wow64DisableWow64FsRedirection Disables file system redirection for the calling thread.
Wow64EnableWow64FsRedirection Enables or disables file system redirection for the calling thread.
Wow64RevertWow64FsRedirection Restores file system redirection for the calling thread.

'저장소 > VC++' 카테고리의 다른 글

[Win32 API] RegEnumKeyEx  (0) 2010.12.16
[Win32 API] File Version  (0) 2010.11.09
[Win32 API] Verifying the System Version  (0) 2010.07.16
[Win32 API] Windows OS Version  (0) 2010.07.16
[Win32 API] 64bit OS인지 확인하려면 IsWow64Process  (0) 2010.07.15

[Win32 API] Verifying the System Version

저장소/VC++

Windows의 Version 및 SP 버전을 확인하고자 할 때는 VerifyVersionInfo API를 이용하면 된다.

MSDN에서 발췌해온 아래 샘플을 참고하자.

[Example 1]

#include <windows.h>
#include <stdio.h>

BOOL Is_WinXP_SP2_or_Later ()
{
   OSVERSIONINFOEX osvi;
   DWORDLONG dwlConditionMask = 0;
   int op=VER_GREATER_EQUAL;

   // Initialize the OSVERSIONINFOEX structure.

   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
   osvi.dwMajorVersion = 5;
   osvi.dwMinorVersion = 1;
   osvi.wServicePackMajor = 2;
   osvi.wServicePackMinor = 0;

   // Initialize the condition mask.

   VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
   VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
   VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
   VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );

   // Perform the test.

   return VerifyVersionInfo(
      &osvi,
      VER_MAJORVERSION | VER_MINORVERSION |
      VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
      dwlConditionMask);
}

void main()
{
    if(Is_WinXP_SP2_or_Later())
        printf("The system meets the requirements.\n");
    else printf("The system does not meet the requirements.\n");
}


[Example 2]

#include <windows.h>
#include <stdio.h>

BOOL Is_Win_Server()
{
   OSVERSIONINFOEX osvi;
   DWORDLONG dwlConditionMask = 0;
   int op=VER_GREATER_EQUAL;

   // Initialize the OSVERSIONINFOEX structure.

   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
   osvi.dwMajorVersion = 5;
   osvi.dwMinorVersion = 0;
   osvi.wServicePackMajor = 0;
   osvi.wServicePackMinor = 0;
   osvi.wProductType = VER_NT_SERVER;

   // Initialize the condition mask.

   VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
   VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
   VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
   VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
   VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );

   // Perform the test.

   return VerifyVersionInfo(
      &osvi,
      VER_MAJORVERSION | VER_MINORVERSION |
      VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR |
      VER_PRODUCT_TYPE,
      dwlConditionMask);
}

void main()
{
    if(Is_Win_Server())
        printf("The system meets the requirements.\n");
    else printf("The system does not meet the requirements.\n");
}

[Win32 API] Windows OS Version

저장소/VC++

Operating system Version number
Windows 7 6.1
Windows Server 2008 R2 6.1
Windows Server 2008 6.0
Windows Vista 6.0
Windows Server 2003 R2 5.2
Windows Server 2003 5.2
Windows XP 64-Bit Edition 5.2
Windows XP 5.1
Windows 2000 5.0


MSDN에서 퍼온 샘플을 보면 이해가 빠를듯 하다.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

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

#define BUFSIZE 256

typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);

BOOL GetOSDisplayString( LPTSTR pszOS)
{
   OSVERSIONINFOEX osvi;
   SYSTEM_INFO si;
   PGNSI pGNSI;
   PGPI pGPI;
   BOOL bOsVersionInfoEx;
   DWORD dwType;

   ZeroMemory(&si, sizeof(SYSTEM_INFO));
   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));

   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

   if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
      return 1;

   // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.

   pGNSI = (PGNSI) GetProcAddress(
      GetModuleHandle(TEXT("kernel32.dll")),
      "GetNativeSystemInfo");
   if(NULL != pGNSI)
      pGNSI(&si);
   else GetSystemInfo(&si);

   if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
        osvi.dwMajorVersion > 4 )
   {
      StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));

      // Test for the specific product.

      if ( osvi.dwMajorVersion == 6 )
      {
         if( osvi.dwMinorVersion == 0 )
         {
            if( osvi.wProductType == VER_NT_WORKSTATION )
                StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
         }

         if ( osvi.dwMinorVersion == 1 )
         {
            if( osvi.wProductType == VER_NT_WORKSTATION )
                StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
            else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
         }
        
         pGPI = (PGPI) GetProcAddress(
            GetModuleHandle(TEXT("kernel32.dll")),
            "GetProductInfo");

         pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);

         switch( dwType )
         {
            case PRODUCT_ULTIMATE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
               break;
            case PRODUCT_PROFESSIONAL:
               StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
               break;
            case PRODUCT_HOME_PREMIUM:
               StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
               break;
            case PRODUCT_HOME_BASIC:
               StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
               break;
            case PRODUCT_ENTERPRISE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
               break;
            case PRODUCT_BUSINESS:
               StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
               break;
            case PRODUCT_STARTER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
               break;
            case PRODUCT_CLUSTER_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
               break;
            case PRODUCT_DATACENTER_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
               break;
            case PRODUCT_DATACENTER_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
               break;
            case PRODUCT_ENTERPRISE_SERVER_IA64:
               StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
               break;
            case PRODUCT_SMALLBUSINESS_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
               break;
            case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
               StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
               break;
            case PRODUCT_STANDARD_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
               break;
            case PRODUCT_STANDARD_SERVER_CORE:
               StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
               break;
            case PRODUCT_WEB_SERVER:
               StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
               break;
         }
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
      {
         if( GetSystemMetrics(SM_SERVERR2) )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
         else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
         else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
         else if( osvi.wProductType == VER_NT_WORKSTATION &&
                  si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
         {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
         }
         else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));

         // Test for the server type.
         if ( osvi.wProductType != VER_NT_WORKSTATION )
         {
            if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
            {
                if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
            }

            else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            {
                if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
                else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
            }

            else
            {
                if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
                else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
                else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
                   StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
                else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
            }
         }
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
      {
         StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
         if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
            StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
         else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
      }

      if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
      {
         StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));

         if ( osvi.wProductType == VER_NT_WORKSTATION )
         {
            StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
         }
         else
         {
            if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
               StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
            else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
               StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
            else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
         }
      }

       // Include service pack (if any) and build number.

      if( _tcslen(osvi.szCSDVersion) > 0 )
      {
          StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
          StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
      }

      TCHAR buf[80];

      StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
      StringCchCat(pszOS, BUFSIZE, buf);

      if ( osvi.dwMajorVersion >= 6 )
      {
         if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
            StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
         else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
            StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
      }
     
      return TRUE;
   }

   else
   { 
      printf( "This sample does not support this version of Windows.\n");
      return FALSE;
   }
}

int __cdecl _tmain()
{
    TCHAR szOS[BUFSIZE];

    if( GetOSDisplayString( szOS ) )
        _tprintf( TEXT("\n%s\n"), szOS );
}