2009年12月21日, 1:27 下午

Loading ...
2009年07月22日, 2:09 下午

Loading ...
本文来源于Microsoft知识库文章How To Use the Registry API to Save and Retrieve Setting,仅供参考。
虽然VB包括用来从注册表中保存和恢复信息的函数SaveSetting和GetSetting,但是这些函数仅操作注册表的特定部分,即HKEY_CURRENT_USER根键下的Visual Basic and VBA Program Settings。
下面的内容介绍了可以用于从注册表的任意位置设置和恢复值的32位Windows API函数。
注册表概述
应用程序和Windows使用注册表存储配置数据,取代了Windows 3.x中大量的INI文件。注册表使用像树一样的键和值的层级系列来组织。每个键都以六个预定义的根键开始,具有与其相关的子键和值。这些键是有组织的且命名的单元,像文件的文件夹一样出现在Windows注册表编辑器中。值是数据项,作为文本项出现在注册表编辑器窗口的右侧。键不需要有相关的值,但可能也有很多相关的值,每个值有一个相关的数据类型。两个最常用的注册表数据类型是:REG_SZ,一个空结尾的字符串;REG_DWORD,一个32位数值。
用于从注册表的某位置写或读的基本过程是相同的。要引用任何提供的键或值,必须有一个对该键的句柄。一旦获得了该项句柄,这个句柄指定的键的值和子键可以被读取、设置或列举(枚举)。
提供了注册表中的某位置,要获取该键的句柄,必须以六个预定义键开始(HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_CONFIG, and HKEY_DYN_DATA),展开注册表树直至到达期望的键。用户程序最经常从HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE中读和写。如果某注册表键已经存在,那么可以使用对RegOpenKey或RegOpenKeyEx函数的一系列调用。如果需要创建注册表键,那么就使用RegCreateKey和RegCreateKeyEx函数。
使用期望的键的句柄,这些函数用于列出、设置和恢复要调用的信息。在所有情况下,带有Ex后缀的函数仅能在32位平台中使用,没有后缀的函数可以在16位和32位Windows中使用。注意,不是所有没有“Ex”后缀的注册表函数都是为16位兼容所提供的,Ex后缀仅添加在16位函数的功能被扩展的函数里。全新的且专为32位平台的函数不具有Ex扩展。
RegSetValue和RegSetValueEx函数允许修改值的设置,RegQueryValue和RegQueryValueEx函数检索值的当前设置。这里,这些非Ex、16位版的APIs的局限是非常明显的。当使用16位的RegSetValue函数时,没有办法命名值,因此RegSetValue不能用于与每个键的多个值相关联。此外,所有使用RegSetValue写入的值具有REG_SZ数据类型。这些局限是16位注册表固有的。RegSetValueEx允许创建具有任何可用数据类型的多个值。
如何写入指定的注册表位置
确定需要使用的函数后,从下文中复制相关的声明,并粘贴到标准模块。所包含的两个VB过程封装了RegSetValueEx和RegQueryValueEx API函数,极大地简化了其使用。下面利用了这些VB函数,然而,如果愿意则可以自由地直接调用API。
1、创建/修改键和值
使用可用的声明和过程,可以创建和打开键,并且添加、修改和读取值。下面介绍如何创建键,设置或修改值,以及查询值。
2、创建新键
使用下面的过程很容易创建新键。CreateNewKey过程接受要创建的键名,以及代表要创建的键下预定义键的常量。对RegCreateKeyEx的调用没有利用安全机制允许,但可以修改,这已经超出了本文讨论的范围。
Private Sub CreateNewKey(sNewKeyName As String, lPredefinedKey As Long)
Dim hNewKey As Long '新键的句柄
Dim lRetVal As Long 'RegCreateKeyEx函数的结果
lRetVal = RegCreateKeyEx(lPredefinedKey, sNewKeyName, 0&, _
vbNullString, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, _
0&, hNewKey, lRetVal)
RegCloseKey (hNewKey)
End Sub
使用下面的语句调用该过程:
CreateNewKey "TestKey", HKEY_LOCAL_MACHINE
立即在HKEY_LOCAL_MACHINE下创建一个名为TestKey的键。
使用下面的语句调用该过程:
CreateNewKey "TestKey\SubKey1\SubKey2", HKEY_LOCAL_MACHINE
立即在HKEY_LOCAL_MACHINE下以TestKey开始创建三层嵌套的键,SubKey1隶属于TestKey,SubKey3在SubKey2之下。
3、设置/修改值
使用下面简单的过程就可以成功创建和设置指定键的值。SetKeyValue过程接受相关值的键、值的名称、值的设置、以及值的类型(SetValueEx函数仅支持REG_SZ和REG_DWORD,但如果需要可以修改)。为已存在的sValueName指定新值将修改该值的当前设置。
Private Sub SetKeyValue(sKeyName As String, sValueName As String, _
vValueSetting As Variant, lValueType As Long)
Dim lRetVal As Long 'SetValueEx函数的结果
Dim hKey As Long '打开键的句柄
'打开指定的键
lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
KEY_SET_VALUE, hKey)
lRetVal = SetValueEx(hKey, sValueName, lValueType, vValueSetting)
RegCloseKey (hKey)
End Sub
调用代码如下:
SetKeyValue "TestKey\SubKey1", "StringValue", "Hello", REG_SZ
创建一个名为“StringValue”的REG_SZ类型的值,其设置为“Hello”,该值将与TestKey的SubKey1键相关。
此时,“TestKey”是HKEY_CURRENT_USER的子键,但可以通过改变对RegOpenKeyEx的调用来修改。如果“TestKey\SubKey1”不存在,那么该调用将失败。为了避免这类问题,使用对RegCreateKeyEx的调用来代替对RegOpenKeyEx的调用。如果已经存在的话,RegCreatKeyEx将打开指定的键。
4、查询值
下面的过程可以用于确定现有值的设置。QueryValue过程接受键的名称和与该键相关的值的名称,并且显示一个带有相应值的消息框。使用了对下面定义的QueryValueEx封装函数的调用,仅支持REG_SZ和REG_DWORD类型。
Private Sub QueryValue(sKeyName As String, sValueName As String)
Dim lRetVal As Long 'API函数的结果
Dim hKey As Long '打开的键的句柄
Dim vValue As Variant '查询的值的设置
lRetVal = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyName, 0, _
KEY_QUERY_VALUE, hKey)
lRetVal = QueryValueEx(hKey, sValueName, vValue)
MsgBox vValue
RegCloseKey (hKey)
End Sub
使用下面的语句调用该过程:
QueryValue "TestKey\SubKey1", "StringValue"
显示一个带有“StringValue”值的当前设置的消息框,假设在“TestKey\SubKey1”键中存在“StringValue”。
如果查询的值不存在,那么QueryValue将返回错误代码:2-’ERROR_BADKEY’。
5、其他
上面的示例专门使用了扩展的32位版本的注册表函数,这些函数允许每个键关联多个值。正如上面所讲述的,16位的RegSetValue和RegQueryValue只作用于当前键相关的单个值(总是REG_SZ类型)。这些函数在32位注册表编辑器中显示为。要设置、修改或查询这个特定相关的值,必须使用16位注册表函数。从16位环境的注册表中读和写比32位环境更简单。相同的基本过程如下:打开键,获取句柄,然后调用修改函数处理该句柄,但是无须考虑多个相关的值或不同的值的数据类型。16位应用程序可以使用RegCreateKey、RegOpenKey、RegQueryValue、RegSetValue和RegCloseKey的声明来创建和修改键和值。
有时,不需要与某键相关的多个值,应用程序可能仅需要知道是否存在某个键或值,不会关心键的值的性质。此时,可以使用RegEnumKey、RegEnumKeyEx和RegEnumValue函数确定是否存在某个键或值。
API函数和常量声明
Public Const REG_SZ As Long = 1
Public Const REG_DWORD As Long = 4
Public Const HKEY_CLASSES_ROOT = &H80000000&
Public Const HKEY_CURRENT_USER = &H80000001&
Public Const HKEY_LOCAL_MACHINE = &H80000002&
Public Const HKEY_USERS = &H80000003&
Public Const ERROR_NONE = 0
Public Const ERROR_BADDB = 1
Public Const ERROR_BADKEY = 2
Public Const ERROR_CANTOPEN = 3
Public Const ERROR_CANTREAD = 4
Public Const ERROR_CANTWRITE = 5
Public Const ERROR_OUTOFMEMORY = 6
Public Const ERROR_ARENA_TRASHED = 7
Public Const ERROR_ACCESS_DENIED = 8
Public Const ERROR_INVALID_PARAMETERS = 87
Public Const ERROR_NO_MORE_ITEMS = 259
Public Const KEY_QUERY_VALUE = &H1
Public Const KEY_SET_VALUE = &H2
Public Const KEY_ALL_ACCESS = &H3F
Public Const REG_OPTION_NON_VOLATILE = 0
Declare Function RegCloseKey Lib "advapi32.dll" _
(ByVal hKey As Long) As Long
Declare Function RegCreateKeyEx Lib "advapi32.dll" Alias _
"RegCreateKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _
ByVal Reserved As Long, ByVal lpClass As String, ByVal dwOptions _
As Long, ByVal samDesired As Long, ByVal lpSecurityAttributes _
As Long, phkResult As Long, lpdwDisposition As Long) As Long
Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias _
"RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, _
ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As _
Long) As Long
Declare Function RegQueryValueExString Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
As String, lpcbData As Long) As Long
Declare Function RegQueryValueExLong Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, lpData As _
Long, lpcbData As Long) As Long
Declare Function RegQueryValueExNULL Lib "advapi32.dll" Alias _
"RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As _
String, ByVal lpReserved As Long, lpType As Long, ByVal lpData _
As Long, lpcbData As Long) As Long
Declare Function RegSetValueExString Lib "advapi32.dll" Alias _
"RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
ByVal Reserved As Long, ByVal dwType As Long, ByVal lpValue As _
String, ByVal cbData As Long) As Long
Declare Function RegSetValueExLong Lib "advapi32.dll" Alias _
"RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, _
ByVal Reserved As Long, ByVal dwType As Long, lpValue As Long, _
ByVal cbData As Long) As Long
SetValueEx和QueryValueEx封装函数:
Public Function SetValueEx(ByVal hKey As Long, sValueName As String, _
lType As Long, vValue As Variant) As Long
Dim lValue As Long
Dim sValue As String
Select Case lType
Case REG_SZ
sValue = vValue & Chr$(0)
SetValueEx = RegSetValueExString(hKey, sValueName, 0&, _
lType, sValue, Len(sValue))
Case REG_DWORD
lValue = vValue
SetValueEx = RegSetValueExLong(hKey, sValueName, 0&, _
lType, lValue, 4)
End Select
End Function
Function QueryValueEx(ByVal lhKey As Long, ByVal szValueName As _
String, vValue As Variant) As Long
Dim cch As Long
Dim lrc As Long
Dim lType As Long
Dim lValue As Long
Dim sValue As String
On Error GoTo QueryValueExError
' 确定读取的数据类型和大小
lrc = RegQueryValueExNULL(lhKey, szValueName, 0&, lType, 0&, cch)
If lrc <> ERROR_NONE Then Error 5
Select Case lType
' 字符串
Case REG_SZ:
sValue = String(cch, 0)
lrc = RegQueryValueExString(lhKey, szValueName, 0&, lType, _
sValue, cch)
If lrc = ERROR_NONE Then
vValue = Left$(sValue, cch - 1)
Else
vValue = Empty
End If
' DWORDS
Case REG_DWORD:
lrc = RegQueryValueExLong(lhKey, szValueName, 0&, lType, _
lValue, cch)
If lrc = ERROR_NONE Then vValue = lValue
Case Else
'所有不支持的其它数据类型
lrc = -1
End Select
QueryValueExExit:
QueryValueEx = lrc
Exit Function
QueryValueExError:
Resume QueryValueExExit
End Function
2009年07月13日, 1:02 下午

