编程高手之路—跟我学VB—Windows 的登录资料库
病从口入, 这句话大致上也适用於电脑, 如果我们不??给电脑不明的软体或档案,就不用担心电脑病毒的肆虐, 不过电脑之所以出状况, 电脑病毒只是其中一种原因,虽然它是最容易联想到的原因, 但实际上, 就像人一样, 除了部分的病痛来自病毒的感染之外,仍有不少的病痛来自於身体组织的毛病。 对 Windows 来说, 哪些是最重要的器官组织呢?除了驱动程式与应用程式之外,当首推登录资料库(Registry Database), 举例来说, 开机时, Windows 会从登录资料库中读取硬体的相关设定,如果登录资料库的设定与硬体不符合, 就可能无法开机或者 Windows 必须重新进行硬体的侦测,除了硬体的设定之外, 软体的运作也与登录资料库有极大的关系, 举例来说,当我们安装 Windows 之後, .bmp 档案预设的开启程式是「小画家」, 但是当我们又安装了其他绘图软体, .bmp 的开启程式却可能变成新安装的绘图软体, 这是因为新安装的绘图软体改变了登录资料库所致。
显然地, 能够了解 Windows 的登录资料库, 在 Windows 出状况时, 将更容易解决问题,而对程式设计者而言, 甚至可以藉着写入资料到登录资料库而达到改变 Windows 或应用程式行为的目的。 登录资料库的组织架构
存取登录资料库以前, 必须先了解登录资料库的组织架构, 而了解登录资料库的组织架构最简单的方法便是启动 Windows 提供的「登录编辑程式」, 启动的方法是利用「开始」工作列的「执行」交谈窗执行 RegEdit 程式, 执行之後, 可看到如图-1 的画面。
图-1 登录编辑程式
Key 与 Subkey
登录编辑程式的视窗结构与档案总管很像, 左边窗格的每一个资料夹图示表示一个 Key(中文的登录编辑程式将它翻译成「机码」, 但为了与程式直接对映, 本文中笔者不做翻译,仍以 Key 称之), 而就像资料夹底下还有子资料夹一样, 登录资料库的 Key 底下也有 Subkey(翻译成「子机码」, 但本文也一样不翻译), 为了完整地表示某一个 Subkey,习惯上是采用资料夹的路径表示法, 举例来说, HKEY_LOCAL_MACHINE 之下的 \Subkey 表示成 HKEY_LOCAL_MACHINE\\Software, 而 \之下的 \Subkey 则表示成 HKEY_LOCAL_MACHINE\\Software\\Microsoft。
图-2 Key 与 Subkey
Value、Value Name、Value Data 与 Default Value
当我们在登录编辑程式左边窗格选取某一个 Key(或 Subkey) 之後, 出现在右边窗格的是这个 Key 的 Value(数值), Value 可分成 Name(名称) 及 Data(资料) 两部分, 对每一个 Key 而言, 至少都含有一个 Default Value(预设值) 的栏位, 以 \Subkey 为例, 其 Default Value 的内容等於 \, 而除了 Default Value 之外, 这个 Subkey 还含有 Name(名称)为 \Type\而 Data(资料)为 \的 Value, 参阅图-3。
图-3 Value、Value Name、Value Data 与 Default Value
存取 Value, 先取 Key Handle
了解登录资料库的组织架构之後, 接下来该如何存取呢?就像我们存取档案时,必须指明档案的所在资料夹(目录)一样, 存取登录资料库时, 则必须先指明 Key。Key 在登录编辑程式中所看到的是一长串的字串, 例如 \,但是在 Windows 内部, 每一个 Key 都会对应到一个 Key Handle(等於一个长整数值,程式中通常以 hKey 表示), Windows 之所以要以 hKey 来代表 Key 是为了让登录资料库的存取更有效率,因为整数的操作效能要优於字串, 所以我们的第一个课题便是如何取得 Key 的 Key Handle(hKey)。
首先是位於最上层的 Key, 包含 HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE…等,这些 Key 的 hKey 是固定不变的, 其值如下表:
Key HKEY_CLASSES_ROOT HKEY_CURRENT_CONFIG HKEY_CURRENT_USER HKEY_DYN_DATA HKEY_LOCAL_MACHINE HKEY_USERS Key Handle &H80000000 &H80000005 &H80000001 &H80000006 &H80000002 &H80000003 但如果要取得这些 Key 的 Subkey Handle, 则必须呼叫 RegOpenKey API 函数, RegOpenKey 含有叁个参数, 意义如下:
(1) ByVal hKey As Long:Key Handle。 (2) ByVal lpSubkey As String:Subkey 的字串。
(3) phkResult As Long:若 RegOpenKey 成功, 则此一参数将传回 Subkey 的 hKey。
举例来说, 我们想取得 HKEY_LOCAL_MACHINE 之下的 \Subkey, 则使用的叙述是:
Dim ret As Long, hKey As Long
ret = RegOpenKey(HKEY_LOCAL_MACHINE, \hKey) If ret = 0 Then ' 表示成功,
' hKey 的值即等於 \Subkey 的 Key Handle End If
请注意呼叫登录资料库 API 函数(例如以上的 RegOpenKey)之後, 若成功,将传回 0, 否则传回非 0 的值, 这一点与 VB 函数的惯例并不相同, 请注意。
RegOpenKey 的第一个参数 hKey 除了可以指定最上层的 Key Handle 值(例如 HKEY_CLASSES_ROOT、HKEY_LOCAL_MACHINE…等)之外, 也可以是一个 Subkey Handle,以上一段程式为例, hKey 等於 \的 Subkey Handle, 接着如果我们要取得 \Y_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\的 Subkey Handle, 则程式如下: Dim ret As Long, hKey As Long, hKey2 As Long ret = RegOpenKey(hKey, \hKey2)
' 则 hKey2 将等於 \的 ' \Subkey Handle
在以上程式中, 请注意不要在 \之前加上 \使成为 \\, 这是错误的表示法。 Value 的存取
在登录资料库的存取中, 主要分成 Key 及 Value 两大部分, 首先让我们来了解 Value 的存取。在 Value 的存取方面, Windows API 提供的函数有 RegQueryValue、RegQueryValueEx、RegEnumValue、RegEnumValueEx …等, 这几个函数的宣告式请参本文附录, 从 VB 的习惯来看, 这几个函数并不好用,主要是因为它们使用了 As Any 的宣告方式, 使得一般使用者很容易传错参数,而无法得到正确的结果, 为了简化 Value 的存取, 笔者特别撰写一套符合 VB 习惯的 Value 存取函数, 这套函数已经将 API 函数封装起来, 也就是说, 您只要使用笔者所提供的 Value 存取函数, 可以暂时不必了解比较艰涩的
API 函数, 当然, 如果您对 Value 存取的 API 函数有兴趣, 可先参阅附录的原始程式码, 至於详细的介绍,由於篇幅有限, 笔者将来会以专书说明, 本文则暂且略过。 笔者所提供的 Value 存取函数
首先参阅本文附录或者请进入笔者的网站下载相关的原始程式码, 笔者所提供的 Value 存取函数有:GetDefaultValue(读取 Default Value)、GetValue(读取特定 Value)、GetValueByIndex(读取任意 Value)、SetDefaultValue(写入 Default Value)、SetValue(写入特定 Value) 等 5 个, 兹说明如下: ◆ GetDefaultValue 函数:读取Default Value 此一函数的定义是:
Function GetDefaultValue(ByVal hKey As Long, ByVal Subkey As String, Value As String) As Boolean 其中 hKey 及 Subkey 参数用来传入欲读取的 Key 或 Subkey, 而 Value 则用来传回读取之资料,若呼叫成功, 此一函数将传回 True。假设我们想读取 \的 Default Value, 则呼叫的范例如下:
Dim S As String, ret As Boolean
ret = GetDefaultValue(HKEY_CLASSES_ROOT, \S) ' 如果 ret 为 True, 则 S 等於读取之资料
' 如果 \没有预设值, 则 S = \
若已事先求得 \的 Subkey Handle 值,则以下的呼叫也是正确的: Dim S As String, ret As Boolean, hKey As Long
' 先呼叫 RegOpenKey 求取 \的 Subkey Handle ret = RegOpenKey(HKEY_CLASSES_ROOT, \hKey)
' hKey 已是正确的 Subkey Handle,所以参数二 Subkey 只要传入空字串即可 ret = GetDefaultValue(hKey, \S) ◆ GetValue 函数:读取特定Value
GetDefaultValue 只能读取某一个 Key(或 Subkey) 的 Default Value, 而 GetValue 则可以读取特定名称的 Value, 举例来说, 欲读取 \Subkey 之下名称为 \Type\的 Value, 则必须使用 GetValue 函数。 GetValue 的函数定义是: