Win32汇编操作注册表

摘要:
RegOpenKeyEx函数用于打开子密钥。Win16中也有一个RegOpenKey函数。尽管Win32中仍然存在此函数,但它仅为兼容性目的而设置。此选项仅对Windows NT系统有效,在9x系统中被忽略。Reg.asm文件中的大多数子程序首先使用RegOpenKeyEx函数为下一个操作打开子键,但RegSetValue子程序中使用了_RegCreateKeyEx功能,因此当子键被保存时

1.打开和关闭子键

注册表函数对注册表的操作是通过句柄来完成的,与文件操作一样,在对某个键下的子键或者键值项进行操作之前,需要先将这个键打开,然后使用键句柄来引用这个键,在操作完毕以后再将键句柄关闭。注册表的根键不需要打开,它们的句柄是固定不变的,要使用根键的时候只要把这些句柄直接拿来用就是了,Windows.inc中已经预定义了它们的数值:

HKEY_CLASSES_ROOT equ 80000000h

HKEY_CURRENT_USER equ 80000001h

HKEY_LOCAL_MACHINE equ 80000002h

HKEY_USERS equ 80000003h

HKEY_PERFORMANCE_DATA equ 80000004h

HKEY_CURRENT_CONFIG equ 80000005h

HKEY_DYN_DATA equ 80000006h

在程序中可以随时将这些助记符当做句柄来引用对应的根键。在程序结束的时候,不需要关闭这些根键句柄。

打开子键使用RegOpenKeyEx函数,在Win16中还存在一个RegOpenKey函数,虽然在Win32中这个函数仍然存在,但这仅是为了兼容的目的而设置的。API手册中推荐使用RegOpenKeyEx函数:

invoke RegOpenKeyEx,hKey,lpSubKey,dwOptions,samDesired,phkResult

函数的hKey参数指定父键句柄,lpSubKey指向一个字符串,用来表示要打开的子键名称,在系统中一个子键的全称是以“根键\第1层子键\第2层子键\第n层子键”类型的字符串表示的,中间用“\”隔开,字符串的最后以0字符结束,这和目录名的表示方法是很像的。

既然子键的全称是这样表示的,那么要打开一个子键的时候,下面的两种表示方法有什么不同呢?

1)父键=HKEY_LOCAL_MACHINE,子键=Software\RegTest\MySubkey

2)父键=HKEY_LOCAL_MACHINE\Software,子键=RegTest\MySubkey

答案是:这两种表示方法是完全相同的。在使用RegOpenKeyEx函数打开子键的时候,既可以将hKey参数设置为HKEY_LOCAL_MACHINE根键的句柄,并将lpSubKey参数指向“Software\RegTest\MySubkey”字符串;也可以将hKey参数设置为“HKEY_LOCAL_ MACHINE\Software”的句柄,将lpSubKey参数指向“RegTest\MySubkey”字符串,得到的结果是一样的。但是,使用第一种方法时,hKey参数可以直接使用助记符HKEY_LOCAL_ MACHINE来表示,因为根键的句柄是固定的,不需要打开;而使用第二种方法时,还需要先打开“HKEY_LOCAL_MACHINE\Software”键来获取它的句柄,所以具体使用哪种方法还要根据具体情况灵活选用。

函数的其他几个参数的含义如下。

dwOptions参数——系统保留参数,必须指定为0。

samDesired参数——子键的打开方式,根据使用子键的方式,可以设置为下列取值的组合,只有指定了打开的方式,才能在打开子键后进行相应的操作:

KEY_ALL_ACCESS——允许所有的存取。

KEY_CREATE_LINK——允许建立符号列表。

KEY_CREATE_SUB_KEY——允许建立下一层子键。

KEY_ENUMERATE_SUB_KEYS——允许枚举下一层子键。

KEY_EXECUTE——允许读操作。

KEY_QUERY_VALUE——允许查询键值数据。

KEY_READ—KEY_QUERY_VALUE,KEY_ENUMERATE_SUB_KEYS和KEY_ NOTIFY的组合。

