Shell 和 Shlwapi DLL 版本

本部分介绍如何确定应用程序在哪个版本的 Shell DLL 上运行,以及如何针对特定版本将应用程序作为目标。

DLL 版本号

除了 Shell 文档中讨论的少数几个编程元素外,所有编程元素都包含在两个 DLL 中:Shell32.dll 和 Shlwapi.dll。 由于持续增强,这些 DLL 的不同版本可实现不同的功能。 在 Shell 参考文档中,每个编程元素都指定了受支持的 DLL 版本号。 除非另行指定,否则此版本号指示编程元素在该版本和 DLL 的后续版本中实现。 如果未指定版本号,则编程元素将在 DLL 的所有现有版本中实现。

在 Windows XP 之前,新Shell32.dll和Shlwapi.dll版本有时会随新版本的 Windows Internet Explorer 一起提供。 从 Windows XP 起,这些 DLL 不再作为新版本 Windows 本身之外的可再发行文件提供。 下表概述了不同的 DLL 版本,以及它们自 Microsoft Internet Explorer 3.0、Windows 95 和 Microsoft Windows NT 4.0 起的分发方式。

Shell32.dll版本 4.0 位于 Windows 95 和 Microsoft Windows NT 4.0 的原始版本中。 Shell 未使用 Internet Explorer 3.0 版本进行更新,因此Shell32.dll没有版本 4.70。 Shell32.dll版本 4.71 和 4.72 随相应的 Internet Explorer 版本一起提供,但它们不一定安装 (请参阅注释 1) 。 对于 Microsoft Internet Explorer 4.01 和 Windows 98 之后的版本,Shell32.dll和Shlwapi.dll的版本号不同。 通常,应假定 DLL 具有不同的版本号,并单独测试每个版本号。

Shell32.dll

版本 分发平台
4.0 Windows 95 和 Microsoft Windows NT 4.0
4.71 Microsoft Internet Explorer 4.0。 见第 1 条注释。
4.72 Internet Explorer 4.01 和 Windows 98。 见第 1 条注释。
5.0 Windows 2000 和 Windows Millennium Edition (Windows Me) 。 请参阅注释 2。
6.0 Windows XP
6.0.1 Windows Vista
6.1 Windows 7

Shlwapi.dll

版本 分发平台
4.0 Windows 95 和 Microsoft Windows NT 4.0
4.71 Internet Explorer 4.0。 见第 1 条注释。
4.72 Internet Explorer 4.01 和 Windows 98。 见第 1 条注释。
4.7 Internet Explorer 3.x
5.0 Microsoft Internet Explorer 5 和 Windows 98 SE。 请参阅注释 2。
5.5 Microsoft Internet Explorer 5.5 和 Windows Millennium Edition (Windows Me)
6.0 Windows XP 和 Windows Vista

注释 1: 使用 Internet Explorer 4.0 或 4.01 的所有系统分别具有Shlwapi.dll (4.71 或 4.72 的相关版本) 。 但是,对于 Windows 98 之前的系统,可以使用或不使用 集成 Shell 安装 Internet Explorer 4.0 和 4.01。 如果 Internet Explorer 随集成 Shell 一起安装,则还安装了关联的 Shell32.dll (4.71 或 4.72) 版本。 如果在未安装集成 Shell 的情况下安装 Internet Explorer,Shell32.dll仍为版本 4.0。 换句话说,系统上存在版本 4.71 或 4.72 的 Shlwapi.dll并不保证Shell32.dll具有相同的版本号。 所有 Windows 98 系统都具有 4.72 版Shell32.dll。

注释 2: Shlwapi.dll版本 5.0 随 Internet Explorer 5 一起分发,在安装了 Internet Explorer 5 的所有系统上找到,Windows 2000 除外。 Shell32.dll版本 5.0 与 Windows 2000 和 Windows Millennium Edition (Windows Me) 一起以本机方式分发,以及 5.0 版Shlwapi.dll。

使用 DllGetVersion 确定版本号

从版本 4.71 开始,Shell DLL 等开始导出 DllGetVersion。 应用程序可以调用此函数来确定系统上存在的 DLL 版本。

注意

DLL 不一定导出 DllGetVersion。 在尝试使用它之前,请始终对其进行测试。

对于早于 Windows 2000 的 Windows 版本, DllGetVersion 返回一个 DLLVERSIONINFO 结构,其中包含主版本号和次要版本号、内部版本号和平台 ID。 对于 Windows 2000 及更高版本的系统, DllGetVersion 可能会改为返回 DLLVERSIONINFO2 结构。 除了通过 DLLVERSIONINFO 提供的信息外, DLLVERSIONINFO2还提供用于标识最新安装的 Service Pack 的修补程序编号,从而提供了一种更可靠的方法来比较版本号。 由于 DLLVERSIONINFO2 的第一个成员是 DLLVERSIONINFO 结构,因此后面的结构向后兼容。

使用 DllGetVersion

以下示例函数 GetVersion 加载指定的 DLL 并尝试调用其 DllGetVersion 函数。 如果成功,它将使用宏将 DLLVERSIONINFO 结构中的主版本号和次要版本号打包到返回到调用应用程序的 DWORD 中。 如果 DLL 不导出 DllGetVersion,则函数返回零。 使用 Windows 2000 及更高版本的系统,可以修改 函数来处理 DllGetVersion 返回 DLLVERSIONINFO2 结构的可能性。 如果是这样,请使用该 DLLVERSIONINFO2 结构的 ullVersion 成员中的信息来比较版本、内部版本号和 Service Pack 版本。 MAKEDLLVERULL 宏简化了将这些值与 ullVersion 中的值进行比较的任务。

注意

错误地使用 LoadLibrary 可能会带来安全风险。 有关如何使用不同版本的 Windows 正确加载 DLL 的信息,请参阅 LoadLibrary 文档。

#include "stdafx.h"
#include "windows.h"
#include "windef.h"
#include "winbase.h"
#include "shlwapi.h"

#define PACKVERSION(major,minor) MAKELONG(minor,major)

DWORD GetVersion(LPCTSTR lpszDllName)
{
    HINSTANCE hinstDll;
    DWORD dwVersion = 0;

    /* For security purposes, LoadLibrary should be provided with a fully qualified 
       path to the DLL. The lpszDllName variable should be tested to ensure that it 
       is a fully qualified path before it is used. */
    hinstDll = LoadLibrary(lpszDllName);
    
    if(hinstDll)
    {
        DLLGETVERSIONPROC pDllGetVersion;
        pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");

        /* Because some DLLs might not implement this function, you must test for 
           it explicitly. Depending on the particular DLL, the lack of a DllGetVersion 
           function can be a useful indicator of the version. */

        if(pDllGetVersion)
        {
            DLLVERSIONINFO dvi;
            HRESULT hr;

            ZeroMemory(&dvi, sizeof(dvi));
            dvi.info1.cbSize = sizeof(dvi);

            hr = (*pDllGetVersion)(&dvi);

            if(SUCCEEDED(hr))
            {
               dwVersion = PACKVERSION(dvi.info1.dwMajorVersion, dvi.info1.dwMinorVersion);
            }
        }
        FreeLibrary(hinstDll);
    }
    return dwVersion;
}

下面的代码示例演示了如何使用 GetVersion 来测试 Shell32.dll 是版本 6.0 还是更高版本。

LPCTSTR lpszDllName = L"C:\\Windows\\System32\\Shell32.dll";
DWORD dwVer = GetVersion(lpszDllName);
DWORD dwTarget = PACKVERSION(6,0);

if(dwVer >= dwTarget)
{
    // This version of Shell32.dll is version 6.0 or later.
}
else
{
    // Proceed knowing that version 6.0 or later additions are not available.
    // Use an alternate approach for older the DLL version.
}

项目版本

为了确保应用程序与 .dll 文件的不同目标版本兼容,版本宏存在于头文件中。 这些宏用于为不同版本的 DLL 定义、排除或重新定义某些定义。 有关这些宏的深入说明,请参阅 使用 Windows 标头

例如,宏名称 _WIN32_IE 通常位于较旧的标头中。 你负责将宏定义为十六进制数。 此版本号定义使用 DLL 的应用程序的目标版本。 下表显示了可用的版本号以及每个版本号对应用程序的影响。

版本 说明
0x0200 该应用程序与 Shell32.dll 版本 4.00 及更高版本兼容。 应用程序无法实现在版本 4.00 之后添加的功能。
0x0300 该应用程序与 Shell32.dll 版本 4.70 及更高版本兼容。 应用程序无法实现在版本 4.70 之后添加的功能。
0x0400 该应用程序与 Shell32.dll 版本 4.71 及更高版本兼容。 应用程序无法实现在版本 4.71 之后添加的功能。
0x0401 该应用程序与 Shell32.dll 版本 4.72 及更高版本兼容。 应用程序无法实现在版本 4.72 之后添加的功能。
0x0500 该应用程序与 Shell32.dll 和 Shlwapi.dll 版本 5.0 及更高版本兼容。 应用程序无法实现在 Shell32.dll 和 Shlwapi.dll 版本 5.0 之后添加的功能。
0x0501 该应用程序与 Shell32.dll 和 Shlwapi.dll 版本 5.0 及更高版本兼容。 应用程序无法实现在 Shell32.dll 和 Shlwapi.dll 版本 5.0 之后添加的功能。
0x0600 该应用程序与 Shell32.dll 和 Shlwapi.dll 版本 6.0 及更高版本兼容。 应用程序无法实现在 Shell32.dll 和 Shlwapi.dll 版本 6.0 之后添加的功能。

如果未在项目中定义 _WIN32_IE 宏,则会自动将其定义为0x0500。 若要定义不同的值,可以将以下内容添加到 make 文件中的编译器指令;将所需的版本号替换为0x0400。

/D _WIN32_IE=0x0400

另一种方法是在包含 Shell 头文件之前,在源代码中添加类似于以下内容的行。 将所需的版本号替换为0x0400。

#define _WIN32_IE 0x0400
#include <commctrl.h>