Windows 版 (精华区)

发信人: bali (阿奔), 信区: Windows
标  题: Microsoft Windows 2000 应用程序兼容性(1)
发信站: 紫 丁 香 (Fri May  5 23:32:00 2000), 转信

     Microsoft Windows 2000 应用程序兼容性
(选自:CLanguage区,作者:headstream (超级大宝),时间:2000年04月19日)
几个月来,我一直从事一项任务,即找出 Windows 2000 操作系统中的应用程序
兼容性问题。在这里我真正要讨论的是,造成应用程序与 Windows 2000 不兼容
的原因。没有人真正关心使应用程序兼容的原因。
我一直在与 Windows 2000 测试组合作,他们在过去的几个月中已测试了数百个
应用程序。我们已将应用程序在 Windows 2000 上正常或不正常运行的原因进行
书面论述。我们发现的问题可以归为四类:
无法在 Windows 2000 上安装的应用程序。 这是迄今我们发现的最大问题。应用
程序在 Windows 2000 上安装的方式并无甚特殊之处;问题是这些应用程序不让
自己安装到这一新版本的操作系统中。
我们对操作系统所做的、影响应用程序运行的更改。每当 Microsoft Windows N
T(R) 开发组面临选择,是使系统作为平台更稳定或更强大,还是保障应用程序的
兼容性,他们总是牺牲后者而取稳定性。Windows 2000 开发工作的一个主要目标
就是让系统作为平台更加稳定。遗憾的是,为了实现这一点而必须进行的某些改
动,已导致应用程序在 Windows 2000 上不兼容。
我们已对操作系统进行的更改不会影响应用程序的兼容性,但会中断某些应用程
序。
过于依赖 Windows 9x 平台的应用程序。我们在开发 Windows 2000 时,考虑到
有众多 Windows 9x 用户需要升级,因此对 Windows 9x 应用程序进行了测试,
将它们移植到 Windows 2000 中。我们发现某些应用程序过于依赖 Windows 9x。

设置和安装问题
我们要讨论的第一类问题是设置和安装问题;最常见的问题无疑是无法在 Windo
ws 2000 上安装应用程序。实际上,导致无法安装应用程序的一个最普遍的原因
,在于 Windows 2000 是 Windows NT 的 5.0 版。
测试组以多种方式测试应用程序。他们将应用程序安装在基于 Windows 2000 的
系统中,或者将应用程序安装在 Windows NT 4.0 或 Windows 95 中,然后再将
系统升级到 Windows 2000,以便进行测试。
我们拿来一台未安装任何操作系统的机器后,安装上 Windows 2000,再安装应用
程序,与上述升级的情况相比,前者的兼容性数目要少得多。
版本检查
造成应用程序无法安装在 Windows 2000 上的第一位原因,是它们无法正确处理
版本号。我们发现很多应用程序都进行以下示例代码所做的操作。它们在运行过
程中会调用 GetVersionEX,然后写下一条“if”语句,该语句规定:“如果系统
是版本 3,因为没有新的 Shell,我不能正常运行,所以我可能无法安装。如果
系统是版本 4,我可以进行安装和设置”。问题出在如果系统是版本 5,这一“
if”语句就没有了下文。因为版本号是 5.0,这些应用程序由于自身原因而无法
安装,所以我们发现了一系列这样那样的问题。
if (osvi.dwMajorVersion == 3)
   {
   // 请这样做
   }
else if (osvi.dwMajorVersion == 4)
   {
   // 请那样做
   }
测试组继续寻找解决方案,并蒙蔽了许多此类应用程序。在早期的编译中,我们
能够采取措施改变 GetVersionEx 的返回值。我们可以改变其返回值,欺骗应用
程序,告诉它版本号就是 4.0,然后程序就能够继续安装,并正常运行。但有部
分应用程序的设计思想就是不能安装在 Windows 2000 上。对于病毒扫描程序或
其他低级实用程序来说,受限于某一操作系统版本是可以理解的。不过,这些应
用程序会显示消息来说明这一点。我们查找的是那些不能安装或无法正常运行、
又根本没有通知用户的应用程序。
怎样才能正确地检查版本号?在 Windows 2000 中我们将添加一个新的 API: V
erifyVersionInfo,这一 API 在运行时将依次检查主版本号、次版本号以及服务
包。如果出现了操作系统的新版本,应用程序仍然能够在其上安装并运行。实际
上应用 VerifyVersionInfo 的选项和方式还有很多,但如果只是检查“要是操作
系统升级了,应用程序该如何处理”这一类问题,您只需调用这三个标志,然后
检查主版本号、次版本号以及服务包。您能够定义以下语句:“我的程序需要运
行在 Windows NT 4.0、SP2 上”,然后询问 VerifyVersionInfo“我正在运行的
操作系统是否已达到这一标准?”,该 API 将返回真值或假值。
VerifyVersionInfo(&osvi,
      VER_MAJORVERSION |
      VER_MINORVERSION |
      VER_SERVICEPACKMAJOR,
      dwlConditionMask);