KEY_SET_VALUE——允许修改或创建键值数据。

KEY_WRITE——KEY_SET_VALUE和KEY_CREATE_SUB_KEY的组合。

phkResult参数——指向一个双字变量,函数在这里返回打开的子键句柄。

如果函数执行成功,返回值是ERROR_SUCCESS,并且函数在phkResult参数指向的变量中返回子键句柄。

当不再需要继续使用键句柄的时候,可以使用RegCloseKey函数将它关闭:

invoke RegCloseKey,hKey

如果句柄被成功关闭,函数返回ERROR_SUCCESS。



2.创建和删除子键

创建一个子键可以使用RegCreateKeyEx函数:

invoke RegCreateKeyEx,hKey,lpSubKey,Reserved,lpClass,dwOptions,\

samDesired,lpSecurityAttributes,phkResult,lpdwDisposition

函数中与RegOpenKeyEx函数中同名参数的含义和用法是相同的,hKey也是用来指定父键句柄,lpSubKey指向要创建的子键名称字符串,samDesired参数指明子键建立后的操作方式,phkResult指向用来返回键句柄的双字变量。

其余一些参数的含义如下。

Reserved参数——保留参数,必须设置为0。

lpClass参数——为创建的子键定义一个类名,这个参数一般设置为NULL。

dwOptions参数——创建子键时的选项,它可以是以下取值之一:

REG_OPTION_NON_VOLATILE——默认值,子键被创建到注册表文件中。

REG_OPTION_VOLATILE——创建易失性的子键,子键被保存在内存中,当系统重新启动的时候,子键消失。这个选项仅对Windows NT系统有效,在9x系统中被忽略。

lpSecurityAttributes参数——指向一个SECURITY_ATTRIBUTES结构,用来指定键句柄的继承性,如果句柄不需要被继承,可以使用NULL。

lpdwDisposition参数——这个参数一般使用NULL。

当需要创建的子键已经存在的时候,函数仅起到RegOpenKeyEx函数的作用;如果子键不存在,那么函数将创建子键。如果函数执行成功,返回值是ERROR_SUCCESS。

如果要创建“HKEY_LOCAL_MACHINE\Key1\Key2\Key3”子键,既可以将hKey参数设置为HKEY_LOCAL_MACHINE,将lpSubKey参数指向“Key1\Key2\Key3”字符串;也可以先打开“HKEY_LOCAL_MACHINE\Key1”键,将hKey设置为打开的键句柄,然后将lpSubKey参数指向“Key2\Key3”字符串,这和RegOpenKeyEx函数中的用法是类似的。在第二种用法中,打开父键的时候注意要指定KEY_CREATE_SUB_KEY方式。

当被创建子键的上层键不存在的时候,函数连上层的子键一起创建。如上面的例子中,假如Key2也不存在,那么函数先在“HKEY_LOCAL_MACHINE\Key1”下创建Key2,然后在Key2下继续创建Key3。

_Reg.asm文件中的大部分子程序首先用RegOpenKeyEx函数打开子键以便进行下一步操作,但是保存键值用的_RegSetValue子程序中使用的是RegCreateKeyEx函数,这样当子键已经存在的时候,函数仅打开它,如果子键不存在的话则创建子键。

删除子键使用RegDeleteKey函数:

invoke RegDeleteKey,hKey,lpSubKey

hKey参数为父键句柄,lpSubKey参数指向要删除的子键名称字符串。函数仅删除最后一层子键以及下面的全部键值项。比如在“HKEY_LOCAL_MACHINE\Key1\Key2\Key3”子键存在的情况下,当hKey指定为HKEY_LOCAL_MACHINE,lpSubKey指向“Key1\Key2\Key3”的时候,函数仅删除Key3子键,不会连同Key2,Key1全部删除。但如果Key3子键下有键值项的话,这些键值项会被一起删除。

