正确使用DllGetVersion

 

《关于NOTIFYICONDATA的一些新特性》中,我提到了使用

[cpp:nogutter] view plain copy print ?
  1. HRESULT CALLBACK DllGetVersion(DLLVERSIONINFO *pdvi);  

这一函数获取Shell32.dll的版本号,但这一函数不是API,而是Shell32.dll中的一个导出函数。我们需要使用LoadLibrary与GetProcAddress 来获取这个函数的指针,并调用它,才能实现版本的获取。 下面,简单介绍下如何实现这一过程。

首先,DllGetVersion并不是每一个版本的Shell32.dl的导出函数,若函数GetProcAddress在Shell32.dll中找不到此导出函数,返回值为0 ,这时,我们可以确定Shell32.dll为4.7.1之前的版本(4.7.1开始有此导出函数)。

其次,使用 LoadLibrary 加载dll时,错误的操作会有安全风险,我们必须确保dll路径有效并且正确。

再次,函数DllGetVersion的唯一参数是一个指向DLLVERSIONINFO结构的指针,该结构用于接收dll的版本信息(major and minor version numbers, the build number, and a platform ID),在调用之前,我们必须初始化该结构中的cbSize。下面给出的是该结构定义。

[cpp:nogutter] view plain copy print ?
  1. typedef struct _DllVersionInfo {  
  2.     DWORD cbSize;  
  3.     DWORD dwMajorVersion;  
  4.     DWORD dwMinorVersion;  
  5.     DWORD dwBuildNumber;  
  6.     DWORD dwPlatformID;  
  7. } DLLVERSIONINFO;  

另外,在Windows 2000及之后的版本,系统返回的可能是DLLVERSIONINFO2结构,为了保持兼容性,该结构的第一个成员是DLLVERSIONINFO结构。在返回DLLVERSIONINFO2结构时,可以使用宏MAKEDLLVERULL将 versions, build numbers, and service pack releases等信息与该结构中的成员 ullVersion 进行比较。下面给出的是该结构的定义。

[cpp:nogutter] view plain copy print ?
  1. typedef struct _DLLVERSIONINFO2 {  
  2.     DLLVERSIONINFO info1;  
  3.     DWORD dwFlags;  
  4.     ULONGLONG ullVersion;  
  5. } DLLVERSIONINFO2;  

最后,该函数的返回值为S_OK则表示成功获取。

 下面给出的是MSDN中的一个例子,用于获取指定路径dll的版本信息,版本信息中的major,minor信息组合成DWORD形式返回,若指定Dll不存在,返回0。

 

[cpp:nogutter] view plain copy print ?
  1. #include "stdafx.h"   
  2. #include "windows.h"   
  3. #include "windef.h"   
  4. #include "winbase.h"   
  5. #include "shlwapi.h"   
  6.   
  7. #define PACKVERSION(major,minor) MAKELONG(minor,major)   
  8.   
  9. DWORD GetVersion(LPCTSTR lpszDllName)  
  10. {  
  11.     HINSTANCE hinstDll;  
  12.     DWORD dwVersion = 0;  
  13.   
  14.     /* For security purposes, LoadLibrary should be provided with a fully-qualified  
  15.        path to the DLL. The lpszDllName variable should be tested to ensure that it  
  16.        is a fully qualified path before it is used. */  
  17.     hinstDll = LoadLibrary(lpszDllName);  
  18.       
  19.     if(hinstDll)  
  20.     {  
  21.         DLLGETVERSIONPROC pDllGetVersion;  
  22.         pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");  
  23.   
  24.         /* Because some DLLs might not implement this function, you must test for  
  25.            it explicitly. Depending on the particular DLL, the lack of a DllGetVersion  
  26.            function can be a useful indicator of the version. */  
  27.   
  28.         if(pDllGetVersion)  
  29.         {  
  30.             DLLVERSIONINFO dvi;  
  31.             HRESULT hr;  
  32.   
  33.             ZeroMemory(&dvi, sizeof(dvi));  
  34.             dvi.info1.cbSize = sizeof(dvi);  
  35.   
  36.             hr = (*pDllGetVersion)(&dvi);  
  37.   
  38.             if(SUCCEEDED(hr))  
  39.             {  
  40.                dwVersion = PACKVERSION(dvi.info1.dwMajorVersion, dvi.info1.dwMinorVersion);  
  41.             }  
  42.         }  
  43.         FreeLibrary(hinstDll);  
  44.     }  
  45.     return dwVersion;  
  46. }  

 

调用例子,判断Shell32.dll版本是否大于6.0

 

[cpp:nogutter] view plain copy print ?
  1. LPCTSTR lpszDllName = L"C://Windows//System32//Shell32.dll";  
  2. DWORD dwVer = GetVersion(lpszDllName);  
  3. DWORD dwTarget = PACKVERSION(6,0);  
  4.   
  5. if(dwVer >= dwTarget)  
  6. {  
  7.     // This version of Shell32.dll is version 6.0 or later.   
  8. }  
  9. else  
  10. {  
  11.     // Proceed knowing that version 6.0 or later additions are not available.   
  12.     // Use an alternate approach for older the DLL version.   
  13. }  

 该例子存在一些问题,函数GetVersion定义了dvi为DLLVERSIONINFO型变量,却引用了不存在的成员info1,应该去掉通过该成员的调用,或者直接定义为DLLVERSIONINFO2型的数据。

info1实际上为DLLVERSIONINFO2类型的成员,我们可以定义该结构变量,并初始化info1中的cbSize为DLLVERSIONINFO2大小,再传递dvi.info1至GetDllVersion,这个函数原意可能是想表明如何使用DLLVERSIONINFO2类型的结构,再使用ullVersion成员进行判断。

下面介绍使用DLLVERSIONINFO2结构进行版本判断,宏MAKEDLLVERULL参数为

[cpp:nogutter] view plain copy print ?
  1. ULONGLONG MAKEDLLVERULL(  
  2.     WORD wMajorVersion,  
  3.     WORD wMinorVersion,  
  4.     WORD wBuild,  
  5.     WORD wQFE  
  6. );  

调用如下:

[cpp:nogutter] view plain copy print ?
  1. DLLVERSIONINFO2 dvi2;     
  2. HRESULT hr;     
  3.     
  4. ZeroMemory(&dvi2, sizeof(dvi2));     
  5. dvi2.info1.cbSize = sizeof(dvi2);     
  6.     
  7. hr = (*pDllGetVersion)(&dvi2.info1);     
  8.   
  9. if(dvi2.ullVersion >= MAKEDLLVERULL(4, 71, 0,0))  
  10. {  
  11.     ...  
  12. }  

经测试,在WIN7 64bit与XP下ullVersion都可以接收到正确的版本号信息。

 

最后补充一点,关于Shell32.dll版本,在MSDN中给出6.0.6版本以上均为Vista及以上操作系统,而XP则是6.0版本的。

劝各位先查看下自己硬盘/windows/system32/shell32.dll的属性中版本信息,再选择具体的判断依据。

在我的电脑上,其中在XPSP3下的版本为6.0.2900.5512,WIN7 64bit下为6.1.7600.16644。

我不知道6.0.6与6.0.2900哪个版本高,但若是利用ullVersion直接判断,那么6.0.6 < 6.0.2900。

Vista正确的版本号是6.0.6000.xxxx,写程序时不要忽略了这点。

 

具体的信息,可以参看英文原版MSDN,链接:

http://msdn.microsoft.com/en-us/library/bb776779(v=vs.85).aspx

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值