⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 015.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:
GetPrivateProfileSectionNames函数可以用来返回全部小节名称的列表:

  invoke  GetPrivateProfileSectionNames,lpBuffer,nSize,lpFileName

lpFileName参数指向INI文件名,lpBuffer参数是一个指针,指向用来返回小节名称列表的缓冲区,nSize参数指定缓冲区的长度。返回到缓冲区中的数据格式也是:“小节名称1,0,小节名称2,0,…,小节名称n,0,0”的格式。当缓冲区太小以至于不能容纳全部数据的时候,后面的数据被丢弃,全部数据被截尾到nSize?2的长度,剩下的两个字节用来保存两个表示结束的0字符。函数的返回值是返回到缓冲区中的数据长度(不包括结尾的0字符)。

GetPrivateProfileSection函数则可以用来返回整个小节的键定义,与上一节介绍的调用GetPrivateProfileString函数时将lpKeyName参数设置为NULL以获取键名列表不同,GetPrivateProfileSection函数返回的是键定义列表。函数的用法是:

  invoke  GetPrivateProfileSection,lpAppName,lpBuffer,nSize,lpFileName

函数的lpAppName指向一个包含小节名称的字符串,返回到缓冲区中的数据格式为:

  键名1=键值1,0,键名2=键值2,0,…,键名n=键值n,0,0

所以,使用这个函数可以同时完成枚举键名和键值的功能。例子程序中就是使用它来枚举键值的,但使用中如果觉得自己处理“键名=键值”字符串来分解键名和键值比较麻烦的话,可以用GetPrivateProfileString函数枚举键名并再次调用它获取指定键的键值。

在Windows 9x中,缓冲区最大不能超过32 767 B,而在Windows NT中则没有限制,函数的返回值是返回到缓存区中的数据长度(不包括结尾的0字符)。

WritePrivateProfileSection函数则将“键名1=键值1,0,键名2=键值2,0,…,键名n=键值n,0,0”格式的小节数据一次性全部写入。函数的用法是:

  invoke  WritePrivateProfileSection,lpAppName,lpString,lpFileName

lpString参数指向包含键值定义列表的缓冲区,函数执行后,指定小节原来的键定义被全部删除,然后加入新的键定义。如果执行成功,函数返回非0值,否则返回0。

15.2.4  使用不同的INI文件

在前面介绍的这些INI文件函数中,当lpFileName参数指定的文件名字符串中不包括路径时,系统将认为文件位于Windows安装目录下,这样当函数创建INI文件的时候,就会把文件创建于Windows安装目录下。但是大部分情况下,希望INI文件位于程序的运行目录下,这样拷贝文件的时候可以连同INI文件一起拷贝,另外,在卸载或删除程序的时候可以避免在Windows目录中留下一个“垃圾”INI文件。

如果希望在程序的运行目录而非Windows目录中建立INI文件,那么最简单的方法就是在INI文件名前面加上“.\”路径,也就是说把文件名写成“.\MyIniFile.ini”的格式,这样系统会在当前目录下建立INI文件。这种方法的缺陷是如果程序运行中需要不断切换当前目录的话,系统就会在不同的地方乱建INI文件。一个常见的情况就是使用“打开文件”通用对话框的时候,系统会将当前目录切换到对话框中浏览的那个目录,这样写INI文件时就会造成INI文件的位置根本无法确定。最保险的办法就是像例子程序中所示的那样,在程序一开始运行的时候就使用GetCurrentDirectory函数获取当前目录,然后将INI文件名添加到目录后组成一个全路径的文件名,以后在所有的操作中都使用这个文件名。

如果要操作的是Windows安装目录下的Win.ini文件而非其他INI文件时,那么既可以使用上面这些函数,也可以使用另一组专门用于操作Win.ini文件的函数,这组函数是:

  invoke  GetProfileString,lpAppName,lpKeyName,lpDefault,lpBuffer,nSize

  invoke  GetProfileInt,lpAppName,lpKeyName,nDefault

  invoke  WriteProfileString,lpAppName,lpKeyName,lpString

  invoke  GetProfileSection,lpAppName,lpBuffer,nSize

  invoke  WriteProfileSection,lpAppName,lpString

