WIN32汇编语言教程:第15章 注册表和INI文件 · 15.3 对注册表的操作(6)
2. 查询键值数据
读取键值项中的数据或者查询键值项的属性使用RegQueryValueEx函数,用法如下:
invoke RegQueryValueEx,hKey,lpValueName,lpReserved,\
lpType,lpData,lpcbData
参数hKey和lpValueName用来指定要读取的键值项所处的子键句柄和键值项的名称, lpReserved参数是保留参数,必须使用0。lpData参数指向一个缓冲区,用来接收返回的键值数据。
函数的其余几个参数使用时必须注意的是它们都是指向双字变量的指针,这一点和使用RegSetValueEx函数时是不同的:
● lpType参数——函数在这个参数指向的双字变量中返回读取的键值类型,如果不需要返回键值项的类型,可以将这个参数设置为NULL。
● lpcbData参数——在调用的时候,程序必须在这个参数指向的双字变量中放置缓冲区的长度(并不是直接用lpcbData参数指出缓冲区长度)。当函数返回的时候,双字变量被函数改为返回到缓冲区中的数据的实际长度。
当函数执行成功的时候,函数的返回值是ERROR_SUCCESS。当程序指定的缓冲区长度不足以容纳返回的数据的时候,函数的返回值是ERROR_MORE_DATA,这时lpcbData参数指向的双字变量中返回需要的长度。
如果仅需要查询键值长度而不需要返回实际的数据,可以将lpData参数设置为NULL,但是lpcbData参数不能为NULL,这时函数会在lpcbData参数指向的双字变量中返回键值数据的长度。如果仅想查询键值项的类型,也可以同时将lpcbData和lpData参数设置为NULL。在这些情况下如果函数查询成功,返回值也是ERROR_SUCCESS。
如果要在一个键中查询键值数据的话,键的打开方式中必须包括KEY_QUERY_VALUE方式。
3. 删除键值项
删除一个键值项的操作则比较简单,使用RegDeleteValue函数就可以了:
invoke RegDeleteValue,hKey,lpValueName
hKey参数和lpValueName指定父键句柄和被删除键值项的名称。惟一需要注意的是父键句柄的打开方式必须包括KEY_SET_VALUE。如果键值项被成功删除,则函数返回ERROR_SUCCESS。
15.3.4 子键和键值的枚举
在实际的应用中往往需要对一个键下的子键或者键值项进行列表操作,就像在DOS系统下常用Dir命令一样,这就要用到子键和键值的枚举函数。在注册表函数中,枚举子键和枚举键值项使用的函数是不一样的,不像FindFirstFile等文件列表函数那样将文件连同子目录混在一起列出来。下面分别介绍这两种函数。
1. 枚举子键
例子程序中枚举子键和键值项的操作是在_EnumKey子程序中完成的,读者可以参考一下相应的代码,在这个子程序中,程序首先使用RegEnumKeyEx函数来枚举子键:
invoke RegEnumKeyEx,hKey,dwIndex,lpName,lpcbName,lpReserved,\
lpClass,lpcbClass,lpftLastWriteTime
hKey参数指定被枚举的键句柄,dwIndex参数指定需要返回信息的子键索引编号,lpName指向一个缓冲区,函数在这里返回子键名称,lpClass指向用于返回子键类名的缓冲区,lpftLastWriteTime指向一个FILETIME结构,函数在这里返回子键上一次被写入的时间。lpReserved参数是保留参数,必须设置为0。
要注意的是:lpcbName和lpcbClass指向两个双字变量,调用函数前,这两个双字变量中必须放入lpName和lpClass指定的缓冲区的长度,当函数返回的时候,函数在里面返回实际返回到缓冲区中的字符串的长度。如果函数执行成功,返回值是ERROR_SUCCESS。
RegEnumKeyEx函数每次返回一个子键的名称信息,所以要枚举全部子键的话,必须用循环多次调用这个函数,并且每次将dwIndex参数指定的子键索引号递增,当子键全部被枚举后,继续调用函数将得到一个ERROR_NO_MORE_ITEMS返回值,这时就可以结束循环了。下面是循环的典型写法:
.data
dwIndex dd ?
dwSize dd ?
szBuffer db 256 dup (?)
.code
... ...
mov dwIndex,0
.while TRUE
mov dwSize,sizeof szBuffer
invoke RegEnumKeyEx,hKey,dwIndex,addr szBuffer,addr dwSize,\
NULL,NULL,NULL,NULL
.break .if eax == ERROR_NO_MORE_ITEMS
;处理获取的子键
inc dwIndex
.endw
在循环开始前,程序初始化当做索引用的dwIndex变量,每次调用RegEnumKeyEx后将索引加1,当检测到函数的返回值是ERROR_NO_MORE_ITEMS的时候,使用 .break语句退出循环。程序不使用 .break .if eax != ERROR_SUCCESS语句当做结束循环的条件是因为:当出现缓冲区不够长等意外情况时,函数的调用可能失败,但是这时子键可能还没有全部被枚举,所以只有判断返回值是ERROR_NO_MORE_ITEMS才能保证全部子键被枚举。
每次调用函数之前,程序必须重新将dwSize变量的值设置为szBuffer缓冲区的大小,这是因为每次函数返回时,dwSize中会变成返回的子键名称字符串的长度,如果不重新设置,下一次调用时函数就会将这个长度认为是缓存区的长度。
当进行枚举子键操作时,父键的打开方式中必须包括KEY_ENUMERATE_SUB_KEYS方式(KEY_READ方式中已经包括KEY_ENUMERATE_SUB_KEYS)。
2. 枚举键值
RegEnumKeyEx函数仅枚举一个键下面的全部子键,对键下面的键值项则不会去理会。如果要枚举一个键下面的键值项,那么必须使用RegEnumValue函数:
invoke RegEnumValue,hKey,dwIndex,lpValueName,lpcbValueName,\
lpReserved,lpType,lpData,lpcbData
函数的hKey,dwIndex和lpReserved参数的使用同RegEnumKeyEx函数中的同名参数。其余的一些参数中,lpValueName和lpData参数指向两个缓存区,函数在里面分别返回键值项的名称和数据。lpcbValueName和lpcbData参数指向两个双字变量,调用函数前里面必须放入键值项名称缓冲区和键值数据缓冲区的长度,函数返回后这两个变量的值被改为返回到缓冲区中的数据长度。lpType参数则指向一个用于返回键值数据类型的双字变量。
如果不需要返回键值数据,lpData和lpcbData参数可以设置为NULL,如果不需要返回键值数据类型,lpType参数也可以设置为NULL。
下面是一段典型的用于枚举键值项的循环代码:
.data
dwIndex dd ?
dwType dd ?
dwNameSize dd ?
szName db 256 dup (?)
dwDataSize dd ?
szData db 256 dup (?)
.code
...
mov dwIndex,0
.while TRUE
mov dwNameSize,sizeof szName
mov dwDataSize,sizeof szData
invoke RegEnumValue,hKey,dwIndex,addr szName,\
addr dwNameSize,NULL,addr dwType,\
addr szData,addr dwDataSize
.break .if eax == ERROR_NO_MORE_ITEMS
;处理获取的键值项
inc dwIndex
.endw
这个循环的结构和使用RegEnumKeyEx函数的循环是大同小异的。
要进行枚举键值项的操作,父键的打开方式中必须包括KEY_QUERY_VALUE方式。
上页:第15章 注册表和INI文件 · 15.3 对注册表的操作(5) 下页:第15章 注册表和INI文件 · 15.3 对注册表的操作(7)