如果要删除的子键下还存在下一层子键,比如上例中的Key3子键下还存在Key4子键,那么对Key3子键进行删除时,Windows 9x和Windows NT系统的做法是不同的:在Windows 9x中,Key3子键本身、Key3子键下所有的键值项和下层子键(包括上面举例的Key4)会被全部删除;而在Windows NT中,只有在不存在下层子键的情况下删除才能成功,如果Key3子键下还存在Key4子键,那么对Key3子键的删除是不会成功的。

应用程序不能直接在HKEY_LOCAL_MACHINE根键下面创建和删除子键,只能在下一层由系统定义的子键下进行操作,如果要保存配置信息的话,用户应用程序一般在HKEY_LOCAL_MACHINE\SOFTWARE子键下再创建自己的子键,然后将键值项保存在自己的子键中。

3 管理键值

配置信息是存放在键值项中的,打开或者创建一个键的最终目的都是为了在键下面存取键值项,这就像磁盘上的目录是用来合理组织和管理文件用的,数据还是存放在文件中的。当使用打开或者创建键的函数得到键句柄后,就可以通过它来存取键值项了。

3.1设置键值项

在一个键下面设置和创建键值项使用RegSetValueEx函数:

invoke RegSetValueEx,hKey,lpValueName,Reserved,dwType,lpData,cbData

hKey参数指定一个键句柄,键值项将保存在这个键下,lpValueName参数指向定义键值项名称的字符串。假如lpValueName参数指向一个空串或者设置为NULL,并且设置的键值类型是REG_SZ的话,那么函数设置的是键的默认值(图15.2中所示的“默认”项)。

Reserved参数是保留的,必须设置为0。

dwType参数指出了要设置的键值数据的类型,可以使用的类型如表15.1所示。

lpData参数是一个指针,指向包含键值数据的缓冲区,cbData参数为要保存的数据长度。缓冲区中的数据格式以及cbData参数指定的数据长度需要和dwType参数指出的键值类型相对应,比如要设置REG_SZ类型的键值项,就要将cbData参数设置为字符串的长度+1(加上尾部的0);同样对于REG_MULTI_SZ类型的键值项来说,最后的两个0的长度都必须包括到cbData参数中;对于REG_DWORD类型的键值项,需要将双字数据放在缓冲区中并将cbData参数设置为4(不像其他函数一样当参数是双字的时候一般将双字在参数中直接传递)。

当子键中的键值项不存在的时候,函数新建键值项;当键值项已经存在的时候,函数将新的键值数据写入。如果键值数据保存成功,函数返回ERROR_SUCCESS。

虽然键值数据的最大长度没有规定,其大小仅受限于可用的内存大小,应用程序甚至可以使用REG_BINARY格式的键值项将整个文件都保存到注册表中,但在实际的使用中还是建议不要将大于2 KB的数据放到注册表中,因为这将影响注册表的使用效率。

要在一个键中创建或修改键值项,键的打开方式中必须包括KEY_SET_VALUE方式。

3.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.3 删除键值项

删除一个键值项的操作则比较简单,使用RegDeleteValue函数就可以了:

invoke RegDeleteValue,hKey,lpValueName

hKey参数和lpValueName指定父键句柄和被删除键值项的名称。惟一需要注意的是父键句柄的打开方式必须包括KEY_SET_VALUE。如果键值项被成功删除,则函数返回ERROR_SUCCESS。

4 子键和键值的枚举

在实际的应用中往往需要对一个键下的子键或者键值项进行列表操作,就像在DOS系统下常用Dir命令一样,这就要用到子键和键值的枚举函数。在注册表函数中,枚举子键和枚举键值项使用的函数是不一样的,不像FindFirstFile等文件列表函数那样将文件连同子目录混在一起列出来。下面分别介绍这两种函数。

4.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)。

4.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方式。


4.3 查询键属性

在枚举子键和键值项的时候往往会遇到这样一个问题:注册表函数对键值数据的长度并没有限制,在预留缓冲区的时候如果申请太大的内存比较浪费,申请太小的内存则无法枚举成功,对于返回的子键名称和键值项名称也是如此。那么,究竟该留多大的缓冲区呢?其实在枚举之前可以先用RegQueryInfoKey函数查看一下键的统计信息。