可以看出,与操作通用INI文件的函数相比,这组函数的函数名中少了“Private”单词,参数中少了lpFileName参数(因为操作的INI文件名就是Win.ini,并不需要单独指定),所有其他参数的用法都是相同的。

读者可以注意到这些函数中似乎少了一个GetProfileSectionNames函数,实际上并没有这个函数,如果要枚举Win.ini文件中的小节列表的话,只需把GetPrivateProfileSectionNames函数的lpFileName参数指定为NULL就行了,并不需要单独设置一个类似于GetProfileSectionNames的函数。

 


15.3 对注册表的操作(1)


注册表在Windows 9x及NT系统中是很重要的,不谈操作系统本身对注册表依赖性的大小,仅从应用程序的角度来说,注册表除了用来代替INI文件用做保存配置信息以外,有些功能是必须通过操作注册表来完成的,比如要让一个程序在Windows启动的时候自动运行,那就必须在注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ CurrentVersion\Run子键下面添加一个键值定义;如果要让应用程序和某种数据文件相关联,就必须在注册表的HKEY_CLASSES_ROOT键下面为相应的数据文件扩展名设置关联信息;再比如,编写好一个COM组件以后,要为组件的DLL文件在注册表中添加注册信息,组件才能被其他程序使用。另外,操作系统本身将绝大多数的配置信息保存于注册表中,应用程序在运行中往往需要查询这些系统信息来决定运行的方式。

要自如地使用注册表,必须解决两方面的问题,第一是如何在程序中对注册表进行读写与枚举等操作;第二就是要搜集整理关于注册表键值定义的资料。因为注册表是Windows中出了名的“数据迷宫”,很多键的定义只有Microsoft自己知道,公开的键定义也足够编成一本手册了,仅知道如何读写注册表却不知道该往哪里读写是没用的。本节并不是当做注册表的定义手册来写的,所以内容仅涉及第一个方面的问题。本节讨论的内容是:注册表的数据组织方式以及如何用Win32汇编来读写和枚举注册表的内容。

15.3.1  注册表的结构

1. 注册表的数据组织方式

INI文件中的数据是按照两层组织的——只能通过一些在结构上“平行”的小节来归类不同的键,这就像一个驱动器中只能建立一层目录来管理文件一样非常不便,与此相比,注册表的结构有很大改进。

注册表中的数据是分多个层次来组织的,组织的方式类似于磁盘目录的多层组织方式。与文件系统中根目录、子目录和文件这样的层次划分类似,注册表中的数据层次分为根键、键和键值项,其中根键就相当于文件系统中的根目录,键相当于子目录,键值项相当于文件。根键和子键是为了将不同的键值项分类组织而定义的,只有键值项中才包含真正的配置数据。

在Windows自带的注册表编辑器Regedit中就可以看出注册表的结构来。如图15.2所示,注册表中的根键有6个,其名称是Windows规定的,并且是固定不变的,它们分别是HKEY_CLASSES_ROOT,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_CURRENT_CONFIG,HKEY_DYN_DATA和HKEY_USERS。在每个根键下可以建立不同的键,以HKEY_LOCAL_MACHINE根键为例,下面有HARDWARE,SAM,SECURITY和SOFTWARE等子键,而SOFTWARE键下面又建立了ACD Systems,Acer和Adobe等子键,键和子键的关系是相对的,就像一个目录既可以是其上层目录的子目录,又可以是其下层目录的父目录一样。

在一个键中既可以继续建立多个子键,也可以同时建立多个键值项,就像一个目录中既可以建立多个子目录,同时也可以存放多个文件一样。图15.2右边窗口中列出的就是ACDSee键中定义的键值项。



图15.2  注册表的结构

每个键值项由键值名称和键值数据组成(就像是文件名和文件中的数据的关系),如键值名称AppMode中的数据是“00 00 00 00”、键值名称UserName中的数据是“aaa”。不像INI文件中的键值只能定义为字符串,注册表键值的数据类型要丰富得多,全部可用的键值类型如表15.1所示。

表15.1  注册表的键值类型

键值类型
 说   明
 
REG_BINARY
 任何方式的二进制数据
 