采用这一方式检查版本,就可以符合 Windows 2000 应用程序的规范,其基本思
想是“只要存在新版本的操作系统,就要在新版本上进行安装。”
应用 VerifyVersionInfo 的一个问题是目前该 API 只能在 Windows 2000 平台
上运行。为了检查 Windows 95 等旧平台的版本,您必须应用GetVersionEx。查
看以下示例代码,即可发现它的功能与 VerifyVersionInfo 基本相同:依次检查
主版本号、次版本号以及服务包。
BOOL bIsWindowsVersionOK(DWORD dwMajor, DWORD dwMinor, DWORD dwSPMajor
 )
   {
   OSVERSIONINFO osvi;
   // 初始化 OSVERSIONINFO 结构
   //
   ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
   GetVersionEx((OSVERSIONINFO*)&osvi);
   // 首先,主版本
   if ( osvi.dwMajorVersion > dwMajor )
      return TRUE;
   else if ( osvi.dwMajorVersion == dwMajor )
      {
      // 然后,次版本
      if (osvi.dwMinorVersion > dwMinor )
         return TRUE;
      else if (osvi.dwMinorVersion == dwMinor )
         {
         // 对,最好检查一下 Service Pack
         if ( dwSPMajor && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT
)
            {
            HKEY   hKey;
            DWORD   dwCSDVersion;
             DWORD   dwSize;
            BOOL   fMeetsSPRequirement = FALSE;

            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                         "System\\CurrentControlSet\\Control\\Windows"
, 0,
                         KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
               {
               dwSize = sizeof(dwCSDVersion);
               if (RegQueryValueEx(hKey, "CSDVersion",
                        NULL, NULL, (unsigned char*)&dwCSDVersion,
                        &dwSize) == ERROR_SUCCESS)
                  {
                  fMeetsSPRequirement = (LOWORD(dwCSDVersion) >= dwSPM
ajor);
                  }
                RegCloseKey(hKey);
                }
            return fMeetsSPRequirement;
            }
         return TRUE;
         }
      }

   return FALSE;
   }
//
// 此示例适用于 Windows 2000 和更新版本
//
BOOL bIsWindowsVersionOK(DWORD dwMajor, DWORD dwMinor, DWORD dwSPMajor
 )
    {
    OSVERSIONINFOEX osvi;
   ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
   osvi.dwMajorVersion = dwMajor;
   osvi.dwMinorVersion = dwMinor;
   osvi.wServicePackMajor = dwSPMajor;
   // 设置条件掩码。
   VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_
EQUAL );
   VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_
EQUAL );
   VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREA
TER_EQUAL );
   // 执行测试。
   return VerifyVersionInfo(&osvi,
                             VER_MAJORVERSION | VER_MINORVERSION
                             | VER_SERVICEPACKMAJOR,dwlConditionMask);
     }
首先,需要检查主版本号。如果当前操作系统的主版本号高于所需主版本号,则
不需要进行任何检查,直接向下运行即可。如果主版本号相等,则以同样方式检
查次版本号。最后再检查服务包号。在我们获得发布的某一版本时,就可以说“
没关系,我们不在乎是 Service Pack 3、4 还是 5”。如果主版本号或次版本号
有所增长,系统同样可以处理。我们查找了所有要检查版本信息的应用程序,发
现它们将分别检查每一组件。它们在运行中会说“噢,主版本号是 5,我只要求
 4,不错。次版本号是 .0,很好,但 Service Pack 是 0,我需要的是 3”。很