Loading ...
可以使用注册表来存储应用程序的初始和配置的设置。VBA允许读写下列注册表路径中的注册表设置:
\HKEY_CURRENT_USER\Software\VB and VBA Program Settings\{子键}
要在这个注册表路径中读取注册表设置,使用GetSetting函数。要写入注册表设置到该注册表路径中,使用SaveSetting函数。注意,不正确地修改注册表会导致严重的后果,甚至需要重新安装操作系统。
GetSetting函数和SaveSetting函数的语法如下:
SaveSetting(AppName,Section,Key,Setting)
GetSetting(AppName,Section,Key[,Default])
其中:
- 参数AppName必需,String类型,指定VB and VBA Program Settings键的子键;
- 参数Section必需,String类型,在参数AppName中指定的键的子键;
- 参数Key必需,String类型,在参数Section中指定的键的值;
- 参数Setting必需,String类型或数值型,存储在参数Key指定的值中的一块数据;
- 参数default可选,String类型,指定当参数Key中没有设置值时返回的数据。
使用DeleteSetting函数删除子键或值,其语法为:
DeleteSetting(AppName[,Section[,Key]]
其中的参数与上述相同。
下面的示例代码创建带有两个值的子键,列出它们的值,然后删除子键并再次试图列出它们的值。
'演示VBA SaveSetting函数和GetSetting函数的使用
Public Sub TestRegistryFunctions()
'创建带有两个值的子键
SaveSetting AppName:="MyApp", Section:="MySection", _
Key:="MyKey", Setting:="MySetting"
SaveSetting AppName:="MyApp", Section:="MySection", _
Key:="MyKey2", Setting:="MySetting2"
'显示"MySetting"和"MySetting2"
MsgBox Prompt:=GetSetting(AppName:="MyApp", _
Section:="MySection", Key:="MyKey")
MsgBox Prompt:=GetSetting(AppName:="MyApp", _
Section:="MySection", Key:="MyKey2")
'删除子键
DeleteSetting AppName:="MyApp"
'显示空字符串
MsgBox Prompt:=GetSetting(AppName:="MyApp", _
Section:="MySection", Key:="MyKey")
MsgBox Prompt:=GetSetting(AppName:="MyApp", _
Section:="MySection", Key:="MyKey2")
End Sub
关于GetSetting函数和SaveSetting函数的一些说明
- 如果忽略GetSetting函数中的参数Default,则认为是一个零长字符串(”")。
- 参数Section可以是一个嵌套子键的路径,每个子键与其父键之间使用反斜杠隔开。例如,如果参数Section的值为Settings\Coordinates,则表明从HKEY_CURRENT_USER\Software\VB and VBA Program Settings\[AppName]\Settings\Coordinates中检索值。
- SaveSetting函数不允许改变注册表项的缺省值,否则会产生运行时错误。
下面再看一个示例:
Sub TestTheReg()
SaveSetting "MyRealGoodApp", _
"TestBranch\SomeSection\AnotherSection", _
"TestKey", "10"
MsgBox "现在看看注册表"
End Sub
Sub TestDelete()
If GetSetting("MyRealGoodApp", _
"TestBranch\SomeSection\AnotherSection", _
"") = "" Then
DeleteSetting "MyRealGoodApp", _
"TestBranch\SomeSection\AnotherSection", _
"TestKey"
MsgBox "再看看注册表"
End If
End Sub
关于DeleteSetting函数的一些说明
- 不能使用DeleteSetting函数从注册表的主键里删除那些不是HKEY_CURRENT_USER\Software\VB and VBA Program Settings的子键的项。
- 如果提供了参数Key,那么只有名为Key的项及其关联的值被删除;如果忽略了参数Key,那么参数Section指定的子键将被删除;如果忽略了参数Section,那么参数AppName的键将被全部删除。
- DeleteSetting函数不能删除属于任何键的缺省值。
下面再看一个示例,代码如下:
Sub ExperimentWithRegistry()
Dim vaKeys As Variant
'创建新的注册表项
SaveSetting "XLTest", "General", "App_Name", "XLTest"
SaveSetting "XLTest", "General", "App_Version", "1.0.0"
SaveSetting "XLTest", "General", "App_Date", "10/11/2003"
PrintRegistrySettings
'更新设置
SaveSetting "XLTest", "General", "App_Version", "1.0.1"
PrintRegistrySettings
'获取所有的设置
vaKeys = GetAllSettings("XLTest", "General")
PrintAllSettings vaKeys
'删除设置
DeleteSetting "XLTest", "General", "App_Name"
DeleteSetting "XLTest", "General", "App_Version"
DeleteSetting "XLTest", "General", "App_Date"
PrintRegistrySettings
End Sub
Sub PrintRegistrySettings()
On Error Resume Next
Debug.Print "应用程序名:" & _
GetSetting("XLTest", "General", "App_Name")
Debug.Print "应用程序版本:" & _
GetSetting("XLTest", "General", "App_Version")
Debug.Print "应用程序日期:" & _
GetSetting("XLTest", "General", "App_Date")
Debug.Print "------------------------------"
End Sub
Sub PrintAllSettings(vaSettings As Variant)
Dim nItem As Integer
If IsArray(vaSettings) Then
For nItem = 0 To UBound(vaSettings)
Debug.Print vaSettings(nItem, 0) & ": " & _
vaSettings(nItem, 1)
Next
End If
Debug.Print "------------------------------"
End Sub
其中,使用GetAllSettings函数可以获取某应用程序的一系列键。该函数返回一个二维的Variant型数组,其第一维表示返回的设置,第二维则返回键名或键值。
参考资料:
MSDN,Paul Cornell《Ten Tips for Microsoft Office VBA Library Development》
Paul Lomax,《VB & VBA in a Nutshell:the Language》
Steven M. Hansen,《Mastering Excel 2003 Programming with VBA》
2009年03月19日, 12:41 下午

Loading ...
这是在MS Office Gurus中看到的一个很有趣的技巧,但说实在的,不怎么实用。既然有趣,那还是介绍一下吧。
在Office 2007中,Microsoft引入了“Office按钮”,位于界面的左上角,其功能与以前版本的“文件”菜单相似。当单击该按钮时,会出现处理文件的功能,诸如新建、打开、保存、另存为、打印……等等。
使用下面的方法,能够使Office按钮闪烁,以引起用户的注意,如下图所示。

一旦在该按钮上单击后,将停止闪烁。在MS Office Gurus中,作者使用一个2分多钟的视频介绍了实现这种效果的方法。这里总结如下:
1、在桌面单击“开始——运行”。
2、输入regedit.exe,打开注册表编辑器。
3、单击HKEY_CURRENT_USER。
4、在左侧的目录树中找到Software\Microsoft\Office\12.0\Common\General。
5、在右侧的窗口中找到OfficeMenuDiscovered并双击,在出现的“编辑DWORD值”对话框中将其值改为0,单击“确定”并退出注册表编辑器。
此时,若开启Office 2007,则Office按钮会闪烁,直到您单击它。这是一次性的操作,即修改该值后第一次开启Office 2007应用程序,会使Office按钮闪烁,单击Office按钮后,停止闪烁,注册表中相应的健值也会恢复,再开启Office应用程序,Office按钮不会再闪烁。
2009年03月18日, 12:52 下午

Loading ...