程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 7開發:版本檢查 - 白皮書

Windows 7開發:版本檢查 - 白皮書

編輯:關於.NET

介紹

用戶和開發人員面對的大多數普通應用程序的兼容性問題,就是應用程序檢 測操作系統版本後運行失敗。當版本檢測出現錯誤的時候,很多應用程序都會出錯。用戶可 能會有“靜默失敗”的體驗,也就是一個應用程序加載失敗並且什麼都沒有發生 。又或者用戶可能會看到一個帶有標示的對話框,寫明了“你必須運行在 Microsoft Windows XP或更新版本”,但實際上計算機已經安裝了Windows 7 。很多由於不嚴謹的 版本檢測導致的結果,能夠給用戶帶來很多的不便。

由於版本檢測造成的應用程序運行失敗,通常是兩個原因:

• 在檢測版本的 代碼中的缺陷(錯誤)。比如次版本號降低,主版本提高(例如,版本號從5.1變為6.0)或 者一些期望的service pack (SP)沒有安裝,又或者你已經安裝了更新的額操作系統(比如, 版本從Windows XP SP 2 變為 Windows Vista SP 1),都可能造成應用程序運行失敗。

• 故意的阻斷,應用程序的開發人員會阻止應用程序運行在沒有經過測試的操作系 統版本上(我們的建議是,不要阻止應用程序運行在未來的操作系統中)。

當一個應 用程序以“不兼容“(由於不嚴謹的版本檢測)的Windows版本運行,那麼它通常 會提示一個錯誤信息,但是它也有可能靜默退出或者有其他的行為。通常,如果我們使用版 本檢測的解決方案,那麼應用程序將能夠很好的運行。最終用戶和IT專業人員就能使用一個 簡單的修復,來讓應用程序知道它現在正運行在一個早期的Windows版本上。

下面的章節提供了一些關於如何解決版本檢測的兼容性問題的信息,同時也提供了如何檢 測操作系統版本的信息。我們同時也給出最好最全面的建議:不用檢測操作系統的版本,而 只需要檢測操作系統的功能。

解決問題

Windows給我們提供了兩種結構來解決 版本檢測的問題:

• 兼容性模式:它是專門為最終用戶設計的,兼容模式是解 決兼容性問題的簡單方法。當它被啟用的時候,將修復一些列的兼容性問題,並且為早期 Windows版本所開發的應用程序提供一個更加兼容的運行時環境。這些修復的問題中的其中一 個就是“版本欺騙“,它將使函數返回一個用戶在屬性對話框中的兼容性標簽中 選中的操作系統版本,而不是計算機的實際Windows版本。

• 應用程序兼容性工 具 (ACT):為IT專業人員和開發人員提供的應用程序兼容性工具的集合,ACT提供了檢測和調 試大量兼容性問題的方法,開發人員可以用來修復應用程序,同時,ACT還提供了通過從列表 中使用兼容性選項來解決兼容性問題的方法,包括“版本欺騙“。ACT提供了一套 能夠解決細節問題的工具。

兼容模式

要啟用兼容模式:

1.右鍵點擊可 執行文件或者可執行文件的快捷方式。

2.點擊屬性。

3.點擊兼容性標簽。

4.選中以兼容模式運行這個應用程序:並且選擇你希望應用程序運行的操作系統。一 些應用程序可能包含多個可執行文件。你可能需要為每一個文件都執行這樣的操作。

5.點擊OK來關閉該對話框。

6.運行應用程序。

注意 : 兼容模式一般不會對通過Environment.OSVersion函數,或者通過P/Invoke調用 Win32函數(例如,GetVersionEx)的檢測版本的托管代碼應用程序產生影響。但是,如果應 用程序混合了托管代碼和本地代碼,那麼這個方法仍然是有幫助的。如果這個應用程序檢測 版本是通過本地調用來實現的,那麼這個方法將被使用。

應用程序兼容性工具

在安裝了ACT之後,在開始菜單中運行兼容性管理員:

1.查看左邊的樹形菜單。如果這裡沒有“自定義數據庫“節點,那麼點擊工具欄中的New 。

2.右鍵點擊 New Database

3.點擊 Rename ,並且給兼容性數據庫起一個名稱。

4.右鍵點擊你剛才重命名的數據庫,指向Create New,然後點擊Application Fix。 Create new Application Fix對話框將彈出:

5.填充一些細節信息。

6.點擊 Next.

7.在Operating System Modes中,選擇None。

8.在 Select additional compatibility modes:中,選擇 WinXPSP2VersionLie.

9.點擊 Next.

10.如果你的應用程序需要其他的東西,那麼也在這裡進行選擇。

11.點擊 Next。

12.選擇Windows需要為可執行程序定義的條件。

13.點擊 Finish.

14.點擊工具欄中的Save來將兼容性數據庫保存到一個文件中(以.sdb為擴展名的文件) 。你可以使用Windows SDBinst工具將這個文件安裝到目標計算機上。

15.Windows可以為很多程序都使用這種包含多種修改的兼容性數據庫;你可以通過展開 System Database/Applications節點來查看這些。點擊子節點就可以看到其對應用程序所做 的修改。

解決方案

更好的版本檢測

通過識別當前的操作系統版本來決定這個操作系統所擁有的功能,並不是一個最佳的方法 。但是,如果你不能將你的應用程序設計成能夠檢測指定的功能,那麼唯一的確定兼容性的 方式,就是通過版本檢測,那麼,請參考下面的方法。

對於本地應用程序,你可能需要確保你的應用程序邏輯能夠在更新的Windows版本上運行 。當版本變更的時候請不要阻止應用程序運行!下面就是一個使用了GetVersionEx 的Win32 代碼示例。如果主版本號大於5(Windows Vista, Windows Server 2008 R2 和 Windows 7) ,那麼檢測就能夠通過。如果等於5,那麼次版本號應該是1或者更大(Windows XP 或者 Windows Server 2003)。

C++

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

                 void main()
                 {
                     OSVERSIONINFO osvi;
                     BOOL bIsWindowsXPorLater;

                     ZeroMemory(&osvi, sizeof (OSVERSIONINFO));
                     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

                     GetVersionEx(&osvi);

                     bIsWindowsXPorLater = 
                  ( (osvi.dwMajorVersion > 5) ||
                        ( (osvi.dwMajorVersion == 5)  && (osvi.dwMinorVersion >= 1) ));

                     if(bIsWindowsXPorLater)
                   printf("The system meets the  requirements.\n");
                     else printf("The system does not  meet the requirements.\n");
                 }

下面的代碼示例是使用了VerifyVersionInfo來檢測操作系統的版本是否滿足最低需求 (Windows XP SP2):

C++

#include <windows.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);
                 }

對於.NET Framework開發人員,使用==, !=, <=, <, >, >=操作符來對 Environment.OSVersion.Version返回的Version對象進行操作:

C#

//  This code checks if the OS is at least Windows XP
      if  (Environment.OSVersion.Version < new Version(5, 1))
       {
            MessageBox.Show("Windows XP or later  required.",
                                                  "Incompatible Operating System",  MessageBoxButtons.OK,
                                                                                  MessageBoxIcon.Error);
             return;
      }

檢測功能

之前提到的,檢測操作系統的 版本來確定操作系統所能提供的功能,不是一個最佳的方法。這是因為操作系統可能會在可 再發行DLL中增加新的功能。與其使用 GetVersionEx來決定操作系統的平台或者版本號,不 如檢測操作系統本身所提供的功能更為有效。例如,我們准備使用Direct2D 和 DirectWrite 這些API和在Windows Vista中所提供的Ribbon的API,那麼在使用這些API時不需要阻斷你的 應用程序。

如果可能,你的應用程序應該在沒有這些功能的依然能夠正常運行,只不 過是減少一些功能或者性能。

對於Win32,使用下面的技術:

• 使用 LoadLibrary()來加載一個還沒有加載進你的應用程序的庫。如果你對已經加載的DLL文件( 比如,kernel32.dll)中的新功能感興趣,那麼可以調用GetModuleHandle()來獲取模塊的句 柄。如果這些函數都返回空值,那麼這將引起一個錯誤。

• 使用GetProcAddress()來獲取一個函數指針。如果GetProcAddress()返回一個空 值,那麼這個函數可能將會退出。我們需要將函數的指針設置成適當的原型。有一些函數, 盡管他們退出了,但也有可能實際返回一個“未完成“的錯誤。同樣我們也需要 檢查這些錯誤。

下面的代碼示例就展示了這個技術:

C++

//  define function pointer type
                typedef  BOOL (WINAPI *SetWaitableTimerExProc)(
                   __in  HANDLE hTimer,
                  __in  const  LARGE_INTEGER *lpDueTime,
                  __in   LONG lPeriod,
                  __in  PTIMERAPCROUTINE  pfnCompletionRoutine,
                  __in  LPVOID  lpArgToCompletionRoutine,
                  __in   PREASON_CONTEXT WakeContext,
                  __in   ULONG TolerableDelay
                );

                 LARGE_INTEGER liDueTime;
                 liDueTime.QuadPart = 0;
                nt period  = 1000;
                unsigned int tolerance =  1000;
                HANDLE hTimer = // Get timer  handle

                REASON_CONTEXT reasonContext  = {0};
                reasonContext.Version = 0;
                 reasonContext.Flags =  POWER_REQUEST_CONTEXT_SIMPLE_STRING;
                 reasonContext.Reason.SimpleReasonString = L"MyTimer";

                 // Get module handle to a module which is already  loaded
                HMODULE hKernel32Module =  GetModuleHandle(_T("kernel32.dll"));
                if  (hKernel32Module == NULL)
                                 return FALSE;

                // Get  Address of function
                 SetWaitableTimerExProc pFnSetWaitableTimerEx =
                 (SetWaitableTimerExProc) ::GetProcAddress(hKernel32Module,
                                 "SetWaitableTimerEx");

                // Check if  the function exists
                if  (pFnSetWaitableTimerEx == NULL)
                                 return FALSE;

                 // Call function
                if (! pFnSetWaitableTimerEx(hTimer, &liDueTime, period, NULL, NULL,
                                                  &reasonContext, tolerance)
                {  // handle error }

二者擇其一,你可以選擇使用DLL延遲加載,並且在 __try...__異常阻斷中調用函數(了解更多信息,查看Linker Support for Delay-Loaded DLLs)。

對於COM API,我們可以操作通過CoCreateInstance 和 QueryInterface 所 返回的錯誤。

通過P/Invoke調用Win32 API的.NET 框架應用程序,我們需要去管理 EntryPointNotFoundException 和 DllNotFoundException兩個異常。

工具列表

Microsoft應用程序兼容性工具

附加資源

• 應用程序兼容性手冊 :  http://msdn.microsoft.com/en-us/library/bb963893.aspx

• 版本欺騙和 托管應用程序:http://blogs.msdn.com/cjacks/archive/2007/09/10/version-lie-shims- and-managed-code-on-windows-vista.aspx

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved