Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1590864
  • 博文数量: 441
  • 博客积分: 20087
  • 博客等级: 上将
  • 技术积分: 3562
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-19 15:35
文章分类

全部博文(441)

文章存档

2014年(1)

2012年(1)

2011年(8)

2010年(16)

2009年(15)

2008年(152)

2007年(178)

2006年(70)

分类: C/C++

2008-04-23 17:52:22

Windows注册表是Windows的灵魂,它不仅保存了windows运行时所有配置信息,而且包括所有应用程序的运行环境。下面我们通过一个实例来展示一下如何利用windows提供的api来操作注册表。

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

#define HKEY_CLASSES_ROOT           (( HKEY ) (ULONG_PTR)((LONG)0x80000000) )
#define HKEY_CURRENT_USER           (( HKEY ) (ULONG_PTR)((LONG)0x80000001) )
#define HKEY_LOCAL_MACHINE          (( HKEY ) (ULONG_PTR)((LONG)0x80000002) )
#define HKEY_USERS                  (( HKEY ) (ULONG_PTR)((LONG)0x80000003) )
#define HKEY_CURRENT_CONFIG         (( HKEY ) (ULONG_PTR)((LONG)0x80000005) )

在程序中可以随时将这些助记符当做句柄来引用对应的根键。在程序结束的时候,不需要关闭这些根键句柄。
打开子键使用RegOpenKeyEx函数,在Win16中还存在一个RegOpenKey函数,虽然在Win32中这个函数仍然存在,但这仅是为了兼容的目的而设置的。API手册中推荐使用RegOpenKeyEx函数:
LONG RegOpenKeyEx( HKEY hKey,
                   LPCWSTR lpSubKey,
                   DWORD ulOptions,
                   REGSAM samDesired,
                   PHKEY 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”键来获取它的句柄,所以具体使用哪种方法还要根据具体情况灵活选用。

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

●   ulOptions参数——系统保留参数,必须指定为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。

创建一个子键可以使用RegCreateKeyEx函数:
LONG RegCreateKeyEx( HKEY hKey,
                     LPCWSTR lpSubKey,
                     DWORD Reserved,
                     LPWSTR lpClass,
                     DWORD dwOptions,
                     REGSAM samDesired,
                     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                     PHKEY phkResult,
                     LPDWORD 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。


删除子键使用RegDeleteKey函数:
LONG RegDeleteKey( HKEY hKey,
                   LPCWSTR 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子键下再创建自己的子键,然后将键值项保存在自己的子键中。

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

在一个键下面设置和创建键值项使用RegSetValueEx函数:
LONG RegSetValueEx( HKEY hKey,
                    LPCWSTR lpValueName,
                    DWORD Reserved,
                    DWORD dwType,
                    const BYTE *lpData,
                    DWORD cbData );
hKey参数指定一个键句柄,键值项将保存在这个键下,lpValueName参数指向定义键值项名称的字符串。假如lpValueName参数指向一个空串或者设置为NULL,并且设置的键值类型是REG_SZ的话,那么函数设置的是键的默认值。

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

dwType参数指出了要设置的键值数据的类型,可以使用的类型如下:

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结尾的字符串(最常用的类型!)


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

读取键值项中的数据或者查询键值项的属性使用RegQueryValueEx函数,用法如下:
LONG RegQueryValueEx( HKEY hKey,
                   LPCWSTR lpValueName,
                   LPDWORD lpReserved,
                   LPDWORD lpType,
                   LPBYTE lpData,
                   LPDWORD 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方式。

删除一个键值项的操作则比较简单,使用RegDeleteValue函数就可以了:
LONG RegDeleteKey( HKEY hKey,
                                       LPCWSTR lpSubKey );
hKey参数和lpValueName指定父键句柄和被删除键值项的名称。惟一需要注意的是父键句柄的打开方式必须包括KEY_SET_VALUE。如果键值项被成功删除,则函数返回ERROR_SUCCESS。

有时候我们需要枚举所有的子键:
LONG RegEnumKeyEx( HKEY hKey,
              DWORD dwIndex,
              LPWSTR lpName,
              LPDWORD lpcbName,
              LPDWORD lpReserved,
              LPWSTR lpClass,
              LPDWORD lpcbClass,
              PFILETIME lpftLastWriteTime );
hKey参数指定被枚举的键句柄,dwIndex参数指定需要返回信息的子键索引编号,lpName指向一个缓冲区,函数在这里返回子键名称,lpClass指向用于返回子键类名的缓冲区,lpftLastWriteTime指向一个FILETIME结构,函数在这里返回子键上一次被写入的时间。lpReserved参数是保留参数,必须设置为0。

要注意的是:lpcbName和lpcbClass指向两个双字变量,调用函数前,这两个双字变量中必须放入lpName和lpClass指定的缓冲区的长度,当函数返回的时候,函数在里面返回实际返回到缓冲区中的字符串的长度。如果函数执行成功,返回值是ERROR_SUCCESS。

RegEnumKeyEx函数每次返回一个子键的名称信息,所以要枚举全部子键的话,必须用循环多次调用这个函数,并且每次将dwIndex参数指定的子键索引号递增,当子键全部被枚举后,继续调用函数将得到一个ERROR_NO_MORE_ITEMS返回值,这时就可以结束循环了。

RegEnumKeyEx函数仅枚举一个键下面的全部子键,对键下面的键值项则不会去理会。如果要枚举一个键下面的键值项,那么必须使用RegEnumValue函数:
LONG RegEnumValue( HKEY hKey,
             DWORD dwIndex,
             LPWSTR lpValueName,
             LPDWORD lpcbValueName,
             LPDWORD lpReserved,
             LPDWORD lpType,
             LPBYTE lpData,
             LPDWORD lpcbData );
函数的hKey,dwIndex和lpReserved参数的使用同RegEnumKeyEx函数中的同名参数。其余的一些参数中,lpValueName和lpData参数指向两个缓存区,函数在里面分别返回键值项的名称和数据。lpcbValueName和lpcbData参数指向两个双字变量,调用函数前里面必须放入键值项名称缓冲区和键值数据缓冲区的长度,函数返回后这两个变量的值被改为返回到缓冲区中的数据长度。lpType参数则指向一个用于返回键值数据类型的双字变量。

如果不需要返回键值数据,lpData和lpcbData参数可以设置为NULL,如果不需要返回键值数据类型,lpType参数也可以设置为NULL。

下面的是例子源代码:
新建一个VC6++win32应用程序的空工程,加入以下文件:

// reg.h

/*******************************************************************************/
/*  下面的一组自定义函数,为操作注册表提供了方便,可以直接在其他的例程中使用   */
/*******************************************************************************/
/*******************************************************************************
 _RegQueryValue: 查询键值
 hRootKey: 根键
 lpszKey: 子键
 lpszValueName: 要查询的键值名称
 lpszValue: 返回键值的缓冲区
 lpdwSize: 返回键值的缓冲区大小
 lpdwType: 返回键值的类型
 例:
     char szValue[256];
     DWORD dwType;
     _RegQueryValue(HKEY_LOCAL_MACHINE,
                    "SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run",
                    "MyProgram", szValue, sizeof(szValue), &dwType);                   
********************************************************************************/
DWORD    _RegQueryValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName, LPTSTR lpszValue,
                       LPDWORD lpdwSize, LPDWORD lpdwType);

/**********************************************************************************
 _RegSetValue: 添加键值
 hRootKey: 根键
 lpszKey: 子键
 lpszValueName: 键值名称
 lpszValue: 键值
 dwValueType: 键值类型
 dwSize: 键值长度
 例:
     char szValue[] = TEXT("C:\\abc.exe");
     _RegSetValue(HKEY_LOCAL_MACHINE,
                  "SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run",
                  "MyProgram", szValue, REG_SZ, sizeof(szValue));
***********************************************************************************/
void    _RegSetValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName, LPCTSTR lpszValue,
                     DWORD dwValueType, DWORD dwSize);

/*************************************************************************************
 _RegCreateKey: 创建子键
 hRootKey: 根键
 lpszKey: 子键
 lpszSubKeyName: 要创建的子键名称
 例:
     _RegCreateKey(HKEY_LOCAL_MACHINE,
                  "SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run",
                  "MySubKey");
**************************************************************************************/
void    _RegCreateKey(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszSubkeyName);

/*************************************************************************************
 _RegDelValue: 删除键值
 hRootKey: 根键
 lpszKey: 子键
 lpszValueName: 要删除的键值名称
 例:
 _RegDelValue(HKEY_LOCAL_MACHINE,
                  "SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run",
                  "MyProgram");
**************************************************************************************/
void    _RegDelValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName);

/*************************************************************************************
 _RegDelSubKey: 删除子键
 hRootKey: 根键
 lpszKey: 子键
 lpszSubkeyName: 要删除的子键名称
 例:
 _RegDelSubkey(HKEY_LOCAL_MACHINE,
               "SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run",
               "MySubKey");
**************************************************************************************/
void    _RegDelSubkey(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszSubkeyName);

/************************************************************************************/

/*************************下面是具体的实现****************************************/

DWORD    _RegQueryValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName, LPTSTR lpszValue,
                       LPDWORD lpdwSize, LPDWORD lpdwType)
{
    HKEY hKey;
    DWORD dwRtn = -1;

    // 打开子键
    dwRtn = RegOpenKeyEx(hRootKey, lpszKey, NULL, KEY_QUERY_VALUE, &hKey);
    if ( dwRtn == ERROR_SUCCESS )
    {
        // 查询当前子键下的某一键值, lpszValueName为键的名称, lpszValue为返回的键值
        dwRtn = RegQueryValueEx(hKey, lpszValueName, NULL, lpdwType, lpszValue, lpdwSize);
        RegCloseKey(hKey);
    }
    return dwRtn;
}

void    _RegSetValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName, LPCTSTR lpszValue,
                     DWORD dwValueType, DWORD dwSize)
{
    HKEY hKey;
    // 获取将要创建键值的子键的句柄
    if  ( ERROR_SUCCESS == RegCreateKey(hRootKey, lpszKey, &hKey) )
    {
        // 设置键值
        RegSetValueEx(hKey, lpszValueName, 0, dwValueType, lpszValue, dwSize);
        RegCloseKey(hKey);
    }
}

void    _RegCreateKey(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszSubkeyName)
{
    HKEY hKey, hSubkey;
    DWORD dwDisp;

    // 打开要创建子键的键
    if ( ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpszKey, NULL, KEY_CREATE_SUB_KEY, &hKey))
    {
        // 创建子键
        RegCreateKeyEx(hKey, lpszSubkeyName, 0, NULL, 0, 0, NULL, &hSubkey, &dwDisp);
        RegCloseKey(hKey);
        RegCloseKey(hSubkey);
    }
}

void    _RegDelValue(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszValueName)
{
    HKEY hKey;
   
    //获取将要删除一个键值的子键的句柄
    if ( ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpszKey, NULL, KEY_WRITE, &hKey) )
    {
        // 删除下面的某一个键值,lpszValueName为键值名称
        RegDeleteValue(hKey, lpszValueName);
        RegCloseKey(hKey);
    }
}