明显,Windows 2000 还没有推出 SP3,所以这种检查版本信息的方法是错误的。
检查 Windows NT 的版本号时需要注意以下细节:检查版本号和服务包信息的方
法有三种。第一种是获取 GetVersionEx 的返回值,然后检查“szCSDVersion”
字符串。实际的服务包号嵌入在该字符串的某一位置。分析这一串字符实在是比
较繁琐,而且您必须始终牢记它是否进行了本地化,这是很难做到的。这不是一
种最好的方式。如果系统运行的是 Windows NT 4.0,您只需检查以下注册键值,
其中有一个数字是服务包号。提取这一数字,并进行一个“等于”或“大于”比
较即可:
HCLM\System\CurrentControlSet\Control\Windows\CSDVersion
如果您运行的是 Windows 2000 或更高版本,则仍可以使用 GetVersionEx,但需
要将其传递到 OSVERSIONINFOEX 结构,而不是正在使用的OSVERSIONINFO 结构。
考虑到起始处操作员成员的大小,Windows 2000 会将其视为一个较大的结构,并
且给出一个新的字段(服务包、主版本、次版本),作为进行比较时所用的整数
。如果您还是使用 VerifyVersionInfo,您会发现这是最方便的一种方式。
DLL 版本检查
在检查 Windows 版本的同时,我们还发现了另一个与版本相关的问题,即用户不
检查 DLL 的版本。无论 DLL 是系统目录中的 Microsoft DLL,还是您自己的 D
LL,在将其复制到系统前,都必须进行版本检查。检查的目的是防止将旧版的 D
LL 复制到新版的上面。
必须确认在用户自己的 DLL 中已添加了版本信息,以便进行检查。进行这一操作
非常重要,它能够避免出现各种麻烦。不要试图更改系统目录中的 DLL,甚至不
要考虑对系统 DLL 进行升级或降级,或覆盖同一 DLL。系统 DLL 是由 Windows
 2000 在 CD 或服务包中提交的、位于系统目录中的 DLL。
如果您打算编制新的 Windows 2000 应用程序,则需要使用 Windows Installer
,它能够为您检查 DLL 的版本。只要说明需要将某一特定的 DLL 置于特定的目
录中,即可发现 Windows Installer 在为您进行版本检查工作。您不需要再处理
这一小块代码。
DLL Hell
如果没有正确地检查 DLL 版本,结果毋庸质疑会发生 DLL Hell。我肯定不需要
向您解释什么是 DLL Hell,您一定在这上面花费了不少时间。因为我最初曾参与
开发 ctl3d.dll,对这些东西就象熟悉我的邻居一样。
我们花费了几年的时间,努力去突破那些影响 DLL 正常工作的障碍,我们最终认
定应用程序开发商无法保持后向兼容性。每个人都在朝这方面努力,这一目标很
伟大,但却无法实现。实际上,DLL 不可能保持后向兼容性。结果就是:某一应
用程序如果要正常结束,必须取决于某一 DLL 的某个特定版本,而另一应用程序
则取决于该 DLL 的另一版本,因为这两个应用程序在这一共享组件(即共享 DL
L)方面发生了冲突,导致无法共存于同一系统中。
到目前为止,我们仍然认为对于 Windows 应用程序来说,DLL 共享功能是一个非
常良好和重要的组成部分。我们同样认为 DLL 能为您提供的功能还是非常有价值
的。问题是如果不能测试 DLL 的版本,而跨应用程序对 DLL 进行全局共享会带
来非常多的问题。
并行 DLL
在 Windows 2000 中,我们开始实施某些称之为并行 DLL 的内容。我们希望您开
发的应用程序也开始向并行版本策略靠拢。在 Windows 2000 中,我们采取了一
些预防性措施,以减少 DLL Hell。我们要考虑的第一位的事情是无论安装了何种
应用程序,都要保证系统处于受保护状态,保持其完整性。随后我们将讨论 Win
dows 文件保护。
我们要做的另一件事情是实现组件的并行,同时希望应用程序供应商也这样做。
我们针对的是微软的组件;至于您自己的组件,我们也建议您这样做。我们将采
用并行版本功能,而对于您自己目前正在进行全局共享的组件,我们也希望您能
采用并行版本功能。 
--



  在时间面前,没有永恒
      
         ------一个热爱自由的人

※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: 202.108.67.114]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.360毫秒