📄 10.txt
字号:
ret = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\kj\Registry", hKey)
ret = GetValueByIndex(hKey, Index, Name, bArr, vType)
While ret
If Len(Name) = 0 Then Name = "(预设 值)"
List1.AddItem Name & vbTab & ValueOutput(bArr, vType)
Index = Index + 1
ret = GetValueByIndex(hKey, Index, Name, bArr, vType)
Wend
Call RegCloseKey(hKey)
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim Index As Long, ret As Long, hKey As Long
Dim bArr() As Byte, Name As String, vType As Long
ret = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\kj\Registry", hKey)
ret = GetValueByIndex(hKey, Index, Name, bArr, vType)
While ret
Call RegDeleteValue(hKey, Name)
' 不可以执行 Index = Index + 1,因为 Index = 0 的 Value 已删除,
' 後面的 Index 向前递减, 所以 Index = 0 又可以读到 Value,
' 其实在这一个 While 回圈中, 您可以将 Index 变数改成 0
ret = GetValueByIndex(hKey, Index, Name, bArr, vType)
Wend
Call RegCloseKey(hKey)
MsgBox "kj\Registry 的 Value 已删除, 利用 RegEdit 检查时, 记得要先执行功能的「检视/重新整理」!"
End Sub
--------------------------------------------------------------------------------
Key 的存取
--------------------------------------------------------------------------------
相对於 Value 的存取, Key 的存取要简单得多, Windows 所提供的 API 函数有 RegCreateKey(建立 Subkey)、RegEnumKey(逐一列举 Subkey)、RegDeleteKey(删除 Key 或 Subkey), 而笔者也仿效 Value 的存取函数, 提供了 GetSubkeyByIndex 替代比较不容易使用的 RegEnumKey, 至於 RegCreateKey 及 RegDeleteKey, 由於比较简单,所以直接呼叫即可, 以下就让笔者来说明这几个函数的用法。
RegCreateKey API 函数:建立 Subkey
--------------------------------------------------------------------------------
RegCreateKey 的用法与 RegOpenKey 完全相同, 所不同的是 RegOpenKey 只能开启既有的 Subkey, 而 RegCreateKey 则可以建立 Subkey, 比较特别的是, 如果呼叫 RegCreateKey 所建立的 Subkey 是一个已存在的 Subkey, 则 RegCreateKey 的作用与 RegOpenKey 相同, 由於 RegCreateKey 具有以上的特性, 很多人乾脆就不用 RegOpenKey 了,而不管开启或建立 Subkey, 都一概使用 RegCreateKey。
GetSubkeyByIndex 函数:读取任意 Subkey
--------------------------------------------------------------------------------
此一函数的定义如下:
Function GetSubkeyByIndex(ByVal hKey As Long, ByVal Index As Long, KeyName As String) As Boolean
如果已经了解之前存取 Value 的 GetValueByIndex 函数, 应该不难了解此一函数的用法,假设我们想列举 "HKEY_LOCAL_MACHINESOFTWARE\Microsoft" 的所有 Subkey, 则程式大致如下:
Dim ret As Long, hKey As Long, Index As Integer, Name As String
ret = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft", hKey)
While GetSubkeyByIndex(hKey, Index, Name)
Debug.Print Name ' 印出 Subkey Name
Index = Index + 1
Wend
RegDeleteKey API:删除 Key 或 Subkey
--------------------------------------------------------------------------------
RegDeleteKey 函数含有两个参数:
(1) ByVal hKey As Long:Key Handle。
(2) ByVal lpSubkey As String:Subkey 的字串, 若传入 "",表示删除 Key。
请注意当我们利用 RegDeleteKey 删除某一个含有 Subkey 的 Key 或 Subkey 时(假设 "HKEY_LOCAL_MACHINE\kj" 含有 "Registry" Subkey,则删除 "HKEY_LOCAL_MACHINE\kj" 即属於此一情况), 对於 Windows 95 或 NT 来说, 结果是不相同的, Windows 95 会将此一 Key(或 Subkey) 及其所有 Subkey 全数删除, 而 Windows NT 则传回失败值。
为了能够让 Windows NT 也具备 Windows 95 删除所有 Subkey 的功能, 笔者提供了另一个 VB 函数:
Function DeleteSubkeyTree(ByVal hKey As Long, ByVal Subkey As String) As Boolean
此一函数会呼叫 GetSubkeyByIndex 再向下读取所有的 Subkey, 然後一一将它们删除,程式的内容如下:
Function DeleteSubkeyTree(ByVal hKey As Long, ByVal Subkey As String) As Boolean
Dim ret As Long, Index As Long, Name As String
Dim hSubKey As Long
ret = RegOpenKey(hKey, Subkey, hSubKey) ' 取得 Subkey 的 Handle
If ret <> 0 Then
DeleteSubkeyTree = False
Exit Function
End If
ret = RegDeleteKey(hSubKey, "")
If ret <> 0 Then ' 失败,表示此一 Subkey 的下一层还有 Subkey
While GetSubkeyByIndex(hSubKey, 0, Name) And _
DeleteSubkeyTree(hSubKey, Name) ' 递回删除 Subkey 的 Subkey
Wend
ret = RegDeleteKey(hSubKey, "")
End If
DeleteSubkeyTree = (ret = 0)
End Function
以上程式在 While 回圈中利用了递回呼叫(在 DeleteSubkeyTree 函数中又呼叫 DeleteSubkeyTree)的特性, 很轻易地就可以向下删除所有层次的 Subkey。
--------------------------------------------------------------------------------
登录资料库的应用
--------------------------------------------------------------------------------
由於登录资料库是 Windows 与应用程式存放常用资料的大本营, 同时也会影响 Windows 及应用程式的运作模式, 因此直接存取登录资料库, 犹如通往 Windows 及应用程式核心的直达车, 确实是一件很过瘾的事情, 但如果胡乱写入资料或更改资料,却可能造成 Windows 及应用程式执行的错误。
设定应用程式的路径
--------------------------------------------------------------------------------
在 DOS 底下, 我们会利用 PATH 环境变数来设定程式的路径, 而当我们输入某一执行档名时, DOS 便会从目前工作目录及设定於 PATH 环境变数中的路径来寻找执行档。
对 Windows 而言, 搜寻执行档的顺序是:(1) 目前工作目录 (2) Windows 的所在目录及 System 目录 (3) 设定於 PATH 环境变数中的路径。如果我们想让使用者直接在「执行」交谈窗输入档名(不必输入完整路径)就可以启动程式,比较普通的方法是将程式的执行档复制到 Windows 的所在目录(或 System 目录),或者设定好 PATH 环境变数, 不过这两种方法都有缺点, 将执行档复制到 Windows 的所在目录, 会造成 Windows 所在目录的档案越来越多, 而不易於管理, 设定 PATH 环境变数则必须重新启动电脑才能生效, 且环境变数的空间是有限的。
其实 Windows 搜寻执行档的方法除了以上的 (1)(2)(3) 之外, 还会搜寻登录资料库 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths" 之下的 Subkey, 假设我们在此一 Subkey 之下, 建立了名称为 "Project1.exe" 而 Default Value 等於 "c:\vb\myapp\Project1.exe" 的 Subkey,则将来我们在「执行」交谈窗中输入 "Project1" 之後, Windows 就会搜寻到 "c:\vb\myapp\Project1.exe" 的执行档完整路径而启动此一程式, 您可以利用 RegEdit 观察 ""HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths" 的内容, 即可了解其中的端倪。
改变控制台的设定值
--------------------------------------------------------------------------------
使用 Windows 时, 我们可能会使用「控制台」来改变系统的设定值, 此时,系统的设定值是存放在 "HKEY_CURRENT_USER\Control Panel" 之下,举例来说, 利用「控制台」改变桌面的底图, 将会改变 "Desktop" Subkey 的 Wallpaper 设定值, 反过来说, 如果改变 "HKEY_CURRENT_USER\Control Panel\Desktop" 的 Wallpaper 设定值, 也应该可以改变桌面的底图, 基本上,这句话是正确的, 但笔者要特别说明的是, 当我们改变登录资料库的内容时, Windows 或应用程式并不知道登录资料库的内容已经改变了, 因此不一定会立刻反映出来,而通常要等到下次开机, Windows 或应用程式重新读取登录资料库时才有作用。(注:有关「控制台」相关的设定, Windows 提供了另一个 API 函数—SystemParametersInfo, 呼叫此一函数除了改变登录资料库之外,也会通知 Windows 立刻反应结果)。
副档名与应用程式的启动
--------------------------------------------------------------------------------
在档案总管里面, 如果我们双按 .txt 的档案, 档案总管会启动「记事本」开启此一档案,如果双按 .bmp 的档案, 则会启动「小画家」开启此一档案…, 此一工作模式,也与登录资料库有关, 以下就让笔者以 ".txt" 为例, 来说明登录资料库中的相关设定。
首先请检视 HKEY_CLASSES_ROOT 之下的 ".txt" Subkey, 它的 Default Value 等於 "txtfile", 接着继续在 HKEY_CLASSES_ROOT 之下寻找此一内容("txtfile")的 Subkey, 果然可以找到, 而它的 Default Value 等於 "纯文字文件",接着再检视 "txtfile" 之下的内容, 以笔者机器为例, 结构如下:
txtfile: (预设值)="纯文字文件"
shell: (预设值)=""
open: (预设值)=""
command: (预设值)="C:\\WINDOWS\\NOTEPAD.EXE %1"
print: (预设值)=""
command: (预设值)="C:\\WINDOWS\\NOTEPAD.EXE /p %1"
由於以上的结构, 使得我们在 ".txt" 的档案上面按下滑鼠右钮时,所有出现的快显功能表含有「开启旧档」及「列印」两种命令, 如图-6:
图-6 因为 txtfile\shell 之下含有 open 及 print, 所以档案总管的快显功能表会出现「开启旧档」与「列印」两种命令
接着请看 "open\command" 的 Default Value(预设值), 它等於 "C:\WINDOWS\NOTEPAD.EXE %1", 这表示当我们选取「开启旧档」命令时,档案总管会将其中的 %1 替换成 .txt 档案名(假设是 abc.txt), 然後执行 "C:\WINDOWS\NOTEPAD.EXE abc.txt", 同样的, 由於 "print\command" 的 Default Value(预设值) 等於 "C:\WINDOWS\NOTEPAD.EXE /p %1", 当我们选取「列印」命令时,档案总管的所执行的命令是 "C:\WINDOWS\NOTEPAD.EXE /p abc.txt"。
在图-6 的快显功能表中, 「开启旧档」是以粗体显示, 这表示当我们双按 ".txt" 档案时, 所启动的命令是「开启旧档」, 在此笔者想问的是,为什麽双按启动的是「开启旧档」, 而不是「列印」, 其实这跟 "txtfile\shell" 的 Default Value 有关, 由於 "txtfile\shell" 的没有 Default Value,所以档案总管便以第一个 Subkey(=open)为双按时的命令, 如果我们将 "txtfile\shell" 的 Default Value 改成 "print", 则双按所执行的命令将变成「列印」。
了解其他设定的意义
--------------------------------------------------------------------------------
笔者以上所举的只是少数的几个例子, 了解越多 Key 及 Value 的意义, 将越懂得藉助登录资料库的设定来控制 Windows 及应用程式的行为, 本文受限於篇幅, 暂且介绍至此, 如果您有兴趣进一步了解登录资料库内各种 Key 及 Value 的意义, 坊间可以找到不少中英文的参考书。
一个很困难的问题, 及一个很简单的解决方案
--------------------------------------------------------------------------------
有不少读者问:「不同程式之间, 如何共用资料?」, 这个问题真的很困难,对 Windows 3.1 而言, 记忆体的定址空间对所有程式而言是共用的, 为了达到资料的共用,可以由程式 A 配置资料, 然後传递资料的位址给程式 B, 程式 B 便可以透过此一位址使用此一资料,而达到共用资料的目的, 这一种共用资料的特色是每一程式都可以存取记忆体中任何位址的资料,不管这份资料是否属於自己所有, 乍看之下, 此一存取资料的模式十分方便,但也正因为如此, 很容易破坏他人的程式码造成当机, 而这正是 Windows 3.1 最为人诟病的一件事情。
对 32-bits 的 Windows(Windows 95 或 NT)而言, 每个程式都拥有独立的 2GB 定址空间, 首先让笔者来解释何谓独立的定址空间, 假设程式 A 某一资料的位址是 &H12340, 而资料的内容是 "AAAA", 但是对程式 B 而言, 同样的 &H12340 位址却可能存放着 "BBBB" 的资料, 虽然位址相同, 但实际上,在 Windows 的巧妙安排下, 使用的却是不同的记忆体位置, 为什麽要这麽做呢?道理很简单,也许程式 A 有 bug 把资料写错了位置, 如果它的定址空间不是独立的, 便可能破坏其他程式的程式码或资料,而造成其他程式的错误, 而相反的, 若每一个程式的定址空间都是独立的, 写得再烂的程式也不会毒到别人的程式,如此一来, 便可以让 Windows 更趋於稳定。
但有一得, 却也有一失, 由於每个程式的定址空间是独立的, 便造成了程式之间共用资料的困难,为了共用资料, 最普遍的解决方式是利用「记忆体对映档案」(Memory Mapped File)或是 ActiveX EXE 来达到资料共用的目的, 但这两种解决方案都不算简单, 而本期我们介绍的登录资料库正是一个简单的资料共用方法,只要程式之间讲好资料存放在哪一个 Key 及 Value 之下, 就可以利用本文所介绍的函数存取资料而达到共用的目的。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -