什么是注册表
注册表是系统定义的数据库,应用程序和系统组件在其中存储和检索配置数据。存储在注册表中的数据因Microsoft Windows 的版本而异。应用程序使用注册表API来检索、修改或删除注册表数据。
PS:API 是应用程序编程接口(Application Programming Interface)的缩写,是一组预定义的函数和规范,用于在软件应用程序之间进行通信和交互。API 使得不同的应用程序可以共享数据和服务,从而实现更加高效、灵活和可扩展的软件开发。
除非绝对必要,否则不应编辑不属于您的应用程序的注册表数据。如果注册表中有错误,您的系统可能无法正常运行。如果发生这种情况,您可以将注册表恢复到上次成功启动计算机时的状态。
关于注册表
以下小节描述了注册表以及您可以调用以检索的修改存储在其中的数据的函数。
注册表结构
注册表是一个分层数据库,其中包含对Windows的操作以及在Windows上运行的应用程序和服务至关重要额数据。数据以树格式结构化。树中的每个阶段称为键。每个键都可以包含子键和称为值的数据条目。有时,密钥的存在就是应用程序所需的所有数据;其他时候,应用程序打开一个键并使用与该键关联的值。一个键可以有任意数量的值,值可以是任意形式。
每个键都有一个由一个或多个可打印字符组成的名称。键名不区分大小写。键名不能包含反斜杠字符 (\),但可以使用任何其他可打印字符。值名称和数据可以包含反斜杠字符。
每个子项的名称相对于层次结构中紧靠其上方的项而言是唯一的。键名未本地化为其他语言,但值可能是。
下图是注册表编辑器显示的示例注册表项结构。
我的电脑下的每棵树都是一把钥匙。HKEY_LOCAL_MACHINE键具有以下子键:HARDWARE、SAM、SECURITY、SOFTWARE和SYSTEM。这些键中的每一个依次具有子键。例如,HARDWARE键有子键DESCRIPTION、DEVICEMAP和RESOURCEMAP;DEVICEMAP键有几个子键,包括VIDEO。
每个值都包含一个值名称及其关联数据(如果有)。MaxObjectNumber和VgaCompatible是包含VIDEO子项下数据的值。
注册表树可以有 512 层深。您可以通过单个注册表 API 调用一次最多创建 32 个级别。
存储空间
尽管对于应用程序可以存储在注册表中的数据类型和大小几乎没有技术限制,但是存在一些实用指南来提高系统效率。应用程序应将配置和初始化数据存储在注册表中,并将其他类型的数据存储在其他地方。
通常,超过一或两千字节(K)的数据应存储为文件并通过在注册表中使用键来引用,而不是存储为值。应用程序不应在注册表中复制大量数据,而应将数据保存为文件并引用该文件。可执行的二进制代码不应该存储在注册表中。
值条目使用的注册表空间比键少得多。为了节省空间,应用程序应该将相似的数据组合在一起作为一个结构并将该结构存储为一个值,而不是将每个结构成员存储为一个单独的键。(以二进制形式存储数据允许应用程序将数据存储在一个值中,否则该值将由多个不兼容的类型组成。)
例如,如果一个应用程序需要存储一个包含多个字段的结构,它可以将这些字段组合在一起,并将它们存储在一个值中。这将比将每个字段存储在不同的键中更有效率,因为每个键都需要一定的空间来存储键名,而值只需要一个键名。
预定义键
预定义键
应用程序必须先打开一个密钥,然后才能将数据添加到注册表中。要打开一个注册表项,应用程序必须提供注册表中另一个已打开的注册表项的句柄。系统定义了始终打开的预定义键。预定义键帮助应用程序在注册表中导航,并使开发允许系统管理员操作数据类型的工具成为可能。将数据添加到注册表的应用程序始终在预定义键的框架内工作,以便管理工具可以找到并使用新数据。
应用程序可以使用这些键的句柄作为注册表的入口点。这些句柄对注册表的所有实现都有效,尽管句柄的使用可能因平台而异。此外,还为特别平台定义了其它预定义句柄。以下是预定义键的句柄。
处理 | 描述 |
HKEY_CLASSES_ROOT | 属于此键的注册表项定义文档的类型(或类)以及与这些类型关联的属性。Shell 和 COM 应用程序使用存储在该键下的信息。 此密钥还通过存储 DDE 和 OLE 支持信息提供与 Windows 3.1 注册数据库的向后兼容性。文件查看器和用户界面扩展将它们的 OLE 类标识符存储在HKEY_CLASSES_ROOT中,进程内服务器在该键中注册。 此句柄不应在模拟不同用户的服务或应用程序中使用。 |
HKEY_CURRENT_CONFIG | 包含有关本地计算机系统当前硬件配置文件的信息。HKEY_CURRENT_CONFIG下的信息仅描述了当前硬件配置与标准配置之间的差异。有关标准硬件配置的信息存储在HKEY_LOCAL_MACHINE的软件和系统键下。HKEY_CURRENT_CONFIG是HKEY_LOCAL_MACHINE\System\CurrentControlSet\Hardware Profiles\Current的别名。 |
HKEY_CURRENT_USER | 从属于该键的注册表条目定义了当前用户的首选项。这些首选项包括环境变量的设置、有关程序组、颜色、打印机、网络连接和应用程序首选项的数据。这个键可以更容易地建立当前用户的设置;该键映射到HKEY_USERS中当前用户的分支。在HKEY_CURRENT_USER中,软件供应商存储当前用户特定的首选项以在其应用程序中使用。例如,Microsoft 创建了HKEY_CURRENT_USER\Software\Microsoft键供其应用程序使用,每个应用程序都在Microsoft键下创建自己的子键。HKEY_CURRENT_USER 之间的映射并且HKEY_USERS是每个进程,并且是在进程第一次引用HKEY_CURRENT_USER时建立的。该映射基于引用HKEY_CURRENT_USER的第一个线程的安全上下文。如果此安全上下文没有在HKEY_USERS中加载注册表配置单元,则使用HKEY_USERS\.Default建立映射。建立此映射后,它会持续存在,即使线程的安全上下文发生变化也是如此。HKEY_CURRENT_USER中除HKEY_CURRENT_USER\Software\Classes 下的所有注册表项包含在漫游用户配置文件的每个用户注册表部分中。要从漫游用户配置文件中排除其他条目,请将它们存储在HKEY_CURRENT_USER_LOCAL_SETTINGS中。 此句柄不应在模拟不同用户的服务或应用程序中使用。 |
HKEY_CURRENT_USER_LOCAL_SETTINGS | 从属于该键的注册表条目定义了当前用户在机器本地的首选项。这些条目不包含在漫游用户配置文件的每个用户注册表部分中。Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP/2000:从 Windows 7 和 Windows Server 2008 R2 开始支持此密钥。 |
HKEY_LOCAL_MACHINE | 从属于此项的注册表条目定义了计算机的物理状态,包括有关总线类型、系统内存以及已安装的硬件和软件的数据。它包含保存当前配置数据的子项,包括即插即用信息(枚举分支,包括系统上所有硬件的完整列表)、网络登录首选项、网络安全信息、软件相关信息(例如作为服务器名称和服务器的位置),以及其他系统信息。 |
HKEY_PERFORMANCE_DATA | 从属于此键的注册表项允许您访问性能数据。数据实际上并未存储在注册表中;注册表功能使系统从其来源收集数据。 |
HKEY_PERFORMANCE_NLSTEXT | 从属于该键的注册表条目引用以计算机系统运行区域的本地语言描述计数器的文本字符串。这些条目不可用于 Regedit.exe 和 Regedt32.exe。Windows 2000:不支持该键。 |
HKEY_PERFORMANCE_TEXT | 从属于该键的注册表项引用了描述美式英语计数器的文本字符串。这些条目不可用于 Regedit.exe 和 Regedt32.exe。Windows 2000:不支持该键。 |
HKEY_USERS | 从属于此项的注册表项定义了本地计算机上新用户的默认用户配置和当前用户的用户配置。 |
RegOverridePredefKey函数使您能够将预定义的注册表项映射到注册表中的指定项。例如,软件安装程序可以在安装 DLL 组件之前重新映射预定义的键。这使安装程序能够轻松检查 DLL 的安装过程写入预定义密钥的信息。
RegDisablePredefinedCache和RegDisablePredefinedCacheEx函数禁用预定义注册表句柄的句柄缓存。使用模拟的服务应在使用预定义注册表句柄之前调用RegDisablePredefinedCacheEx 。
预定义句柄不是线程安全的。在一个线程中关闭预定义句柄会影响正在使用该句柄的任何其他线程。
HKEY_CLASSES_ROOT密钥
HKEY_CLASSES_ROOT ( HKCR ) 键包含文件扩展名关联和 COM 类注册信息,例如ProgID、CLSID和IID。它主要用于与 16 位 Windows 中的注册表兼容。
类注册和文件扩展名信息存储在HKEY_LOCAL_MACHINE和HKEY_CURRENT_USER键下。HKEY_LOCAL_MACHINE \Software\Classes项包含可应用于本地计算机上所有用户的默认设置。HKEY_CURRENT_USER \Software\Classes项包含仅适用于交互式用户的设置。HKEY_CLASSES_ROOT键提供了合并来自这两个来源的信息的注册表视图。HKEY_CLASSES_ROOT还为为以前版本的 Windows 设计的应用程序提供此合并视图。
用户特定设置优先于默认设置。例如,默认设置可能会指定一个特定的应用程序来处理 .doc 文件。但是用户可以通过在注册表中指定不同的应用程序来覆盖此设置。
RegOpenKeyEx或RegQueryValueEx等注册表函数允许您指定HKEY_CLASSES_ROOT键。当您从交互式用户帐户中运行的进程调用这些函数时,系统会将HKEY_LOCAL_MACHINE\Software\Classes中的默认设置与HKEY_CURRENT_USER\Software\Classes中的交互式用户设置合并。
要更改交互式用户的设置,请将更改存储在HKEY_CURRENT_USER\Software\Classes而不是HKEY_CLASSES_ROOT下。
要更改默认设置,请将更改存储在HKEY_LOCAL_MACHINE\Software\Classes下。如果您将密钥写入HKEY_CLASSES_ROOT下的密钥,系统会将信息存储在HKEY_LOCAL_MACHINE\Software\Classes下。如果您将值写入HKEY_CLASSES_ROOT下的某个键,并且该键已存在于HKEY_CURRENT_USER\Software\Classes下,系统会将信息存储在那里而不是在HKEY_LOCAL_MACHINE\Software\Classes下。
在交互式用户以外的安全上下文中运行的进程不应将HKEY_CLASSES_ROOT键与注册表函数一起使用。相反,此类进程可以显式打开HKEY_LOCAL_MACHINE\Software\Classes键以访问默认设置。要打开将HKEY_LOCAL_MACHINE\Software\Classes的内容与指定用户的设置合并的注册表项,这些进程可以调用RegOpenUserClassesRoot函数。例如,如果正在模拟客户端的线程需要为被模拟的客户端检索合并视图,则它可以调用RegOpenUserClassesRoot 。请注意,RegOpenUserClassesRoot如果尚未加载指定用户的用户配置文件,则失败。系统在登录时自动加载交互式用户的配置文件。对于其他用户,您需要调用LoadUserProfile函数来显式加载用户的配置文件。
如果应用程序以管理员权限运行并且禁用了用户帐户控制,则 COM 运行时将忽略每个用户的 COM 配置并仅访问每个机器的 COM 配置。需要管理员权限的应用程序应在安装期间将依赖的 COM 对象注册到每台计算机的 COM 配置存储 ( HKEY_LOCAL_MACHINE\Software\Classes )。
注册表蜂窝
配置单元是注册表中键、子键和值的逻辑组,当操作系统启动或用户登录时,它具有一组加载到内存中的支持文件。
每次新用户登录到计算机时,都会为该用户创建一个新的配置单元,并为用户配置文件创建一个单独的文件。这称为用户配置文件配置单元。用户的配置单元包含与用户的应用程序设置、桌面、环境、网络连接和打印机有关的特定注册表信息。用户配置文件配置单元位于HKEY_USERS项下。
注册表文件有以下两种格式:标准格式和最新格式。标准格式是 Windows 2000 唯一支持的格式。为了向后兼容,更高版本的 Windows 也支持它。从 Windows XP 开始支持最新格式。在支持最新格式的 Windows 版本上,以下配置单元仍使用标准格式:HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE\SAM、HKEY_LOCAL_MACHINE\Security和HKEY_USERS\.DEFAULT;所有其他配置单元都使用最新格式。
配置单元的大部分支持文件都在 %SystemRoot%\System32\Config 目录中。每次用户登录时都会更新这些文件。这些目录中文件的文件扩展名,或者在某些情况下缺少扩展名,表明它们包含的数据类型。下表列出了这些扩展名以及文件中数据的描述。
数据类别
在将数据放入注册表之前,应用程序应将数据分为两类:特定于计算机的数据和特定于用户的数据。通过进行这种区分,应用程序可以支持多个用户,并且还可以通过网络定位用户特定数据并在不同位置使用该数据,从而允许与位置无关的用户配置文件数据。(用户配置文件是为每个用户保存的一组配置数据。)
安装应用程序时,它应该在HKEY_LOCAL_MACHINE键下记录计算机特定的数据。特别是,它应该为公司名称、产品名称和版本号创建键,如以下示例所示:
**HKEY_LOCAL_MACHINE\Software\**我的公司\我的产品\1.0
如果应用程序支持 COM,它应该将该数据记录在HKEY_LOCAL_MACHINE\Software\Classes下。
应用程序应在HKEY_CURRENT_USER键下记录用户特定的数据,如以下示例所示:
**HKEY_CURRENT_USER\Software\**我的公司\我的产品\1.0
打开、创建和关闭键
在应用程序可以将数据添加到注册表之前,它必须创建或打开一个键。要创建或打开密钥,应用程序总是将该密钥称为当前打开的密钥的子密钥。以下预定义键始终打开:HKEY_LOCAL_MACHINE、HKEY_CLASSES_ROOT、HKEY_USERS和HKEY_CURRENT_USER。应用程序使用RegOpenKeyEx函数打开密钥,使用RegCreateKeyEx函数创建密钥。注册表树可以有 512 层深。您可以通过单个注册表 API 调用一次最多创建 32 个级别。
应用程序可以使用RegCloseKey函数关闭一个键并将它包含的数据写入注册表。RegCloseKey在返回前不一定将数据写入注册表;将缓存刷新到硬盘可能需要几秒钟的时间。如果应用程序必须显式地将注册表数据写入硬盘,则可以使用RegFlushKey函数。但是, RegFlushKey使用许多系统资源,应仅在绝对必要时才调用。
写入和删除注册表
应用程序可以使用RegSetValueEx函数将值及其数据与键相关联。
要从键中删除值,应用程序可以使用RegDeleteValue函数。要删除一个键,可以使用RegDeleteKey函数。已删除的密钥在其最后一个句柄关闭之前不会被删除。不能在已删除的键下创建子键和值。
在写入操作期间无法锁定注册表项以同步对数据的访问。但是,您可以使用安全属性控制对注册表项的访问。
可以在单个事务中执行多个注册表操作。要将注册表项与事务相关联,应用程序可以使用RegCreateKeyTransacted或RegOpenKeyTransacted函数。
数据从注册表中检索数据
要从注册表中检索数据,应用程序通常会枚举键的子键,直到它找到一个特定的子键,然后从与其关联的一个或多个值中检索数据。应用程序可以调用RegEnumKeyEx函数来枚举给定键的子键。
要检索有关特定子项的详细数据,应用程序可以调用RegQueryInfoKey函数。RegGetKeySecurity函数检索保护密钥的安全描述符的副本。
应用程序可以使用RegEnumValue函数枚举给定键的值,并使用RegQueryValueEx函数检索键的特定值。应用程序通常调用RegEnumValue来确定值名称,然后调用 RegQueryValueEx来检索名称的数据。
RegQueryMultipleValues函数检索与打开的注册表项关联的值名称列表的类型和数据。此函数对动态密钥提供程序很有用,因为它通过在原子操作中检索多个值来确保数据的一致性。
因为其他应用程序可以在您的应用程序可以读取值和使用它之间更改注册表值中的数据,所以您可能需要确保您的应用程序具有最新数据。当注册表项的属性或内容发生更改,或者注册表项被删除时,您可以使用RegNotifyChangeKeyValue函数通知调用线程。该函数向事件对象发出信号以通知调用者。如果调用RegNotifyChangeKeyValue的线程退出,则会发出事件信号并停止对注册表项的监视。
您可以通过使用通知过滤器或标志来控制或指定应报告哪些更改。通常,通过向函数发出您指定的事件信号来报告更改。请注意,RegNotifyChangeKeyValue函数不适用于远程句柄。
注册表文件
应用程序可以将注册表的一部分保存在一个文件中,然后将文件的内容加载回注册表中。当正在处理大量数据、在注册表中创建许多条目或数据是暂时的并且必须加载然后再次卸载时,注册表文件很有用。备份和恢复部分注册表的应用程序可能会使用注册表文件。
要将键及其子键和值保存到注册表文件,应用程序可以调用RegSaveKey或RegSaveKeyEx函数。
RegSaveKey和RegSaveKeyEx创建具有存档属性的文件。该文件是在进程的当前目录中为本地密钥创建的,在 %systemroot%\system32 目录中为远程密钥创建的。
注册表文件有以下两种格式:标准格式和最新格式。标准格式是 Windows 2000 唯一支持的格式。为了向后兼容,更高版本的 Windows 也支持它。RegSaveKey以标准格式创建文件。
从 Windows XP 开始支持最新格式。以这种格式创建的注册表文件无法在 Windows 2000 上加载。RegSaveKeyEx可以通过指定 REG_STANDARD_FORMAT 或 REG_LATEST_FORMAT 以任一格式保存注册表文件。因此,它可用于将使用标准格式的注册表文件转换为最新格式。
要将注册表文件写回注册表,应用程序可以使用RegLoadKey、RegReplaceKey或RegRestoreKey函数,如下所示。
- RegLoadKey将注册表数据从指定文件加载到调用应用程序计算机或远程计算机上HKEY_USERS或HKEY_LOCAL_MACHINE下的指定子项中。如果指定的子项不存在,该函数将创建它。调用此函数后,应用程序可以使用RegUnLoadKey函数将注册表恢复到以前的状态。
- RegReplaceKey 用指定文件中包含的数据替换注册表中的键及其所有子键和值。新数据在系统下次启动时生效。
- RegRestoreKey将指定文件中的注册表数据加载到调用应用程序计算机或远程计算机上的指定键中。此函数用文件中顶级键后面的子键和值替换指定键下面的子键和值。
RegConnectRegistry函数建立到另一台计算机上预定义注册表句柄的连接。应用程序主要使用此功能来访问网络环境中其他计算机上的远程注册表中的信息,您也可以使用注册表编辑器来执行此操作。您可能想要访问远程注册表以备份注册表或调节对它的网络访问。请注意,您必须具有适当的权限才能使用此功能访问远程注册表。
注册表键安全和访问权限
Windows 安全模型使您能够控制对注册表项的访问。
您可以在调用RegCreateKeyEx或RegSetKeySecurity函数时为注册表项指定安全描述符。如果您指定NULL,密钥将获得默认的安全描述符。密钥的默认安全描述符中的 ACL 是从其直接父密钥继承的。
要获取注册表项的安全描述符,请调用RegGetKeySecurity、GetNamedSecurityInfo或GetSecurityInfo函数。
注册表项的有效访问权限包括 DELETE、READ_CONTROL、WRITE_DAC 和 WRITE_OWNER标准访问权限。注册表项不支持 SYNCHRONIZE 标准访问权限。
下表列出了注册表项对象的特定访问权限。
value | 含义 |
KEY_ALL_ACCESS (0xF003F) | 结合了 STANDARD_RIGHTS_REQUIRED、KEY_QUERY_VALUE、KEY_SET_VALUE、KEY_CREATE_SUB_KEY、KEY_ENUMERATE_SUB_KEYS、KEY_NOTIFY 和 KEY_CREATE_LINK 访问权限。 |
KEY_CREATE_LINK (0x0020) | 保留供系统使用。 |
KEY_CREATE_SUB_KEY (0x0004) | 创建注册表项的子项时需要。 |
KEY_ENUMERATE_SUB_KEYS (0x0008) | 需要枚举注册表项的子项。 |
KEY_EXECUTE (0x20019) | 相当于 KEY_READ。 |
KEY_NOTIFY (0x0010) | 请求注册表项或注册表项的子项的更改通知时需要。 |
KEY_QUERY_VALUE (0x0001) | 需要查询注册表项的值。 |
KEY_READ (0x20019) | 结合了 STANDARD_RIGHTS_READ、KEY_QUERY_VALUE、KEY_ENUMERATE_SUB_KEYS 和 KEY_NOTIFY 值。 |
KEY_SET_VALUE (0x0002) | 创建、删除或设置注册表值时需要。 |
KEY_WOW64_32KEY (0x0200) | 指示 64 位 Windows 上的应用程序应在 32 位注册表视图上运行。32 位 Windows 忽略此标志。有关详细信息,请参阅访问备用注册表视图。 此标志必须使用 OR 运算符与此表中查询或访问注册表值的其他标志组合。 Windows 2000:不支持此标志。 |
KEY_WOW64_64KEY (0x0100) | 指示 64 位 Windows 上的应用程序应在 64 位注册表视图上运行。32 位 Windows 忽略此标志。有关详细信息,请参阅访问备用注册表视图。 此标志必须使用 OR 运算符与此表中查询或访问注册表值的其他标志组合。 Windows 2000:不支持该标志。 |
KEY_WRITE (0x20006) | 组合了 STANDARD_RIGHTS_WRITE、KEY_SET_VALUE 和 KEY_CREATE_SUB_KEY 访问权限。 |
当您调用RegOpenKeyEx函数时,系统会根据密钥的安全描述符检查请求的访问权限。如果用户对注册表项没有正确的访问权限,则打开操作将失败。如果管理员需要访问密钥,解决方案是启用 SE_TAKE_OWNERSHIP_NAME 权限并使用 WRITE_OWNER 访问权限打开注册表项。有关详细信息,请参阅启用和禁用权限。
如果要读取或写入注册表项的系统访问控制列表 (SACL),您可以请求对注册表项的 ACCESS_SYSTEM_SECURITY 访问权限。有关详细信息,请参阅访问控制列表 (ACL)和SACL 访问权限。
要查看某个键(包括预定义键)的当前访问权限,请使用注册表编辑器 (Regedt32.exe)。导航到所需的密钥后,转到“编辑”菜单并选择“权限”。
32位和64位应用程序数据注册表
在 64 位 Windows 上,部分注册表条目分别为 32 位应用程序和 64 位应用程序存储,并使用注册表重定向器和注册表反射映射到单独的逻辑注册表视图,因为 64 位版本的应用程序可能使用与 32 位版本不同的注册表项和值。还有未重定向或反映的共享注册表项。
每个 64 位注册表节点的父节点是映像特定节点或 ISN。注册表重定向器透明地将应用程序的注册表访问定向到适当的 ISN 子节点。注册表树中的重定向子节点由 WOW64 组件使用名称Wow6432Node自动创建。因此,重要的是不要命名您创建的任何注册表项Wow6432Node。
KEY_WOW64_64KEY 和 KEY_WOW64_32KEY 标志分别启用对 64 位注册表视图和 32 位视图的显式访问。有关详细信息,请参阅访问备用注册表视图。
要为特定键禁用和启用注册表反射,请使用RegDisableReflectionKey和RegEnableReflectionKey函数。应用程序应仅针对它们创建的注册表项禁用反射,而不应尝试禁用预定义键(例如HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER)的反射。要确定哪些键在反射列表中,请使用RegQueryReflectionKey函数。
虚拟化
注册表虚拟化是一种应用程序兼容性技术,可以将具有全局影响的注册表写入操作重定向到每个用户的位置。此重定向对于读取或写入注册表的应用程序是透明的。从 Windows Vista 开始支持它。
这种形式的虚拟化是一种临时的应用程序兼容技术;随着越来越多的应用程序与 Windows Vista 和更高版本的 Windows 兼容,Microsoft 打算将其从未来版本的 Windows 操作系统中删除。因此,重要的是您的应用程序不依赖于系统中注册表虚拟化的行为。
虚拟化仅旨在为现有应用程序提供兼容性。为 Windows Vista 和更高版本的 Windows 设计的应用程序不应写入敏感的系统区域,也不应依赖虚拟化来解决任何问题。更新现有代码以在 Windows Vista 和更高版本的 Windows 上运行时,开发人员应确保应用程序仅将数据存储在每个用户位置或 %alluserprofile% 中正确使用访问控制列表 (ACL) 的计算机位置。
有关构建符合 UAC 的应用程序的更多信息,请参阅UAC 开发人员指南。
虚拟化概述
在 Windows Vista 之前,应用程序通常由管理员运行。因此,应用程序可以自由访问系统文件和注册表项。如果这些应用程序由标准用户运行,它们将因访问权限不足而失败。Windows Vista 和更高版本的 Windows 通过自动重定向这些操作提高了这些应用程序的应用程序兼容性。例如,对全局存储 ( HKEY_LOCAL_MACHINE\Software ) 的注册表操作被重定向到用户配置文件中的每个用户位置,称为虚拟存储( HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software )。
注册表虚拟化大致可分为以下类型:
(1)开放注册表虚拟化
如果调用者没有对密钥的写入权限并尝试打开该密钥,则该密钥将以该调用者允许的最大访问权限打开。
如果为密钥设置了 REG_KEY_DONT_SILENT_FAIL 标志,则操作失败并且不会打开密钥。有关详细信息,请参阅本主题后面的“控制注册表虚拟化”。
(2)写注册表虚拟化
如果调用者没有对键的写入权限并尝试向其写入值或创建子键,则该值将写入虚拟存储。
例如,如果受限用户尝试将值写入以下键:HKEY_LOCAL_MACHINE\Software \ AppKey1,虚拟化会将写入操作重定向到HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software \ AppKey1。
(3)读取注册表虚拟化
如果调用者从虚拟化的键中读取,注册表会向调用者呈现虚拟化值(来自虚拟存储)和非虚拟值(来自全局存储)的合并视图。
例如,假设HKEY_LOCAL_MACHINE\Software \ AppKey1包含两个值 V1 和 V2,并且受限用户将值 V3 写入密钥。当用户尝试从此键读取值时,合并视图包括来自全局存储的值 V1 和 V2 以及来自虚拟存储的值 V3。
请注意,虚拟值在存在时优先于全局值。在上面的例子中,即使全局存储在这个键下有值 V3,值 V3 仍然会从虚拟存储返回给调用者。如果要从虚拟存储中删除 V3,则将从全局存储中返回 V3。换句话说,如果要从HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software \ AppKey1中删除 V3 ,但HKEY_LOCAL_MACHINE\Software \ AppKey1具有值 V3,则将从全局存储返回该值。
注册表虚拟化范围
仅为以下启用注册表虚拟化:
- 32 位交互式进程。
- 键入HKEY_LOCAL_MACHINE\Software。
- 管理员可以写入的密钥。(如果管理员无法写入密钥,那么即使该应用程序由管理员运行,它在以前版本的 Windows 上也会失败。)
注册表虚拟化在以下情况下被禁用:
-
64 位进程。
-
非交互式进程,例如服务。
请注意,如果密钥被虚拟化,将注册表用作服务(或任何其他未启用虚拟化的进程)和应用程序之间的进程间通信 (IPC) 机制将无法正常工作。例如,如果防病毒服务根据应用程序设置的值更新其签名文件,则该服务将永远不会更新其签名文件,因为该服务从全局存储读取但应用程序写入虚拟存储。
-
模拟用户的进程。如果进程在模拟用户时尝试执行操作,则该操作将不会被虚拟化。
-
内核模式进程,例如驱动程序。
-
在其清单中指定了requestedExecutionLevel 的进程。
-
HKEY_LOCAL_MACHINE\Software\Classes、HKEY_LOCAL_MACHINE\Software\Microsoft\Windows和HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT的键和子键。
控制注册表虚拟化
除了通过使用清单中的requestedExecutionLevel在应用程序级别控制虚拟化之外,管理员还可以针对HKEY_LOCAL_MACHINE\Software中的键在每个键的基础上启用或禁用虚拟化。为此,请使用 Reg.exe 命令行实用程序 FLAGS 选项和下表中列出的标志。
值 | 意义 |
REG_KEY_DONT_SILENT_FAIL | 此标志禁用开放注册表虚拟化。如果设置了此标志并且在启用了虚拟化的密钥上打开操作失败,则注册表不会尝试重新打开该密钥。如果清除此标志,则注册表会尝试使用 MAXIMUM_ALLOWED 访问权限而不是请求的访问权限重新打开密钥。 |
REG_KEY_DONT_VIRTUALIZE | 此标志禁用写入注册表虚拟化。如果设置了此标志并且创建键或设置值操作失败,因为调用者对父键没有足够的访问权限,则注册表将失败操作。如果此标志清除,注册表将尝试在虚拟存储中写入键或值。调用者必须对父键具有 KEY_READ 权限。 |
REG_KEY_RECURSE_FLAG | 如果设置了此标志,注册表虚拟化标志将从父项传播。如果清除此标志,则不会传播注册表虚拟化标志。更改此标志仅影响在更改标志后创建的新后代键。它不会为现有的后代键设置或清除这些标志。 |