REG_DWORD
 一个32位的双字(同REG_DWORD_LITTLE_ENDIAN)
 
REG_DWORD_BIG_ENDIAN
 高位排在低字节的双字
 
REG_EXPAND_SZ
 扩展字符串,可以将中间类似于“%PATH%”类型的子串按照环境变量中的定义值扩展
 
REG_LINK
 Unicode符号链接
 
REG_MULTI_SZ
 多字符串,格式为“字符串1,0,字符串2,0,0”类型
 
REG_RESOURCE_LIST
 设备驱动程序资源列表
 
REG_SZ
 以0结尾的字符串(最常用的类型!)
 

图15.2中的AppMode和UsageCount键值项是REG_BINARY类型的,WindowsPosition键值项是REG_DWORD类型的,其余的键值项是REG_SZ类型的,这3种类型的键值项在注册表中是最常见的。每个键下面还可以有一个没有名称的键值项,称为默认键,默认键必须是REG_SZ或REG_EXPAND_SZ类型的。

2. 注册表中的根键

注册表的结构中大量采用“映射”关系,系统定义的6种根键其实存放在不同的文件中。在Windows 9x系统中,HKEY_LOCAL_MACHINE根键的内容存放在System.dat文件中,HKEY_USERS根键的内容存放在User.dat文件中。而在Windows NT系统中,注册表的内容存放得更分散,连HKEY_LOCAL_MACHINE根键中的不同子键SOFTWARE,SAM,SECURITY和SYSTEM等都分开存放在Windows\system32\config目录下的不同文件中。

HKEY_LOCAL_MACHINE和HKEY_USERS根键是注册表中的两大根键,其余的根键都是它们的派生,实际上它们都是这两大根键下面某些子键的映射,如HKEY_CLASSES_ROOT根键是HKEY_LOCAL_MACHINE根键下SOFTWARE\Classes子键的映射,HKEY_CURRENT_CONFIG根键是HKEY_LOCAL_MACHINE根键下Config子键的映射。

HKEY_USERS根键中的内容是用户配置信息,其内容取决于计算机是否激活了用户配置文件。若未激活用户配置文件,则里面只有名为 .DEFAULT的单一子键,该子键包括与所有用户相关的各种设置。若激活了用户配置文件并且正确地执行了登录操作,则根键下还会有代表当前登录用户的子键,这时候HKEY_CURRENT_USER根键就是这个子键的映射。

HKEY_DYN_DATA保存了系统运行时的动态数据,它反映出系统的当前状态,所以它的数据在每次运行时都是不一样的。应用程序一般不使用这个根键。

对这些实际上是其他数据的映射的根键来说,操作根键上的数据和操作未经映射前的数据产生的效果是一样的,系统建立映射可以让键值数据的组织更清晰,操作起来更加快捷方便。

15.3.2  管理子键

本节用一个例子来演示对注册表的操作方法,例子代码在所附光盘的Chapter14\Reg目录中,运行后的界面如图15.3所示。例子程序演示了子键的创建和删除,键值项的创建、读取和删除,以及枚举子键和键值项的功能。



图15.3  注册表操作例子的运行界面

    


15.3 对注册表的操作(2)


例子程序对HKEY_LOCAL_MACHINE根键进行操作,当在“键名”一栏中输入子键名称字符串并在“键值名”一栏输入键值名称后,按下“读取键值”按钮,如果指定子键中存在这个键值项,程序会读出键值数据并显示在“键值”一栏中;如果按下“删除键值”按钮,那么对应键值项被删除;读者也可以在“键值”一栏中输入其他数据并选定“类型”,然后按下“保存键值”按钮将新的键值数据设置到注册表中。

例子程序也可以对子键进行操作。在对话框最下面的“子键名”一栏中输入子键名称,按下“创建子键”的话,函数会在“键名”一栏指定的键下面创建子键,如果按下“删除子键”按钮,那么“键名”指定的键下面由“子键名”指定的子键会被删除。

每次进行操作以后,程序将“键名”指定的键下面的全部子键和键值项列在编辑框中,以便让用户看到操作的结果。

这里列出了资源脚本文件和源代码。Reg.rc文件定义了如图15.3所示的对话框,文件内容如下:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#include         

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