void    _RegDelSubkey(HKEY hRootKey, LPCTSTR lpszKey, LPCTSTR lpszSubkeyName)
{
    HKEY hKey;
   
    // 获取将要删除子键的子键句柄
    if ( ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpszKey, NULL, KEY_WRITE, &hKey) )
    {
        // 删除子键
        RegDeleteKey(hKey, lpszSubkeyName);
        RegCloseKey(hKey);
    }
}

// reg.c

#include
#include "resource.h"
#include "reg.h"

HWND    hWinMain = NULL;
char    szLocalMachine[] = TEXT("HKEY_LOCAL_MACHINE");
char    szUsers[] = TEXT("HKEY_USERS");
char    szCurrentUser[] = TEXT("HKEY_CURRENT_USER");
char    szClassRoot[] = TEXT("HKEY_CLASSES_ROOT");
char    szCurrentConfig[] = TEXT("HKEY_CURRENT_CONFIG");
char    szTypeSz[] = TEXT("REG_SZ");
char    szTypeDw[] = TEXT("REG_DWORD");
char    szFmtSubkey[] = TEXT("【子键】%s\r\n");
char    szFmtSz[] = TEXT("【键值】%s=%s (REG_SZ类型)\r\n");
char    szFmtDw[] = TEXT("【键值】%s=%08X (REG_DWORD类型)\r\n");
char    szFmtValue[] = TEXT("【键值】%s (其它类型)\r\n");
char    szNotSupport[] = TEXT("程序暂不显示其它类型键值!");


void    EnumKey(HKEY hRootKey, LPCTSTR lpSubkey);
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void    AutoRun(BYTE bAutoRun);
void    GetFileName(char *szFullPath, char *szFileName);
void    CheckAutoRun();

int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
    DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc, 0);
    return 0;
}

void    EnumKey(HKEY hRootKey, LPCTSTR lpSubkey)
{
    HKEY    hKey;
    DWORD    dwIndex;
    FILETIME    dwLastTime;
    char    szBuffer[512];
    char    szBuffer1[512];
    char    szValue[256];
    DWORD    dwSize1, dwSize, dwType;

    dwIndex = 0;

    // 将显示文本框清空
    SendDlgItemMessage(hWinMain, IDC_KEYLIST, WM_SETTEXT, 0, 0);
    // 获取当前子键下的所有子键
    if ( ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpSubkey, NULL, KEY_ENUMERATE_SUB_KEYS, &hKey))
    {
        while ( TRUE )
        {
            dwSize = sizeof(szBuffer);           
            // 枚举子键
            if ( ERROR_NO_MORE_ITEMS == RegEnumKeyEx(hKey, dwIndex, szBuffer, &dwSize,
                NULL, NULL, NULL, NULL))
                break;
            wsprintf(szBuffer1, szFmtSubkey, szBuffer);
            SendDlgItemMessage(hWinMain, IDC_KEYLIST, EM_REPLACESEL, 0, szBuffer1);
            ++dwIndex;
        }
        RegCloseKey(hKey);
    }

    dwIndex = 0;

    // 枚举当前子键下的所有键值
    if ( ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpSubkey, NULL, KEY_QUERY_VALUE, &hKey))
    {
        while ( TRUE )
        {
            dwSize = sizeof(szBuffer);
            dwSize1 = sizeof(szValue);
            // 枚举键值
            if ( ERROR_NO_MORE_ITEMS == RegEnumValue(hKey, dwIndex, szBuffer, &dwSize, NULL,
                &dwType, szValue, &dwSize1))
                break;
            if ( dwType == REG_SZ )
                wsprintf(szBuffer1, szFmtSz, szBuffer, szValue);
            else if ( dwType == REG_DWORD )
                wsprintf(szBuffer1, szFmtDw, szBuffer, (DWORD)szValue);
            else
                wsprintf(szBuffer1, szFmtValue, szBuffer, szValue);
           
            SendDlgItemMessage(hWinMain, IDC_KEYLIST, EM_REPLACESEL, 0, szBuffer1);
            ++dwIndex;
        }
        RegCloseKey(hKey);
    }
}

LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    char szKey[256], szSubKey[256], szValueName[256], szValue[256];
    DWORD dwType, dwSize;
    int nIndex;
    HKEY hKey = NULL;
    int nValue;
    BYTE *pB = NULL;

    nIndex = SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_GETCURSEL, 0, 0);
    if ( nIndex != CB_ERR )
        hKey = SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_GETITEMDATA, nIndex, 0);
    if ( hWinMain != NULL )
    {
        GetDlgItemText(hWinMain, IDC_KEY, szKey, sizeof(szKey));
        GetDlgItemText(hWinMain, IDC_SUBKEY, szSubKey, sizeof(szSubKey));
        GetDlgItemText(hWinMain, IDC_VALUENAME, szValueName, sizeof(szValueName));
        GetDlgItemText(hWinMain, IDC_VALUE, szValue, sizeof(szValue));
    }

    switch ( uMsg )
    {
    case WM_CLOSE:
        EndDialog(hWnd, 0);
        break;
    case WM_INITDIALOG:
        hWinMain = hWnd;
        SendDlgItemMessage(hWnd, IDC_TYPE, CB_INSERTSTRING, 0, szTypeSz);
        SendDlgItemMessage(hWnd, IDC_TYPE, CB_INSERTSTRING, 1, szTypeDw);
        SendDlgItemMessage(hWnd, IDC_TYPE, CB_SETCURSEL, 0, 0);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_INSERTSTRING, 0, szLocalMachine);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETITEMDATA, 0, HKEY_LOCAL_MACHINE);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_INSERTSTRING, 1, szUsers);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETITEMDATA, 1, HKEY_USERS);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_INSERTSTRING, 2, szCurrentUser);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETITEMDATA, 2, HKEY_CURRENT_USER);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_INSERTSTRING, 3, szCurrentConfig);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETITEMDATA, 3, HKEY_CURRENT_CONFIG);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_INSERTSTRING, 4, szClassRoot);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETITEMDATA, 4, HKEY_CLASSES_ROOT);
        SendDlgItemMessage(hWnd, IDC_ROOTKEY, CB_SETCURSEL, 0, 0);       
        EnumKey(HKEY_LOCAL_MACHINE, NULL);
        CheckAutoRun();
        break;
    case WM_COMMAND:
        switch ( LOWORD(wParam) )
        {
        case IDC_KEY:
        case IDC_VALUENAME:
        case IDC_VALUE:
        case IDC_TYPE:
        case IDC_KEYLIST:
        case IDC_SUBKEY:
            return TRUE;
        case IDC_ROOTKEY:
            if ( HIWORD(wParam) == CBN_SELENDOK )
            {
                if ( hKey != CB_ERR )
                        EnumKey(hKey, NULL);
            }
            return TRUE;
        case IDC_REMOVEVALUE:
            if ( hKey != CB_ERR )
                _RegDelValue(hKey, szKey, szValueName);
            break;
        case IDC_GETVALUE:
            if ( hKey != CB_ERR )
            {
                dwSize = sizeof(szValue);
                RtlZeroMemory(szValue, dwSize);
                if ( ERROR_SUCCESS == _RegQueryValue(hKey, szKey, szValueName, szValue, &dwSize, &dwType))
                {
                    if ( dwType == REG_SZ )
                    {
                        SetDlgItemText(hWnd, IDC_VALUE, szValue);
                        SendDlgItemMessage(hWnd, IDC_TYPE, CB_SETCURSEL, 0, 0);
                    }
                    else if ( dwType == REG_DWORD )
                    {
                        // 读出来的是一个DWORD值,但是放在了一个字符数组的前4个元素当中
                        // 所以必须把这个四个字节取出来合成一个DWORD值
                        pB = (BYTE*)&nValue;
                        pB[3] = szValue[3];
                        pB[2] = szValue[2];
                        pB[1] = szValue[1];
                        pB[0] = szValue[0];
                        SendDlgItemMessage(hWnd, IDC_TYPE, CB_SETCURSEL, 1, 0);
                        SetDlgItemInt(hWnd, IDC_VALUE, nValue, FALSE);
                    }
                    else
                    {
                        SetDlgItemText(hWnd, IDC_VALUE, szNotSupport);
                    }
                }
            }
            break;
        case IDC_SETVALUE:
            if ( hKey != CB_ERR)
            {
                nIndex = SendDlgItemMessage(hWnd, IDC_TYPE, CB_GETCURSEL, 0, 0);
                if ( !nIndex ) // REG_SZ
                {
                    GetDlgItemText(hWnd, IDC_VALUE, szValue, 256);
                    _RegSetValue(hKey, szKey, szValueName, szValue, REG_SZ, lstrlen(szValue) + 1);
                }
                else // REG_DWORD
                {
                    nValue = GetDlgItemInt(hWnd, IDC_VALUE, NULL, FALSE);
                    // 我们得到的是一个整形值, 但是这里要求写入一个REG_DWORD类型的值
                    // 参数又是字符串, 一个整形值是4个字节,它和字符串不能直接转换,
                    // 所以必须把这个整形值的4个字节拆开放在字符串的前4个元素(字节)当中
                    pB = (BYTE*)&nValue;
                    szValue[3] = pB[3];
                    szValue[2] = pB[2];
                    szValue[1] = pB[1];
                    szValue[0] = pB[0];
                    _RegSetValue(hKey, szKey, szValueName, szValue, REG_DWORD, 4);
                }
            }
            break;
        case IDC_CREATESUBKEY:
            if ( hKey != CB_ERR )
                _RegCreateKey(hKey, szKey, szSubKey);
            break;
        case IDC_REMOVESUBKEY:
            if ( hKey != CB_ERR )
                _RegDelSubkey(hKey, szKey, szSubKey);
            break;
        case IDC_AUTORUN:
            if ( HIWORD(wParam) == BN_CLICKED )
            {
                AutoRun(IsDlgButtonChecked(hWinMain, IDC_AUTORUN));
            }
            break;
        default:
            break;
        }
        if ( hKey != CB_ERR)
            EnumKey(hKey, szKey);
        break;       
    default:
        return FALSE;
    }   
    return TRUE;
}


