본문 바로가기

Windows/Windows API

camel CPU info

// Camel - CPU Identifying Tool
// Copyright (C) 2002, Iain Chesworth
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "common.h"

// Included class header files.
#include "cpu_info.h"

// ----------------------------------------------------------------------------
//
//        Win32 Code:
//         This is code to run the Windows(tm) version of Camel.
//
// ----------------------------------------------------------------------------

#ifdef _WIN32

// Global variables.
HINSTANCE g_hInstance;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // Save the instance handle.
    g_hInstance = hInstance;

    // Initialise the common controls.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof (INITCOMMONCONTROLSEX);
    InitCtrls.dwICC = ICC_TREEVIEW_CLASSES;
    InitCommonControlsEx (&InitCtrls);

    // Create the dialog.
    DialogBox (hInstance, MAKEINTRESOURCE (IDD_CPUDIALOG), NULL, (DLGPROC) CPUDialog_DialogProc);

    return 0;
}

BOOL CALLBACK CPUDialog_DialogProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    HWND hWndOwner;
    PAINTSTRUCT ps;
    static CPUInfo * CPU;
    RECT rc, rcOwner, rcDlg;
    HICON hBigIcon, hSmallIcon;
    
    switch (uMsg) {
        case WM_INITDIALOG:
            if ((hWndOwner = GetParent (hDlg)) == NULL) {
                hWndOwner = GetDesktopWindow ();
            }

            GetWindowRect (hWndOwner, &rcOwner);
            GetWindowRect (hDlg, &rcDlg);
            CopyRect (&rc, &rcOwner);

            // Offset the owner and dialog box rectangles so that
            // right and bottom values represent the width and
            // height, and then offset the owner again to discard
            // space taken up by the dialog box.
    
            OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top);
            OffsetRect (&rc, -rc.left, -rc.top);
            OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom);
    
            // The new position is the sum of half the remaining
            // space and the owner's original position.

            SetWindowPos (hDlg, HWND_TOP, rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2), 0, 0, SWP_NOSIZE);

            // Set the CPU information inside the dialog. NB: This is for the 1st processor in a system only!
            CPU = new CPUInfo ();
            
            // Check to see if the CPU is supported.
            if (CPU->DoesCPUSupportCPUID ()) {
                SendDlgItemMessage (hDlg, IDC_VENDORID, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetVendorID ());
                SendDlgItemMessage (hDlg, IDC_TYPEID, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetTypeID ());
                SendDlgItemMessage (hDlg, IDC_FAMILYID, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetFamilyID ());
                SendDlgItemMessage (hDlg, IDC_MODELID, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetModelID ());
                SendDlgItemMessage (hDlg, IDC_STEPPING, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetSteppingCode ());
                SendDlgItemMessage (hDlg, IDC_BRANDID, WM_SETTEXT, (WPARAM) 0, (LPARAM) CPU->GetExtendedProcessorName ());
                SendDlgItemMessage (hDlg, IDC_PLATFORM, WM_SETTEXT, (WPARAM) 0, (LPARAM) OSDetection ());
            } else {
                SendDlgItemMessage (hDlg, IDC_BRANDID, WM_SETTEXT, (WPARAM) 0, (LPARAM) BAD_CPUID);
                SendDlgItemMessage (hDlg, IDC_PLATFORM, WM_SETTEXT, (WPARAM) 0, (LPARAM) OSDetection ());
            }

            TVINSERTSTRUCT tvi;
            TVITEM tvitem;
            char szText[128];

            // Configure the root of the items...
            tvitem.mask = TVIF_TEXT; tvitem.cchTextMax = 128; tvitem.pszText = szText;
            tvi.hParent = TVI_ROOT; tvi.hInsertAfter = TVI_SORT; tvi.item = tvitem;            

            // First put the processor it into the root of the tree.
            sprintf (szText, TREE_LOADING);
            TreeView_InsertItem (GetDlgItem (hDlg, IDC_FEATURETREE), &tvi);
            
            // Create the threads to interrogate the processors.
            CreateCPUInterrogationThreads (hDlg);

            // Load the new icons for the window.
            hBigIcon = (HICON) LoadImage (g_hInstance, MAKEINTRESOURCE (IDI_APPICON32), IMAGE_ICON, 32, 32, LR_COLOR);
            if (hBigIcon != NULL) SendMessage (hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hBigIcon);
            hSmallIcon = (HICON) LoadImage (g_hInstance, MAKEINTRESOURCE (IDI_APPICON16), IMAGE_ICON, 16, 16, LR_COLOR);
            if (hSmallIcon != NULL) SendMessage (hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hSmallIcon);

            // Display the dialog box.
            ShowWindow (hDlg, SW_SHOW);
            return true;
            
        case WM_PAINT:
            hDC = BeginPaint (hDlg, &ps);
            EndPaint (hDlg, &ps);
            break;

        case WM_COMMAND:
            switch (LOWORD (wParam)) {
                case IDOK:
                    EndDialog (hDlg, 0);
                    break;
                case IDC_ABOUT:
                    CreateDialog (g_hInstance, MAKEINTRESOURCE (IDD_ABOUTDIALOG), hDlg, (DLGPROC) AboutDialog_DialogProc);
                    break;
            }
            break;

        case WM_CLOSE:
            EndDialog (hDlg, -1);
            break;

        case WM_DESTROY:
            delete CPU;
            break;
    }

    return false;
}