RegQueryInfoKey函数返回的信息有:一个键下面子键的数量、键值项的数量、子键名称和键值名称字符串的最大长度及键值数据的最大长度等。根据这些信息,就能方便地申请足够大的缓冲区来保证枚举成功。函数还能返回创建子键时指定的类名和最后一次写入子键的时间等信息。

RegQueryInfoKey函数的用法是:

invoke RegQueryInfoKey,hKey,lpClass,lpcbClass,lpReserved,\

lpcSubKeys,lpcbMaxSubKeyLen,lpcbMaxClassLen,\

lpcValues,lpcbMaxValueNameLen,lpcbMaxValueLen,\

lpcbSecurityDescriptor,lpftLastWriteTime

函数的参数比较多,但并不复杂,各参数的含义是:

●hKey—指定要获取信息的键句柄,键的打开方式中必须包括KEY_QUERY_VALUE。

●lpClass——指向一个缓冲区,用来返回创建键时指定的Class字符串。

●lpcbClass——指向一个双字变量,调用函数时变量中必须放入lpClass指定的缓冲区的长度,函数返回时在这里放入返回到缓冲区中的字符串长度。

●lpReserved——保留参数,必须设置为0。

●lpcSubKeys——指向一个双字,用来返回键中的子键数量。

●lpcbMaxSubKeyLen——指向一个双字,用来返回所有子键中最长的名称字符串长度,返回的长度不包括字符串结尾的0字符。

●lpcbMaxClassLen——指向一个双字,用来返回所有子键中最长的Class字符串长度,返回的长度不包括字符串结尾的0字符。

●lpcValues——指向一个双字,用来返回键下面的键值项数量。

●lpcbMaxValueNameLen——指向一个双字,用来返回所有键值项中最长的名称字符串长度,返回的长度不包括字符串结尾的0字符。

●lpcbMaxValueLen——指向一个双字,用来返回所有键值数据的最大长度。

●lpcbSecurityDescriptor——指向一个双字,用来返回安全描述符的长度。

●lpftLastWriteTime——指向一个FILETIME结构,用来返回最后一次修改键的时间。

可以看到,除hKey外其他的参数都是指针,指向用来返回数据的变量或结构,如果不需要返回某种信息的话,可以将对应的指针参数设置为NULL。另外,所有返回的最长名称字符串长度中都不包括结尾的0字符。

除了前面介绍的函数外,系统中还存在一些不常用的注册表函数,比如可以用RegLoadKey和RegReplaceKey 函数从指定的文件中恢复注册表的子键信息,也可以通过RegSaveKey函数将键信息保存到指定的文件中。另外,可以通过RegConnectRegistry等函数操作远程注册表。对于这些函数,本节就不详细介绍了。



---------------------------------------------------------------------------------------------------------------------------------------

为了让读者不经修改就可以将这些子程序用在其他程序中,将这些注册表子程序放在一个单独的_Reg.asm文件中并在主程序中使用include语句包含进来,文件内容如下:


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;查询键值

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RegQueryValue proc _lpszKey,_lpszValueName,\

_lpszValue,_lpdwSize,_lpdwType

local @hKey,@dwReturn

mov @dwReturn,-1

invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,_lpszKey,NULL,\

KEY_QUERY_VALUE,addr @hKey

.if eax == ERROR_SUCCESS

invoke RegQueryValueEx,@hKey,_lpszValueName,NULL,\

_lpdwType,_lpszValue,_lpdwSize

mov @dwReturn,eax

invoke RegCloseKey,@hKey

.endif

mov eax,@dwReturn

ret

_RegQueryValue endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;设置键值

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RegSetValue proc _lpszKey,_lpszValueName,_lpszValue,\

_dwValueType,_dwSize

local @hKey

invoke RegCreateKey,HKEY_LOCAL_MACHINE,_lpszKey,addr @hKey

.if eax == ERROR_SUCCESS

invoke RegSetValueEx,@hKey,_lpszValueName,NULL,\

_dwValueType,_lpszValue,_dwSize

invoke RegCloseKey,@hKey

.endif

