翻译|其它|编辑:郝浩|2004-02-04 11:41:00.000|阅读 2013 次
概述:
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
David D'Souza、BJ Whalen 以及 Peter Wilson
Microsoft Corporation
1999 年 11 月
摘要:探讨 Microsoft(R) Windows(R) 2000 和 Windows 98 第二版本中并行共享组件的实现(如 Windows 认证规范中讨论的)。包括新的并行组件的创建以及使用 DLL/COM 重定向处理相同组件的不同版本之间的不兼容性。包括编写和安装并行组件以及重新打包和测试应用程序的指南。
介绍
一点背景知识
新组件共享策略
比较两种策略
创建新的并行组件
并行组件编写指南
安装并行组件
DLL/COM
重定向
使用 DLL/COM 重定向
现代操作系统和应用程序由许多组件构成。组件是自包含的软件实体,该软件实体提供了一组可被各种应用程序广泛使用的函数。因为单独的组件被多个应用程序使用,所以组件的共享是很有必要的。
成功的全局组件共享要求任何共享的组件功能和该组件的先前版本完全一样。但是如果不能实现的话,要达到百分之百的向后兼容实际上是很难的,因为测试所有使用共享组件的配置是非常困难的。新旧应用程序最终都使用相同的组件,因此,随着时间的推移,修正并改进这些组件变得愈加困难。
同时,组件的实际功能也不太容易定义。应用程序可能成为依附在组件上的意外副作用,而不被认为是该组件核心功能一部分。例如,组件中的一个错误可能影响到应用程序,以及当组件开发者选择修正此错误时应用程序失败,这种情况就是人们常说的“DLL Hell(该死的 DLL)”。这使得那些使用组件的应用程序会更加深该问题的严重性。
这种缺乏向后兼容性的情况使得在部署新的应用程序时,必须中断已部署的应用程序,或是牺牲某些新应用程序的功能。所有新的应用程序都要求共享组件的版本与已配置的版本不同。要在增强应用程序稳定性的同时提供成功的共享,Microsoft 已在 Windows 2000 和 Windows 98 第二版本中引入了并行共享,开创了通过选择性隔离来共享组件的新方式。
在了解并行共享的详细信息之前,让我们看一些背景资料以及“DLL Hell”的问题。
Windows 最初就采纳了共享的概念。所有操作系统都在提供稳定性、完整的服务集的需求与操作系统所要求的硬件的资源限制的之间寻求平衡。到目前为止, CPU 用量和磁盘空间仍然是 PC 平台中非常紧张的资源。很显然,要将操作系统和应用程序代码装入到一个很小空间,必须尽可能地共享代码。与许多其他好处相比,代码共享加强了硬件资源的均衡运用,并且最大程度地减少在前期质量保证检测中暴露的问题。代码共享是使 Windows 成功的要素之一。
Windows 的共享并不限于代码。应用程序和组件的状态,可以用注册表状态的形式、文件系统中的应用程序专用数据存储的形式和公开全局命名空间的 Windows API 的形式,在整个操作系统中找到。这类共享,在多个软件供应商生产的应用程序之间提供了高级别的互操作性,降低了成本,提高了软件的效率。
但是,共享也必须付出一些代价。共享意味着应用程序彼此依赖,引入了脆弱性因素。更改某一组件会对其他组件产生无法预料的影响。典型的情况,一个应用程序可能依赖于共享组件的一个特定版本。而另一个应用程序可能是用该共享组件的升级(或降级)版本安装的,因此第一个应用程序可能受此更改的影响。在极端的情况下,曾经工作正常的应用程序会突然功能紊乱,甚至失败。这种情况通常称为“DLL Hell”。
在系统中,共享的反面是隔离。通过将所有资源和代码静态地绑定到应用程序,可以隔离应用程序。但是如今对于依赖于 COM 或其他全局存储的系统资源的应用程序来说,完全的隔离是不可行的。
减少应用程序脆弱性的一种解决办法是,有选择地隔离应用程序和组件。在这种方案中,所有应用程序可能都具有对相同组件的访问权,但该组件目前有多个版本可用。组件开发者有权编制旧组件的新版本、作一些改进或修正错误。而客户可以选择适合于特定应用程序的版本。就像走进一个汽车配件商店为您的 1984 Chevy 挑选一个燃油泵一样。您会发现货架上的这个泵和一些比它晚来的适用于其他车型的泵并行放在一起。在使用组件的情况下,关键是提供适合于每个应用程序的版本并且隔离其他不同的版本。而且,在重定向的情况下,应用程序可以进行配置,以使用适合于该特定应用程序的组件版本,而不管最近开发的或以后将要开发那些版本。
为鼓励这类隔离,Microsoft Windows 2000 和 Windows 98 第二版本的新的组件共享形式叫做并行共享,它使用选择性隔离最大程度地减少 DLL Hell。并行共享允许相同组件(COM 或 Win32)的多个版本同时在不同的进程中运行。因此,应用程序可以使用设计并测试过的组件的特定版本,而不管另一个应用程序要求该相同组件的不同版本。这种安排允许开发者建立并部署更可靠的应用程序,因为开发者能指定他们的应用程序使用的组件版本,和系统中其他应用程序无关。
Windows 2000 和 Windows 98 第二版本中的并行共享遵照以下两种策略:
并行组件,不论是最近创建的还是现有的、或重新配置的应用程序的一部分,并不是所有的方案都支持。
注意 DLL/COM 重定向致力于解决部署现有应用程序和组件时的应用程序冲突。在开发新的应用程序或组件时,最佳策略是部署被天然隔离的并行组件。
下表比较两种方法,DLL/COM 重定向和创建并行 (SxS) 组件,并指导如何为您的方案选择正确的方法。
表 1. 并行策略比较
属性 | SxS 组件 | DLL/COM 重定向 |
主要焦点是什么? | 建立稳定的新组件,使它在以后版本中将免受造成组件“向后不兼容”的更改的影响。 | 将现有应用程序与由于其他应用程序安装了不兼容的共享 DLL 而导致的问题隔离开。 |
指定的版本对于使用它们的应用程序来说是隔离的吗? | 是。SxS 组件总是应当部署成:对于使用它们的应用程序来说是隔离的。 | 是。使用 DLL/COM 重定向的应用程序使用安装在该应用程序目录中的共享组件的版本,不管在系统中安装了哪些其他版本。 |
需要新代码还是对现有代码进行修改? | 是。建立 SxS 组件(或编写现有组件 SxS)至少需要将 COM 注册代码更改为允许按相对路径进行访问。可能需要一些附加编码更改,以确保在 SxS 运行版本之间正确地处理全局状态。 | 否。DLL/COM 重定向允许应用程序重新配置为,不需要更改任何代码或重新编译便能安装并运行 SxS。这允许没有应用程序源代码访问权的管理员便能重新配置它以解决 DLL Hell 问题。 |
该策略在所有方案中均采用吗? | 是。SxS 组件被设计并编码以安装并运行 SxS。因此,经过良好设计、开发和测试的 SxS 组件(以及使用它们的应用程序)将不会有与 DLL Hell 相关的问题。 | 否。DLL/COM 重定向不要求改变代码。现有的应用程序和组件可能没有按同时运行多个版本的要求进行设计。经验表明在大多数情况下现有的应用程序和组件可以运行 SxS,但需要进行测试才能确认对于特定方案是否是这样。(请参见 选择要隔离的组件。) |
一般的常规处理方法:
并行共享,要求开发者在创建新的应用程序时编写并行组件。它们都是普通的 COM 或 Win32 组件,不过它们安装在应用程序目录(或其子目录)中,而不是系统目录中。它们是与特定应用程序隔离的,并且不被所有应用程序全局共享。
因此,组件可以安全地与安装在其它地方的同一组件的不同版本,并行安装在另一个应用程序目录中。如果系统中的另一个应用程序要求(因此安装了)不同的版本,您的应用程序不会受到影响。这两个应用程序将和它们各自的组件版本一起运行。
如果另一个应用程序在系统中安装了新的组件版本,您的该组件版本将保持不变,因为您已将它安装到自己的应用程序目录中。在其他应用程序使用它的版本的同时,您的应用程序继续使用随该应用程序提供的组件版本。操作系统可以同时加载这两个版本。
同样,因为并行组件对于安装它的应用程序是“私有”的,所以应用程序的卸装程序始终可以安全地删除并行组件,按照定义,任何其他应用程序都不能依赖于私有组件。
注意 并行组件必须通过操作系统正确注册(在本章后面部分中说明),组件的每个版本才不会与该组件的其他现有版本冲突。
注意 Windows 2000 和 Windows 98 第二版本均支持并行共享。以前的 Windows 操作系统不支持它;但是,在这些系统中,可以在系统目录中安装一个并行 DLL(按照下一节中的指南编写的 DLL)。因此,DLL 以全局共享(向后兼容)方式工作。应用程序必须动态地检查操作系统版本以确定要使用的共享方法。
下面的指南概述了在产生并行组件(COM 或 Win32)中涉及的事项。当您编写这类组件并将它们放在应用程序目录中时,您的代码被私有化为该应用程序的上下文。当您将数据放入以该应用程序名称为根项的注册表项中时,该数据被私有化为该应用程序的。
您的并行组件的用户,与您的组件的其他用户所需要的更改绝缘。您还能够更新您的组件,而不必担心破坏现有的应用程序。应用程序能够安装您的组件而不用重新引导,即使另一个应用程序正在使用该组件的不同版本。
注意 这些指南是当前 Windows 认证指南的更稳定的形式,它告诉用户将 Win32 DLL 放在应用程序的目录中。
#define MyRegistryKey "MyAppv1.0.0.0"
发行组件的新版本时,只需要在某个位置更改该版本。
HKEY_CLASSES_ROOT\CLSID\{GUID}\InprocServer32
Default=foo.dll
ThreadingModel=Apartment
RefCount=1
注意 必须引用与 GUID 无关的 DLL 计数。
HKCU\MyCompany\MyComponent\VersionXXXX
例如,假定一个称为 EnableSuperCoolFeature 的配置设置有真或假的值。在注册表中存储该信息的传统方式为:
HKEY_CurrentUser\Software\MyCompany\MyComponent EnableSuperCoolFeature = TRUE
在并行共享情况下,应当用如下方式存储它:
HKEY_CurrentUser\Software\MyCompany\MyComponent\Version01.01
EnableSuperCoolFeature = TRUE
HKCU\MyCompany\MyComponent\VersionXXYY\SomeApplication\
其中“SomeApplication”是 GetModuleFileName 的返回值。这样做使组件能够隔离它的设置,该设置只针对当前正在运行的应用程序。
安装并行组件之前,必须确定在您的操作系统中是否支持它们。下列代码检测并行共享是否可用。如果不可用,组件必须安装在系统目录中。
BOOL bPlatformSupportsSideBySide(void)
{
OSVERSIONINFOEX osviex ;
osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
// 若平台不支持 OSVERSIONINFOEX 结构,就不支持并行
// 在内核中,我们已经使这些修改连在一起
//
if (!GetVersionEx((OSVERSIONINFO *)&osviex))
{
return FALSE ; // 无 DLL 重定向
}
// 然而对于 NT,则 NT4 SP4 支持 OSVERSIONINFOEX 支持,但它不支持 DLL 重定向。
// 若 DLL 重定向出现在将来的 NT4 SP 中,必须更新此代码。
//
if ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
(osviex.dwMajorVersion < 5) )
{
return FALSE ;
}
// 对于其他平台标识,假定具有并行支持
return TRUE ;
}
正确安装和卸载组件很关键。理想情况下,除了将组件复制到应用程序目录中或将其从应用程序目录中删除外,不应有其他的安装和卸装过程。但是,如果需要执行组件的 COM 注册或其他初始设置,则必须以与并行一致的方式执行。
Windows 2000 包含 Windows Installer 版本 1.1,它将支持并行组件的安装和卸载。(在 Windows 2000 发布之后,Windows Installer 还可以联机使用。)当注册并行 COM 组件时,需要确认“类”表中的属性栏设置了 msidbClassAttributesRelativePath 位。这将用相对路径名注册组件,允许相同组件的多个副本共存。
切记,当组件在应用程序目录中是私有的,一些其他应用程序可能在该机器中安装了该组件的不同版本。当安装或卸载该组件时,您不希望做有损于其他应用程序的事。因此使用您的组件的应用程序将靠您,通过自注册入口点 DLLRegisterServer 或 DLLUnregisterServer(对于 COM 组件)或 DllInstall(对于 Win32 或 COM 组件)来正确安装它。有关这些函数的详细信息,请参阅“平台 SDK”中的 “Register Server”(英文)。
要在应用程序目录中正确安装组件,请像安装常规组件一样执行下列步骤:
{00000109-0000-0010-8000-00AA006D2EA4}
\InprocServer32
Default = "mycomponent.dll"
ReferenceCount=1
注意 类型库应包含在 DLL 中,并且不需要在系统注册表中注册。
要正确卸装应用程序目录中的组件, 请像安装常规组件一样执行下列步骤:
DLL/COM 重定向,要求在部署应用程序时该应用程序是可执行的,并且所有的隔离组件安装在应用程序目录中,而不是系统目录中。另外,“.local”文件被部署在应用程序目录中,以修改 Windows 绑定行为,使应用程序绑定到隔离组件,而不是全局共享版本。
于是,应用程序将使用能安全地并行运行同一组件的不同版本的组件,这些组件的不同版本安装在其他位置、另一个应用程序目录中或系统目录中。如果系统中的另一个应用程序要求不同的版本,您的应用程序将不受影响,并且两个应用程序将用它们各自的组件版本运行。
如果另一个应用程序在系统中安装了新的组件版本,该应用程序的组件版本将保持不变,因为您已将它安装到您的应用程序目录中。在其他应用程序使用它的版本的同时,您的应用程序继续使用随该应用程序提供的组件版本。操作系统可以同时加载这两个版本。
注意 必须用操作系统正确注册隔离的 COM 组件,组件的每个版本才不会与该组件的其他可能存在的版本发生冲突。该注册要求,虽然组件的实现可因版本而异,但诸如 CLSID、ProgID、类型库和线程模型等注册的 COM 元数据,不能因版本而异。
注意 Windows 2000 和 Windows 98 第二版本都支持 DLL/COM 重定向。在该版本以前的 Windows 操作系统不支持他们。
DLL/COM 重定向允许开发者或管理员有选择地将现有组件与正在建立和开发的应用程序隔离开。本节讨论如何激活 DLL/COM 重定向,以及如何选择要隔离的组件 。
通过“.local”文件的形式在逐个应用程序的基础上激活 DLL/COM 重定向。在与应用程序的 .exe 文件相同的目录中,“.local”是一个空文件,它与应用程序的 .exe 文件名称相同,并且在该名称的结尾带有“.local”。
例如,要为称为“myapp.exe”的应用程序激活 DLL/COM 重定向,可在安装 myapp.exe 的相同目录中创建一个称为“myapp.exe.local”的空文件。
一旦激活 DLL/COM 重定向,则每当应用程序装入一个 DLL 或 OCX 时,Windows 将首先在安装该应用程序的 .exe 文件的目录中查找该 DLL 或 OCX。如果在安装 应用程序的 .exe 文件的目录中找到该 DLL 或 OCX 的一个版本,则不管在应用程序或注册表中指定了什么目录路径,应用程序都将使用它。如果在安装应用程序的 .exe 文件的目录中未发现该 DLL 或 OCX 的版本,则使用一般搜索路径或服务器路径。
DLL/COM 重定向允许隔离现有组件,其中安装在计算机中的应用程序需要相同组件的不同版本。不需要对该组件进行任何代码更改,因为一旦激活,DLL/COM 重定向将更改 Windows 绑定行为。
但是到目前为止,并行执行组件的不同版本通常已不是设计所考虑的问题。当组件可以很容易地并行安装(安装在一个共享的位置并且与一个或多个应用程序隔离)时,它们可能不并行运行。假定任何时刻在计算机中只有一个组件版本,出现这种情况是因为一些组件使用全局状态(如存储在注册表中的设置)。另外,当该组件定位它所需要的其他资源时,该组件可能会假设它所安装的特定目录。
由于这个原因,必须测试应用程序,该应用程序使用了安装在自己身上和其他应用程序环境中的隔离组件,该组件是隔离的。Microsoft 的经验表明在大多数方案中,共享的组件通常是可以并行运行的,但在某些情况下,可能需要关闭一个应用程序,然后才能运行下一个应用程序。
选择要隔离的组件时应遵照下列指南:
在该方案中,管理员无法开发新的应用程序,因为新的应用程序使用在 Visual Basic 中创作的 ActiveX 控件的版本。该版本不同于当前开发的应用程序所需要的版本。
这时,对于 ActiveX 控件的错误修正和其他修改引入了语义的差别。如,应用程序使用了一个有问题的控件版本,该控件版本没有经过测试。管理员必须有能力运行不同版本的 ActiveX 控件,这些不同版本的 ActiveX 控件用于不同的应用程序,避免修正并重新测试可能受 ActiveX 控件更改影响的每个应用程序。
注意 在 Visual Basic 中,当前没有可供开发人员编写内在并行的 ActiveX 控件的便利途径。这是因为用 Visual Basic 创作的 ActiveX 控件在注册时将把 OCX 文件的全限定路径写入注册表中。
管理员能够强制新应用程序使用正确版本的 ActiveX 控件,并且通过将新应用程序的设置修改为下列值,以确认现有应用程序的配置没有更改:
在该方案中,管理员得知在开发了新的应用程序之后,一个现有的应用程序停止工作。管理员能够诊断出问题是由于对共享组件进行修改引起的,这样做会导致共享组件的新版本不支持对先前版本的向后兼容。
管理员能够通过执行下列步骤修正应用程序:
DLL/COM 重定向是通过在新的位置安装 DLL 或 OCX 文件(专用于应用程序)来实现的,但是将不隔离与 COM Server 关联的其他系统状态,这对于隔离 COM Server 具有一些特定含义。
安装隔离的 COM Server 时,应当小心,以确保如果在计算机中已安装了组件的任何版本(例如通过其他应用程序),InprocServer 文件的位置不被隔离组件的新位置所覆盖。对于隔离的 COM Server,在运行时忽略 InprocServer 文件位置。但是不使用 DLL/COM 重定向的现有应用程序要求 InprocServer 文件位置继续指定先前安装的 COM Server 的位置。这意味着:
相反,如果隔离的 COM Server 的版本尚未安装在计算机中,则必须注册它。这种问题出现在当 COM Server 与应用程序隔离、被安装在应用程序的 .exe 目录下,然后又安装了一个需要该组件的非隔离的应用程序。在这种情况下,卸载隔离的应用程序不可能将隔离的 COM 组件视为共享文件,因此卸载将中断其他应用程序。这意味着:
对于现有组件,一些版本可能由一些应用程序共享,而另一些版本可能专门用于一些其他的应用程序,比较合理的经验做法是:在安装使用潜在共享组件的隔离版本的应用程序之后,确保安装了该组件的共享版本和隔离版本,并且注册了共享版本。这样做允许卸载程序删除隔离版本,而不必担心会中断其他应用程序。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com