BOOL CALLBACK AboutDialog_DialogProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    HWND hWndOwner;
    PAINTSTRUCT ps;
    RECT rc, rcOwner, rcDlg;
    HICON hBigIcon, hSmallIcon;
    
    switch (uMsg) {
        case WM_INITDIALOG:
            if ((hWndOwner = GetParent (hDlg)) == NULL) {
                hWndOwner = GetDesktopWindow ();
            }

            GetWindowRect (hWndOwner, &rcOwner);
            GetWindowRect (hDlg, &rcDlg);
            CopyRect (&rc, &rcOwner);

            // Offset the owner and dialog box rectangles so that
            // right and bottom values represent the width and
            // height, and then offset the owner again to discard
            // space taken up by the dialog box.
    
            OffsetRect (&rcDlg, -rcDlg.left, -rcDlg.top);
            OffsetRect (&rc, -rc.left, -rc.top);
            OffsetRect (&rc, -rcDlg.right, -rcDlg.bottom);
    
            // The new position is the sum of half the remaining
            // space and the owner's original position.

            SetWindowPos (hDlg, HWND_TOP, rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2), 0, 0, SWP_NOSIZE);

            // Load the new icons for the window.
            hBigIcon = (HICON) LoadImage (g_hInstance, MAKEINTRESOURCE (IDI_APPICON32), IMAGE_ICON, 32, 32, LR_COLOR);
            if (hBigIcon != NULL) SendMessage (hDlg, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hBigIcon);
            hSmallIcon = (HICON) LoadImage (g_hInstance, MAKEINTRESOURCE (IDI_APPICON16), IMAGE_ICON, 16, 16, LR_COLOR);
            if (hSmallIcon != NULL) SendMessage (hDlg, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hSmallIcon);

            // Display the dialog box.
            ShowWindow (hDlg, SW_SHOW);
            return true;
            
        case WM_PAINT:
            hDC = BeginPaint (hDlg, &ps);
            EndPaint (hDlg, &ps);
            break;

        case WM_COMMAND:
            switch (LOWORD (wParam)) {
                case IDOK:
                    EndDialog (hDlg, 0);
                    break;
            }
            break;

        case WM_CLOSE:
            EndDialog (hDlg, -1);
            break;

        case WM_DESTROY:
            break;
    }

    return false;
}

