2004/2/16 by Jack
 
由於Win32 SDK與作業系統核心版本緊密的的關係,導致Win32 API在各個不同版本間,或多或少都可能有些微差異,程式設計師再使用函式時,必須注意說明文件的註解,就以Timer來說,即使是同樣的函式在不同的核心版本中所使用的解析度並不相同,當然也不乏更嚴重的狀況,甚至可能出現應用程式在Win 98 版本可以正常執行而Win NT卻會產生錯誤,反之亦然。

        如果應用程式所使用的API函式已經確定有版本上的問題,解決之道有二個;其一是依據平台版本各自編譯,其二是在應用程式中加入判斷使用者作業系統版本的機制,然後根據實際的版本執行相對應的程式碼。

        就程式設計師的考量而言,使用第一種方式,系統必須為功能完全相同的應用程式,產生二種不同的版本,這會直接增加軟體維護的負擔,而第二種辦法,則將版本問題透過程式自行判斷以選擇正確的程式碼執行,但是必須額外撰寫判斷版本的程式碼,如果純以系統的角度來看,第二種方式的軟體維護負擔較輕,整體系統結構看起來也比較優雅。

使用第二種做法的關鍵是,如何取得使用者的作業系統版本?

        在Win32 平台上,要取得作業系統相關的資料有二種方式,第一種是透過系統登錄檔中所儲存的機碼,第二種則是透過GetVersionEX()來取得。

在這裡我們要介紹的是透過GetVersionEX()取得並判斷作業系統的版本。

首先來看看GetVersionEX()函式的原型:
BOOL GetVersionEx(
     LPOSVERSIONINFO lpVersionInformation
   );
要取得作業系統版本,就必須先準備LPOSVERSIONINFO型態的資料結構,以下是資料結構的定義:
typedef struct _OSVERSIONINFO{  
    DWORD dwOSVersionInfoSize; 
    DWORD dwMajorVersion; 
    DWORD dwMinorVersion; 
    DWORD dwBuildNumber; 
    DWORD dwPlatformId; 
    TCHAR szCSDVersion[ 128 ]; 
} OSVERSIONINFO;
以下是OSVERSIONINFO資料結構各個成員所代表的意義:

dwOSVersionInfoSize
OSVERSIONINFO資料結構的大小,可以利用sizeof(OSVERSIONINFO)取得

dwMajorVersion
作業系統的主要版本編號,其值分別代表以下作業系統版本

作業系統版本 dwMajorVersion
Windows    95 4
Windows    98 4
Windows    Me 4
Windows    NT 3.51 3
Windows    NT 4.0 4
Windows    2000 5
Windows    XP 5
Windows Server  2003 family 5
dwMinorVersion
作業系統次版本編號

作業系統次版本 dwMinorVersion
Windows    95 0
Windows    98 10
Windows    Me 90
Windows    NT 3.51 51
Windows    NT 4.0 0
Windows    2000 0
Windows    XP 1
Windows Server  2003 family 2
dwBuildNumber
建立序號
[Windows Me/98/95:低字組內含建立序號,高字組為主要及次要版本編號]

dwPlatformId
作業平台識別代號

作業平台版本 dwPlatformId
VER_PLATFORM_WIN32s Win32s on Windows 3.1.
VER_PLATFORM_WIN32_WINDOWS Windows?95, Windows?98, or Windows?Me.
VER_PLATFORM_WIN32_NT Windows?NT, Windows?2000, Windows XP, or Windows Server?2003 family.
szCSDVersion
附加資訊字串,如Service Pack 3

了解這些成員所代表意義,接下來就能在程式中利用判斷的語法,偵測使用者的作業系統版本。

//-------------------start resource.h---------------
#include 
#include "resource.h"


ID_ICON_1	ICON  "icon1.ico"
ID_ICON_2	ICON  "icon2.ico"



//-----------------end---------------------

//-------------------start resource.rc---------------
#include 
#include "resource.h"


ID_ICON_1	ICON  "icon1.ico"
ID_ICON_2	ICON  "icon2.ico"



//-----------------end---------------------
編譯視窗資源的指令為:
windres -o resource.o -i resource.rc

//-------------------start c_getversion.cpp--------------- #include #include #include "resource.h" const char* szAppName = "MyWndClass"; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int nTopXY(UINT, UINT); int get_SystemVer(void); char szVersion [80]; //程式進入點 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg; int wnd_W; int wnd_H; wnd_W=400; wnd_H=300; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON_1)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(ID_MENU); wc.lpszClassName = szAppName; wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON_2)); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "視窗類別登記失敗!", "發生錯誤!", MB_ICONEXCLAMATION | MB_OK); return 0; } hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, szAppName, "顯示作業系統版本", WS_OVERLAPPEDWINDOW, nTopXY(wnd_W, GetSystemMetrics(SM_CXSCREEN)), nTopXY(wnd_H, GetSystemMetrics(SM_CYSCREEN)), wnd_W,wnd_H, NULL, NULL, hInstance, NULL); if(hwnd == NULL) { MessageBox(NULL, "視窗建立失敗!", "發生錯誤!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; } LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hMyDC; PAINTSTRUCT ps; char szText[] = "顯示作業系統版本!!"; switch(msg) { case WM_CREATE: get_SystemVer(); break; case WM_PAINT: hMyDC=BeginPaint(hwnd, &ps); TextOut(hMyDC,100,100,szText,lstrlen(szText)); TextOut(hMyDC,100,120,szVersion,lstrlen(szVersion)); EndPaint(hwnd, &ps); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } } int nTopXY(UINT wnd_XY, UINT wnd_Dim) { int resl; resl=((wnd_Dim/2)-(wnd_XY/2)); return resl; } int get_SystemVer(void){ OSVERSIONINFO osvi; memset(&osvi, 0, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&osvi); switch(osvi.dwPlatformId){ case VER_PLATFORM_WIN32s: wsprintf (szVersion, "Microsoft Win32s %d.%d (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); break; case VER_PLATFORM_WIN32_WINDOWS: if (osvi.dwMinorVersion==0){ wsprintf (szVersion, "Microsoft Windows 95 %d.%d (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); } else if (osvi.dwMinorVersion==10){ wsprintf (szVersion, "Microsoft Windows 98 %d.%d (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); } else if (osvi.dwMinorVersion==90){ wsprintf (szVersion, "Microsoft Windows Me %d.%d (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); } break; case VER_PLATFORM_WIN32_NT: if (osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0){ wsprintf (szVersion, "Windows 2000 With %s",osvi.szCSDVersion); } else if (osvi.dwMajorVersion==5 && osvi.dwMinorVersion==1){ wsprintf (szVersion, "Windows XP %s",osvi.szCSDVersion); } else if (osvi.dwMajorVersion<=4){ wsprintf (szVersion, "Windows NT %d.%d with %s", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion); } break; } return 0; } //-----------------end---------------------
編譯指令為:
g++ -o c_getversion.exe resource.o c_getversion.cpp -mwindows
arrow
arrow
    全站熱搜

    marco 發表在 痞客邦 留言(0) 人氣()