ret

_RegSetValue endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;创建子键

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RegCreateKey proc _lpszKey,_lpszSubKeyName

local @hKey,@hSubkey,@dwDisp

invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,_lpszKey,NULL,\

KEY_CREATE_SUB_KEY,addr @hKey

.if eax == ERROR_SUCCESS

invoke RegCreateKeyEx,@hKey,_lpszSubKeyName,NULL,\

NULL,NULL,NULL,NULL,addr @hSubkey,addr @dwDisp

invoke RegCloseKey,@hKey

invoke RegCloseKey,@hSubkey

.endif

ret

_RegCreateKey endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;删除键值

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RegDelValue proc _lpszKey,_lpszValueName

local @hKey

invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,_lpszKey,NULL,\

KEY_WRITE,addr @hKey

.if eax == ERROR_SUCCESS

invoke RegDeleteValue,@hKey,_lpszValueName

invoke RegCloseKey,@hKey

.endif

ret

_RegDelValue endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;删除子键

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_RegDelSubKey proc _lpszKey,_lpszSubKeyName

local @hKey

invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,_lpszKey,NULL,\

KEY_WRITE,addr @hKey

.if eax == ERROR_SUCCESS

invoke RegDeleteKey,@hKey,_lpszSubKeyName

invoke RegCloseKey,@hKey

.endif

ret

_RegDelSubKey endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

form:http://blog.csdn.net/cyg0810/article/details/7771902

免责声明:文章转载自《Win32汇编操作注册表》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇黄聪:Delphi 中的 XMLDocument 类详解(17) 上一个节点、下一个节点、父节点Delphi动态创建菜单下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C++ 常见崩溃问题分析

一、前言 从事自动化测试平台开发的编程实践中,遭遇了几个程序崩溃问题,解决它们颇费了不少心思,解决过程中的曲折和彻夜的辗转反侧却历历在目,一直寻思写点东西,为这段难忘的经历留点纪念,总结惨痛的教训带来的经验,以期通过自己的经历为他人和自己带来福祉:写出更高质量的程序; 由于 C 和 C++ 这两种语言血缘非常近,文本亦对 C 编程语言有借鉴作用; 二、C+...

【转】MS Sql server 日期转换为特定字符串格式

愕然发现,sqlserver和oracle里对数据类型的转换还是有不少差异的。目前项目是sqlserver,需要用到,因此拿捏了过来,转一下,哈哈。作为备份吧。 正文: 日期格式化函数:Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect CONVERT(varchar(1...

【DLL相关】实现函数的DLL封装,并在另一个项目中调用

直接给出步骤: ===========函数的DLL封装=========== 1.创建第一个项目:win32控制台程序,应用程序类型:DLL,附加选项:导出符号(命名:double_dll) 2.double_dll.h中加入函数定义   extern DOUBLE_DLL_API int doublefun(int);//DOUBLE_DLL_API 根...

Qt Quick的国际化和本地化

  国际化您的应用程序 以下部分描述了国际化QML源代码的各个方面。如果您对应用程序中的所有用户界面组件都遵循这些指南,则可以针对不同语言和本地文化约定(例如日期和数字的格式化方式)本地化应用程序的各个方面。 1.对所有Literal用户界面字符串使用qsTr() 可以使用qsTr(),qsTranslate(),qsTrId(),QT_TR_NOOP...

PInvokeStackImbalance, problem tip from MDA

    昨天接到一个bug,说在某一台机器上发现程序在使用IDE调试时会看到一个异常,并显示如下异常信息: A call to PInvoke function 'UnsafeNativeMethods.GetThemeBackgroundRegion' has unbalanced the stack. This is likely because t...

Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解

Graphics View提供了一个界面,它既可以管理大数量的定制2D graphical items,又可与它们交互,有一个view widget可以把这些项绘制出来,并支持旋转与缩放。这个柜架也包含一个事件传播结构,对于在scene中的这些items,它具有双精度的交互能力。Items能处理键盘事件,鼠标的按,移动、释放、双击事件,也可以跟踪鼠标移动。...