bool CreateCPUInterrogationThreads (HWND hDlg)
{
    // Define the local variables.
    HANDLE * hThread;
    DWORD * dwThreadID;
    SYSTEM_INFO SysInfo;
    PTHREADINFO * ThreadInfo;
    int nProcessors = 0;

    // Get the number of processors in the system.
    ZeroMemory (&SysInfo, sizeof (SYSTEM_INFO));
    GetSystemInfo (&SysInfo);
    
    // Number of physical processors in a non-Intel system
    // or in a 32-bit Intel system with Hyper-Threading technology disabled
    nProcessors = SysInfo.dwNumberOfProcessors;

    // For each processor; spawn a CPU thread to access details.
    hThread = new HANDLE [nProcessors];
    dwThreadID = new DWORD [nProcessors];
    ThreadInfo = new PTHREADINFO [nProcessors];

    // Check to see if the memory allocation happenned.
    if ((hThread == NULL) || (dwThreadID == NULL) || (ThreadInfo == NULL)) {
        char * szMessage = new char [128];
        sprintf (szMessage, "Cannot allocate memory for threads and CPU information structures!");
        MessageBox (hDlg, szMessage, APP_TITLE, MB_OK | MB_ICONSTOP);
        delete szMessage;
        return false;
    }

    for (int nCounter = 0; nCounter < nProcessors; nCounter ++) {
        
        ThreadInfo[nCounter] = new THREADINFO;
        ThreadInfo[nCounter]->hDlg = hDlg;
        ThreadInfo[nCounter]->nProcessor = nCounter + 1;

        hThread[nCounter] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) DisplayCPUInformation, (LPVOID) ThreadInfo[nCounter], CREATE_SUSPENDED, &dwThreadID[nCounter]);
        if (hThread[nCounter] == NULL) {
            char * szMessage = new char [128];
            sprintf (szMessage, "Cannot create processor interrogation thread for processor %d!", nCounter + 1);
            MessageBox (hDlg, szMessage, APP_TITLE, MB_OK | MB_ICONSTOP);
            delete szMessage;
        }
        
        // Set the threads affinity to the correct processor.
        if (SetThreadAffinityMask (hThread[nCounter], nCounter + 1) == 0) {
            char * szMessage = new char [128];
            sprintf (szMessage, "Cannot set processor affinity for processor %d thread!", nCounter + 1);
            MessageBox (hDlg, szMessage, APP_TITLE, MB_OK | MB_ICONSTOP);
            delete szMessage;
        }

        ResumeThread (hThread[nCounter]);
    }

    // Clean up memory allocations.
    delete [] ThreadInfo;
    delete [] dwThreadID;
    delete [] hThread;

    // Return success;
    return true;
}


