检查操作系统的特性
有一些应用程序需要某些特殊的操作系统特性支持才能正常运行,所以对操作系统版本有特殊的要求。但是如上所述,检查操作系统的版本并不是一个确保操作系统拥有某项特性的最好方法。这是因为操作系统可能有新的特性添加进来,相比于使用GetVersionEx来检查操作系统平台或者是版本号,更有效的方法是直接检查某项特性本身是否存在。例如,微软打算将Windows 7的两个新特性Direct2D/DirectWrite和Ribbon API引入到Windows Vista中,这样,虽然Windows Vista的主版本号没有变化,但是却拥有了新的特性。当我们的应用程序在判断操作系统是否具有Ribbon特性而决定是否使用更加绚丽的用户界面时,如果仅仅根据版本号来做出判断,就错过了操作系统所提供的新特性了。
如果可以,在这些特性不可用的情况下,你的应用程序也应该能够继续运行,虽然减少了功能或者是降低了性能。
非托管代码检查操作系统特性
对于Win32应用程序,我们可以使用下面这些技术来检查操作系统特性:
• 如果一个库没有加载到你的应用程序,可以使用LoadLibrary()加载这个库。如果你对一个已加载的库(例如,kernel32.dll)中的新函数感兴趣,可以调用GetModuleHandle()获得这个模块的句柄。
• 使用GetProcAddress()获得函数的指针。如果GetProcAddress()返回NULL,则表示这个函数不存在,我们需要提供一些备选方案。将这个指针转化为合适类型的函数指针就可以使用操作系统的特性了。对于一些特殊的函数,虽然他们确实存在,但是可能会返回一个“尚未实现”的错误。针对这种情况,需要特殊处理。
在Windows 2000中,有一个函数SetWaitableTimer可以设置比较精确的计时器,下面的代码就演示了如何检查操作系统是否具有这项特性:
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";
// 获得已经加载模块的句柄
HMODULE hKernel32Module = GetModuleHandle(_T("kernel32.dll"));
if (hKernel32Module == NULL)
return FALSE;
// 获得函数地址
SetWaitableTimerExProc pFnSetWaitableTimerEx =
(SetWaitableTimerExProc) ::GetProcAddress(hKernel32Module,
"SetWaitableTimerEx");
// 检查函数是否存在
// 也就是判断某些特性是否存在
if (pFnSetWaitableTimerEx == NULL)
return FALSE;
// 调用函数
if (!pFnSetWaitableTimerEx(hTimer, &liDueTime, period, NULL, NULL,
&reasonContext, tolerance)
{ // 处理错误 }
这样,我们就可以直接检查操作系统是否具有某项特性,不会因为版本号而错过一些非常有用的操作系统特性了。