void AutoRun(BYTE bAutoRun)
{
    char    szFileName[MAX_PATH];
    char    szPathName[MAX_PATH];
    char    szKeyAutoRun[] = TEXT("SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run");
    DWORD    dwRtn;

    // 获取可执行文件的全路径
    dwRtn = GetModuleFileName(NULL, szPathName, sizeof(szPathName));
    dwRtn++;
    GetFileName(szPathName, szFileName);
    if ( bAutoRun )
    {
        _RegSetValue(HKEY_LOCAL_MACHINE, szKeyAutoRun, szFileName, szPathName, REG_SZ, dwRtn);
    }
    else
    {
        _RegDelValue(HKEY_LOCAL_MACHINE, szKeyAutoRun, szFileName);
    }
}

// 由文件的全路径获取文件的名称
void GetFileName(char *szFullPath, char *szFileName)
{
    int nLen, i, j, k;
    if ( szFullPath == NULL || szFileName == NULL )
        return;

    nLen = strlen(szFullPath);
    for ( i = nLen - 1; i >= 0; i--)
    {
        if ( szFullPath[i] == '\\' )
            break;
    }
    k = 0;
    for ( j = i + 1; j < nLen; j++ )
    {
        szFileName[k] = szFullPath[j];
        k++;
    }
    szFileName[k] = 0;
}

// 检测本程序是否是开机自动运行,如果是,则将开机自动运行的CheckBox打上勾
void CheckAutoRun()
{
    char    szFileName[MAX_PATH];
    char    szPathName[MAX_PATH];
    char    szValue[MAX_PATH];
    char    szKeyAutoRun[] = TEXT("SoftWare\\Microsoft\\Windows\\CurrentVersion\\Run");
    DWORD    dwRtn;
    DWORD    dwSize;

    // 获取可执行文件的全路径
    dwRtn = GetModuleFileName(NULL, szPathName, sizeof(szPathName));
    dwRtn++;
    GetFileName(szPathName, szFileName);

    if ( ERROR_SUCCESS == _RegQueryValue(HKEY_LOCAL_MACHINE, szKeyAutoRun, szFileName, szValue, &dwSize, NULL) )
    {
        CheckDlgButton(hWinMain, IDC_AUTORUN, BST_CHECKED);
    }
}

// resource.h
#define IDD_MAIN                        101
#define IDC_KEY                         1000
#define IDC_VALUENAME                   1001
#define IDC_REMOVEVALUE                 1002
#define IDC_VALUE                       1003
#define IDC_TYPE                        1004
#define IDC_GETVALUE                    1005
#define IDC_SETVALUE                    1006
#define IDC_KEYLIST                     1007
#define IDC_SUBKEY                      1008
#define IDC_CREATESUBKEY                1009
#define IDC_REMOVESUBKEY                1010
#define IDC_ROOTKEY                     1011
#define IDC_AUTORUN                     1012
#define IDC_STATIC                      -1

// reg.rc
#include "resource.h"
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_MAIN DIALOG DISCARDABLE  0, 0, 343, 255
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "注册表操作"
FONT 10, "宋体"
BEGIN
    LTEXT           "根键:",IDC_STATIC,7,9,32,8
    EDITTEXT        IDC_KEY,53,25,284,14,ES_AUTOHSCROLL
    LTEXT           "键值名:",IDC_STATIC,7,48,31,8
    EDITTEXT        IDC_VALUENAME,53,43,225,14,ES_AUTOHSCROLL
    PUSHBUTTON      "删除键值",IDC_REMOVEVALUE,286,43,50,14
    LTEXT           "键值:",IDC_STATIC,7,68,31,8
    EDITTEXT        IDC_VALUE,53,62,283,14,ES_AUTOHSCROLL
    LTEXT           "类型:",IDC_STATIC,7,88,23,8
    COMBOBOX        IDC_TYPE,53,83,97,52,CBS_DROPDOWNLIST | CBS_SORT |
                    WS_VSCROLL | WS_TABSTOP
    PUSHBUTTON      "读取键值",IDC_GETVALUE,169,82,50,14
    PUSHBUTTON      "保存键值",IDC_SETVALUE,232,82,50,14
    LTEXT           "当前键下的所有子键名:",IDC_STATIC,7,105,104,8
    EDITTEXT        IDC_KEYLIST,7,119,329,110,ES_MULTILINE | ES_AUTOVSCROLL |
                    ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
    LTEXT           "子键名:",IDC_STATIC,7,240,31,8
    EDITTEXT        IDC_SUBKEY,40,234,136,14,ES_AUTOHSCROLL
    PUSHBUTTON      "创建子键",IDC_CREATESUBKEY,191,234,50,14
    PUSHBUTTON      "删除子键",IDC_REMOVESUBKEY,255,234,50,14
    COMBOBOX        IDC_ROOTKEY,53,7,129,59,CBS_DROPDOWNLIST | CBS_SORT |
                    WS_VSCROLL | WS_TABSTOP
    LTEXT           "键名:",IDC_STATIC,7,28,23,8
    CONTROL         "开机自动运行本程序",IDC_AUTORUN,"Button",
                    BS_AUTOCHECKBOX | WS_TABSTOP,250,7,86,10
END

本程序具体演示了如何向注册表中添加、删除一个子键,添加、删除一个键值,以及查询键值等操作,并且演示了如何开机自动运行一个程序。
其中reg.h中的几个函数可以直接用到你自己的工程当中,简化操作。

本程序的理论来源于罗云彬的32位汇编语言一书,例子也是由32位汇编语言源代码改写而来。如果你想知道汇编的写法,可以参考此书。

author: cnhnyu
e-mail: cnhnyugmailcom
qq: 94483026





阅读(2051) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-06-15 17:45:02

写得很好,收藏。 但是觉得再封装一下api函数有必要么?

chinaunix网友2010-06-15 17:45:02

写得很好,收藏。 但是觉得再封装一下api函数有必要么?