DWORD WINAPI DisplayCPUInformation (LPVOID lpParameter)
{
    PTHREADINFO ThreadInfo = (PTHREADINFO) lpParameter;
    CPUInfo * CPU = new CPUInfo ();
    HTREEITEM hRootNode;
    HTREEITEM hParent;
    TVINSERTSTRUCT tvi;
    TVITEM tvitem;
    char szText[128];
    HWND hTreeCtrl;

    // Configure the root of the items...
    tvitem.mask = TVIF_TEXT;
    tvitem.cchTextMax = 128;
    tvitem.pszText = szText;

    tvi.hParent = TVI_ROOT;
    tvi.hInsertAfter = TVI_SORT;
    tvi.item = tvitem;

    // Get the handle to the tree control.
    hTreeCtrl = GetDlgItem (ThreadInfo->hDlg, IDC_FEATURETREE);

    // First remove the "Loading... Please Wait!".
    tvitem.hItem = TreeView_GetRoot (hTreeCtrl);
    TreeView_GetItem (hTreeCtrl, &tvitem);
    if (strcmp (tvitem.pszText, TREE_LOADING) == 0) TreeView_DeleteItem (hTreeCtrl, tvitem.hItem);

    // First put the processor it into the root of the tree.
    sprintf (szText, "Processor %d", ThreadInfo->nProcessor);

    // Create the new root node.
    hRootNode = TreeView_InsertItem (hTreeCtrl, &tvi);

    // Configure the root of the items...
    tvitem.mask = TVIF_TEXT;
    tvitem.cchTextMax = 128;
    tvitem.pszText = szText;

    tvi.hParent = hRootNode;
    tvi.hInsertAfter = TVI_LAST;
            
    if (!CPU->DoesCPUSupportCPUID ()) {
        // Inform the user that we cannot get any information.
        sprintf (szText, BAD_CPUID);
        TreeView_InsertItem (hTreeCtrl, &tvi);
        
        // Cleanup memory allocations.
        delete CPU;
        
        // Terminate the thread.
        return 0;
    }
    
    // Add the processor name - either extended or classical.
    sprintf (szText, "Processor Name: %s", CPU->GetExtendedProcessorName ());
    TreeView_InsertItem (hTreeCtrl, &tvi);

    // Add the processor clock frequency.
    sprintf (szText, "Clock Frequency: %d MHz", CPU->GetProcessorClockFrequency ());
    TreeView_InsertItem (hTreeCtrl, &tvi);
    
    // Display the processor serial number.
    if (CPU->DoesCPUSupportFeature (SERIALNUMBER_FEATURE)) {
        sprintf (szText, "Serial Number: %s", CPU->GetProcessorSerialNumber ());
        TreeView_InsertItem (hTreeCtrl, &tvi);
    }

    // Expand the root node.
    TreeView_Expand (hTreeCtrl, hRootNode, TVE_EXPAND);

    // Configure the tree control to not write to the root.
    tvi.hParent = hRootNode;
    tvi.hInsertAfter = TVI_LAST;
        
    // Add the hardware specification node.
    sprintf (szText, "On-Chip Hardware Features");
    hParent = TreeView_InsertItem (hTreeCtrl, &tvi);
    
    // Configure the treeview control.
    tvitem.mask = TVIF_TEXT;
    tvitem.cchTextMax = 128;
    tvitem.pszText = szText;
    
    tvi.hParent = hParent;
    tvi.hInsertAfter = TVI_LAST;

    // State the APIC ID if one is present.
    if (CPU->DoesCPUSupportFeature (APIC_FEATURE)) {
        HTREEITEM hTempParent;

        // Display that the processor has an AGP Peripheral Component Interconnect [APIC].
        sprintf (szText, "APIC Present");
        hTempParent = TreeView_InsertItem (hTreeCtrl, &tvi);

        tvi.hParent = hTempParent;
        tvi.hInsertAfter = TVI_LAST;

        // Attempt to display the ID of the APIC.
        sprintf (szText, "APIC ID: %d", CPU->GetProcessorAPICID ());
        TreeView_InsertItem (hTreeCtrl, &tvi);

        tvi.hParent = hParent;
        tvi.hInsertAfter = TVI_LAST;
    }

    // State if the processor supports the Advanced Configuration and Power Interface [ACPI].
    if (CPU->DoesCPUSupportFeature (ACPI_FEATURE)) {
        sprintf (szText, "ACPI Capable");
        TreeView_InsertItem (hTreeCtrl, &tvi);
    }
            
    // State if the processor supports a thermal monitor.
    if (CPU->DoesCPUSupportFeature (THERMALMONITOR_FEATURE)) {
        sprintf (szText, "On-Chip Thermal Monitor");
        TreeView_InsertItem (hTreeCtrl, &tvi);
    }

    // Check to see if L1\L2\L3 cache exists.
    if (!CPU->DoesCPUSupportFeature (L1CACHE_FEATURE | L2CACHE_FEATURE | L3CACHE_FEATURE)) {
        // Inform the user that on-chip cache is not supported.    
        sprintf (szText, "No L1\\L2\\L3 Cache Found");
        TreeView_InsertItem (hTreeCtrl, &tvi);
    } else {
        // State the size of the L1 cache if present.
        if (CPU->DoesCPUSupportFeature (L1CACHE_FEATURE)) {
            sprintf (szText, "L1 Cache: %dKB", CPU->GetProcessorCacheXSize (L1CACHE_FEATURE));
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State the size of the L2 cache if present.
        if (CPU->DoesCPUSupportFeature (L2CACHE_FEATURE)) {
            sprintf (szText, "L2 Cache: %dKB", CPU->GetProcessorCacheXSize (L2CACHE_FEATURE));
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State the size of the L3 cache if present.
        if (CPU->DoesCPUSupportFeature (L3CACHE_FEATURE)) {
            sprintf (szText, "L3 Cache: %dKB", CPU->GetProcessorCacheXSize (L3CACHE_FEATURE));
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }
    }

    // Configure the tree control to not write to the root.
    tvi.hParent = hRootNode;
    tvi.hInsertAfter = TVI_LAST;
        
    // Add the hardware specification node.
    sprintf (szText, "Power Management Features");
    hParent = TreeView_InsertItem (hTreeCtrl, &tvi);
    
    // Configure the treeview control.
    tvitem.mask = TVIF_TEXT;
    tvitem.cchTextMax = 128;
    tvitem.pszText = szText;
    
    tvi.hParent = hParent;
    tvi.hInsertAfter = TVI_LAST;
    
    // Check to see if power management is supported...
    if (!CPU->DoesCPUSupportFeature (TEMPSENSEDIODE_FEATURE | FREQUENCYID_FEATURE | VOLTAGEID_FREQUENCY)) {
        // Inform the user that power management is not supported.        
        sprintf (szText, "No On-Chip Support");
        TreeView_InsertItem (hTreeCtrl, &tvi);
    } else {
        // State if a temperature sensing diode is present.
        if (CPU->DoesCPUSupportFeature (TEMPSENSEDIODE_FEATURE)) {
            sprintf (szText, "Temperature Sensing Diode");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if a frequency ID control is present.
        if (CPU->DoesCPUSupportFeature (FREQUENCYID_FEATURE)) {
            sprintf (szText, "Frequency ID (FID) Control");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if a voltage ID control is present.
        if (CPU->DoesCPUSupportFeature (VOLTAGEID_FREQUENCY)) {
            sprintf (szText, "Voltage ID (VID) Control");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }
    }
    
    // Configure the tree control to not write to the root.
    tvi.hParent = hRootNode;
    tvi.hInsertAfter = TVI_LAST;
        
    // Add the features node.
    sprintf (szText, "Supported Features");
    hParent = TreeView_InsertItem (hTreeCtrl, &tvi);
    
    // Configure the treeview control for images.
    tvitem.mask = TVIF_TEXT;
    tvitem.cchTextMax = 128;
    tvitem.pszText = szText;
    
    tvi.hParent = hParent;
    tvi.hInsertAfter = TVI_LAST;
            
    if (!CPU->DoesCPUSupportFeature (CMOV_FEATURE | MTRR_FEATURE | MMX_FEATURE | MMX_PLUS_FEATURE | SSE_FEATURE |
                                     SSE_FP_FEATURE | SSE_MMX_FEATURE | SSE2_FEATURE | AMD_3DNOW_FEATURE |
                                     AMD_3DNOW_PLUS_FEATURE | HYPERTHREAD_FEATURE | MP_CAPABLE | IA64_FEATURE)) {
        // Inform the user that no features were found.    
        sprintf (szText, "No Supported Features Found");
        TreeView_InsertItem (hTreeCtrl, &tvi);
    } else {
        // State if CMOV instructions are present.
        if (CPU->DoesCPUSupportFeature (CMOV_FEATURE)) {
            sprintf (szText, "CMOV Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if MTRR instructions are present.
        if (CPU->DoesCPUSupportFeature (MTRR_FEATURE)) {
            sprintf (szText, "MTRR Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if MMX instructions are present.
        if (CPU->DoesCPUSupportFeature (MMX_FEATURE)) {
            sprintf (szText, "MMX Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if MMX+ instructions are present.
        if (CPU->DoesCPUSupportFeature (MMX_PLUS_FEATURE)) {
            sprintf (szText, "MMX+ Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if SSE instructions are present.
        if (CPU->DoesCPUSupportFeature (SSE_FEATURE)) {
            sprintf (szText, "SSE Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if SSE FP instructions are present.
        if (CPU->DoesCPUSupportFeature (SSE_FP_FEATURE)) {
            sprintf (szText, "SSE FP Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if SSE MMX instructions are present.
        if (CPU->DoesCPUSupportFeature (SSE_MMX_FEATURE)) {
            sprintf (szText, "SSE MMX Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }
        
        // State if SSE2 instructions are present.
        if (CPU->DoesCPUSupportFeature (SSE2_FEATURE)) {
            sprintf (szText, "SSE2 Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if 3DNow! instructions are present.
        if (CPU->DoesCPUSupportFeature (AMD_3DNOW_FEATURE)) {
            sprintf (szText, "3DNow! Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if 3DNow!+ instructions are present.
        if (CPU->DoesCPUSupportFeature (AMD_3DNOW_PLUS_FEATURE)) {
            sprintf (szText, "3DNow!+ Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if Hyperthreading instructions are present.
        if (CPU->DoesCPUSupportFeature (HYPERTHREAD_FEATURE)) {
            sprintf (szText, "Hyperthreading Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
            sprintf (szText, "Logical Processors Per Physical: %d", CPU->GetLogicalProcessorsPerPhysical ());
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if the processor is MP capable.
        if (CPU->DoesCPUSupportFeature (MP_CAPABLE)) {
            sprintf (szText, "Multi-processor Capable");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }

        // State if IA64 instructions are present.
        if (CPU->DoesCPUSupportFeature (IA64_FEATURE)) {
            sprintf (szText, "IA64 Instructions");
            TreeView_InsertItem (hTreeCtrl, &tvi);
        }
    }

    // Remove the CPUInfo object as we no longer need it.
    delete CPU;

    return 0;
}

char * OSDetection ()
{
    OSVERSIONINFOEX osvi;
    BOOL bIsWindows64Bit;
    BOOL bOsVersionInfoEx;
    char * szOperatingSystem = new char [256];

    // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
    // If that fails, try using the OSVERSIONINFO structure.
    ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);

    if (!(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi))) {
        // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
        osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
        if (!GetVersionEx ((OSVERSIONINFO *) &osvi)) return NULL;
    }

    switch (osvi.dwPlatformId) {
        case VER_PLATFORM_WIN32_NT:
            // Test for the product.
            if (osvi.dwMajorVersion <= 4) strcpy (szOperatingSystem, "Microsoft?Windows?NT ");
            if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) strcpy (szOperatingSystem, "Microsoft?Windows?2000 ");
            if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) strcpy (szOperatingSystem, "Microsoft?Windows?XP ");

            // Test for product type.
            if (bOsVersionInfoEx) {
                if (osvi.wProductType == VER_NT_WORKSTATION) {
                    if (osvi.wSuiteMask & VER_SUITE_PERSONAL) strcat (szOperatingSystem, "Personal ");
                    else strcat (szOperatingSystem, "Professional ");
                } else if (osvi.wProductType == VER_NT_SERVER) {
                    // Check for .NET Server instead of Windows XP.
                    if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) strcpy (szOperatingSystem, "Microsoft?Windows?.NET ");
                    
                    // Continue with the type detection.
                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER) strcat (szOperatingSystem, "DataCenter Server ");
                    else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) strcat (szOperatingSystem, "Advanced Server ");
                    else strcat (szOperatingSystem, "Server ");
                }
            } else {
                HKEY hKey;
                char szProductType[80];
                DWORD dwBufLen;

                // Query the registry to retrieve information.
                RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);
                RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);
                RegCloseKey (hKey);
                if (lstrcmpi ("WINNT", szProductType) == 0) strcat (szOperatingSystem, "Professional ");
                if (lstrcmpi ("LANMANNT", szProductType) == 0)
                    // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
                    if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
                         strcat (szOperatingSystem, "Standard Server ");
                    else strcat (szOperatingSystem, "Server ");
                if (lstrcmpi ("SERVERNT", szProductType) == 0)
                    // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
                    if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
                         strcat (szOperatingSystem, "Enterprise Server ");
                    else strcat (szOperatingSystem, "Advanced Server ");
            }

            // Display version, service pack (if any), and build number.
            if (osvi.dwMajorVersion <= 4) {
                // NB: NT 4.0 and earlier.
                sprintf (szOperatingSystem, "%sversion %d.%d %s (Build %d)",
                                            szOperatingSystem,
                                            osvi.dwMajorVersion,
                                            osvi.dwMinorVersion,
                                            osvi.szCSDVersion,
                                            osvi.dwBuildNumber & 0xFFFF);
            } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
                // Windows XP and .NET server.
                typedef BOOL (CALLBACK* LPFNPROC) (HANDLE, BOOL *);
                HINSTANCE hKernelDLL;
                LPFNPROC DLLProc;
                
                // Load the Kernel32 DLL.
                hKernelDLL = LoadLibrary ("kernel32");
                if (hKernelDLL != NULL) {
                    // Only XP and .NET Server support IsWOW64Process so... Load dynamically!
                    DLLProc = (LPFNPROC) GetProcAddress (hKernelDLL, "IsWow64Process");
                
                    // If the function address is valid, call the function.
                    if (DLLProc != NULL) (DLLProc) (GetCurrentProcess (), &bIsWindows64Bit);
                    else bIsWindows64Bit = false;
                
                    // Free the DLL module.
                    FreeLibrary (hKernelDLL);
                }

                // IsWow64Process ();
                if (bIsWindows64Bit) strcat (szOperatingSystem, "64-Bit ");
                else strcat (szOperatingSystem, "32-Bit ");
            } else {
                // Windows 2000 and everything else.
                sprintf (szOperatingSystem, "%s%s(Build %d)", szOperatingSystem, osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
            }
            break;

        case VER_PLATFORM_WIN32_WINDOWS:
            // Test for the product.
            if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
                strcpy (szOperatingSystem, "Microsoft?Windows?95 ");
                if (osvi.szCSDVersion[1] == 'C') strcat (szOperatingSystem, "OSR 2.5 ");
                else if (osvi.szCSDVersion[1] == 'B') strcat (szOperatingSystem, "OSR 2 ");
            }

            if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
                strcpy (szOperatingSystem, "Microsoft?Windows?98 ");
                if (osvi.szCSDVersion[1] == 'A' ) strcat (szOperatingSystem, "SE ");
            }

            if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
                strcpy (szOperatingSystem, "Microsoft?Windows?Me ");
            }
            break;

        case VER_PLATFORM_WIN32s:
            strcpy (szOperatingSystem, "Microsoft?Win32s ");
            break;

        default:
            strcpy (szOperatingSystem, "Unknown Windows ");
            break;
    }

    return szOperatingSystem;
}

#endif // _WIN32

'Windows > Windows API' 카테고리의 다른 글

disk free space (wince)  (0) 2013.10.01
local ip address (wince)  (0) 2013.10.01
CenterWindow  (0) 2013.10.01
DrawTransparentBitmap  (0) 2013.10.01
system tray  (0) 2013.10.01