#define ICO_MAIN     1000

#define DLG_MAIN     1000

#define IDC_KEY     1001

#define IDC_VALUENAME   1002

#define IDC_VALUE   1003

#define IDC_TYPE     1004

#define IDC_KEYLIST   1005

#define IDC_SUBKEY     1006

#define IDC_REMOVE_VALUE 1007

#define IDC_GET_VALUE   1008

#define IDC_SET_VALUE   1009

#define IDC_CREATE_SUBKEY   1010

#define IDC_REMOVE_SUBKEY   1011

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN     ICON       "Main.ico"

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

DLG_MAIN DIALOG 205, 107, 245, 206

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "注册表操作"

FONT 9, "宋体"

{

 RTEXT "键名 HKEY_LOCAL_MACHINE\", -1, 9, 9, 105, 8

 EDITTEXT IDC_KEY, 118, 7, 121, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 RTEXT "键值名", -1, 4, 26, 30, 8

 EDITTEXT IDC_VALUENAME, 39, 24, 139, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 RTEXT "键值", -1, 4, 43, 30, 8

 EDITTEXT IDC_VALUE, 39, 41, 201, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 RTEXT "类型", -1, 4, 59, 30, 8

 COMBOBOX IDC_TYPE, 39, 58, 78, 77, CBS_DROPDOWNLIST | WS_TABSTOP

 LTEXT "当前键下的所有的子键名:", -1, 8, 78, 141, 8

 EDITTEXT IDC_KEYLIST, 6, 92, 232, 91, ES_MULTILINE | ES_AUTOVSCROLL |
   ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP

 RTEXT "子键名", -1, 7, 191, 30, 8

 EDITTEXT IDC_SUBKEY, 42, 189, 73, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

 PUSHBUTTON "删除键值", IDC_REMOVE_VALUE, 183, 23, 57, 14

 PUSHBUTTON "读取键值", IDC_GET_VALUE, 122, 57, 57, 14

 PUSHBUTTON "保存键值", IDC_SET_VALUE, 183, 57, 57, 14

 PUSHBUTTON "创建子键", IDC_CREATE_SUBKEY, 121, 188, 57, 14

 PUSHBUTTON "删除子键", IDC_REMOVE_SUBKEY, 182, 188, 57, 14

}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

汇编源代码Reg.asm的内容如下:

      .386

      .model flat, stdcall

      option casemap :none

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

; Include 文件定义

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

include   windows.inc

include   user32.inc

includelib    user32.lib

include   kernel32.inc

includelib    kernel32.lib

include   Advapi32.inc

includelib    Advapi32.lib

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

; Equ 等值定义

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

ICO_MAIN       equ 1000

DLG_MAIN       equ 1000

IDC_KEY     equ 1001

IDC_VALUENAME     equ 1002

IDC_VALUE     equ 1003

IDC_TYPE       equ 1004

IDC_KEYLIST     equ 1005

IDC_SUBKEY     equ 1006

IDC_REMOVE_VALUE       equ 1007

IDC_GET_VALUE   equ 1008

IDC_SET_VALUE   equ 1009

IDC_CREATE_SUBKEY   equ 1010

IDC_REMOVE_SUBKEY   equ 1011

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

; 数据段

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

        .data?

hInstance   dd    ?

hWinMain     dd    ?

        .const

szTypeSz     db    ~REG_SZ~,0

szTypeDw     db    ~REG_DWORD~,0

szFmtSubkey db   ~【子键】%s~,0dh,0ah,0

szFmtSz db   ~【键值】%s=%s (REG_SZ 类型)~,0dh,0ah,0

szFmtDw db   ~【键值】%s=%08X (REG_DWORD 类型)~,0dh,0ah,0

szFmtValue   db   ~【键值】%s (其他类型)~,0dh,0ah,0

szNotSupport   db   ~程序暂不显示其他类型的键值!~,0

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

; 代码段

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

    .code

include   _Reg.asm

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

_EnumKey     proc   _lpKey

      local @hKey,@dwIndex,@dwLastTime:FILETIME

        local @szBuffer1[512]:byte

      local @szBuffer[256]:byte

      local @szValue[256]:byte

      local @dwSize,@dwSize1,@dwType

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -