65.9K
CodeProject 正在变化。 阅读更多。
Home

一个方便使用的 Windows 注册表类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.81/5 (17投票s)

2004 年 6 月 13 日

3分钟阅读

viewsIcon

92494

downloadIcon

1933

如果您不需要花哨的功能,该类展示了访问 Windows 注册表的简单方法。

源代码更新

源代码已更新。 (希望)这将使它们可以在 VC 7+ 上编译。 我无法用 VC 7 测试它,但我希望现在没问题了。 欲了解更多信息,请查看 问题所在。

新增内容

此类已修改

  • 改进了内部逻辑。
  • 改进了对将结构化数据写入注册表的支持。
  • 增加了查看内部执行流程的可能性(例如,从注册表中读取和写入数据时)。
  • 增加了对 HKEY_LOCAL_MACHINEHKEY_USERS 和所有其他类型的支持...

简而言之,为了将结构存储在注册表中,您只需要这样做

SomeStruct X;
//set struct values...
reg["SomeStructData"].set_struct(X);

为了读取存储的结构

SomeStruct X;
//set struct values...
if(reg["SomeStructData"].get_struct(X)){
    //Ok, X contains the read data...
}else {
    //error reading struct.
}

为了使用 HKEY_LOCAL_MACHINE 或其他,您可以将类型为 registry::Key 的第二个参数传递给注册表构造函数

registry reg("Sowtware\\Whatever",registry::hkey_local_machine);

第二个参数是可选的,默认为 registry::hkey_current_user

为了查看内部执行流程,您可以 #define WANT_TRACE。 并且在控制台模式下,您将看到创建了哪些对象以及何时创建,以及何时从注册表中读取/写入值。 添加了一个新项目with_trace 来查看这一点。

//with trace

#define WANT_TRACE //define this to be able to see internal details...

#include "registry.h"
#include "string.h"
#include <STRING>

struct Something{
    int area;
    float height;
};

int main(int, char*)
{
    registry reg("Software\\Company");
    {
        Something X;
        X.area=100;
        X.height=4.5;

        reg["Something"].set_struct(X);
    }
    Something Z;
    if(reg["Something"].get_struct(Z)){
        printf("area is: %i\nheight is: %f\n", Z.area,Z.height);
    }

    return 0;
}

它产生以下输出

with_trace output

引言

首先,您只需要一个文件 registry.h,该文件包含在源代码 distribution 中。 接着阅读...

//Dirty and fast howto

#include "registry.h"
#include "string.h"

int main(int, char*){

    registry reg("Software\\Company");
    reg["Language"]="English";        //set value
    reg["Width"]=50;
    printf("The address is: %s\n",(char*)reg["Address"]); 
    //prints nothing unless you put something in
    return 0;
}

一个更具描述性的操作方法

//Long story:

#include "registry.h"
#include "string.h"

struct ServerAddress{
    char name[64];
    char ip[15];
    short port;
};

int main(int,char*){

    //first step is to create our home registry 
    //record(or open it if exists)
    //the constructor accepts a string and if you do:
    registry settings("Software\\MyCoolApp");
    //you open HKEY_CURRENT_USER\Sowtware\MyCoolApp

    //Due to simplicity this class is desined to deal with only 
    //HKEY_CURRENT_USER registry group. 
    //You may, however, modify this behavior if you need

    //To make sure that the home key has been created or 
    //opened you can test it like this:

    if(!settings){
        //error code goes here...
        exit(1);
    }

    //The next step is to create (or open if exists) 
    //a value key:
    //the official way is like this: (for another, 
    //simpler way, read below.)

    registry::iterator lang=settings["Language"];    
    //Personally I don't use it this way - too much to type...

    //and then you can retrive value of "Language" key 
    //as follows:

    printf("The selected language is: \"%s\"\n",(char*)lang);

    //if you want to modify a value you can do simply like this:

    lang="Russian";

    //Internally this class stores values as 
    //binary data and therefore 
    //you are not limited to strings only.

    // Example:

    ServerAddress MyCoolServer;
    strcpy(MyCoolServer.name,"somewhere.example.com");
    strcpy(MyCoolServer.ip,"192.168.0.1");
    MyCoolServer.port=1024;

    //now let's put this record into registry key "server"
    //it can be simply done like this:

    registry::iterator server=settings["server"];
    server=string((const char *)(&MyCoolServer),sizeof(MyCoolServer));

    //now let's test by retriving the structure back:

    ServerAddress serAdr;
    const string &FromRegistry=server;
    //copy data only if it's of the size of the struct ServerAddress
    if(FromRegistry.length()==sizeof(ServerAddress)){        
        memcpy(&serAdr,FromRegistry.c_str(), sizeof(ServerAddress));
        //now let's see what we have (see a pic below):
        printf("Print out for my server:\n");
        printf("\tserver's host name is:  %s\n",    serAdr.name);
        printf("\tserver's ip address is: %s\n",    serAdr.ip);
        printf("\tserver's port is:       %u\n\n",  serAdr.port);
    }else{
        //error code goes here...
    }
    return 0;
}

Sample Image - long_story.jpg

图 1. 来自更具描述性的操作方法的输出。

我编写了这几行,同时考虑了简单性。 我喜欢这种风格,我可以像给普通变量赋值一样给注册表键赋值。 我将简要描述如何在我的项目中使用此代码。 我将成员变量 reg(注册表的实例)放入需要访问注册表的应用程序类(原因见下文)。 然后,在类的构造函数中,我将 reg 变量实例化到注册表主键。 由于注册表类中没有默认构造函数,您可以这样做

class my_app{
protected:
    registry reg;
    string UserName;
public:
    my_app() : reg("Software\\my_app"){ // <--
        UserName = reg["UserName"]; //read value
    }
    ~my_app(){
        //store value back to the registry
        reg["UserName"] = UserName;
    }
}

在上一行中,您实际上不需要为 UserName 创建一个单独的字符串 - 您可以拥有一个 registry::iterator 类型的成员变量,当您的类被销毁时,该变量将自动存储到注册表中(请参阅页面底部的最终示例)。

然后,每当您需要时,您可以这样做

SetLanguage(reg["Lang"]); 
string UserName=reg["User"];

这真的很简单...

背景

现在,关于其内部工作原理的一些背景信息。 这实际上是一个非常轻量级的类。 它比您可能做的 API 调用更少。

例如,这行代码

reg["Something"]="nothing";

将仅在返回键值被销毁时物理访问注册表一次,以将值“nothing”分配给键“something”。

下一行也是如此(当组超出范围时,只有一个 API 调用)

registry::iterator name=settings["UserName"];
name="John";
name="Alex";
name="Someone Else";

基本上,如果您打算使用此类,您应该意识到语句 reg["something"]="nothing"; 本身不会修改注册表中的任何内容。 只有当语句超出范围时,才会设置该值,如下所示

{
    reg["UserName"]="Bill";
    printf("The username is: %s\n", (char*)reg["UserName"]); 
    //!!WILL NOT PRINT BILL, 
    //it will print the value that was before the previous line
}//at this point the value Bill is in the registry
printf("The username is: %s\n", (char*)reg["UserName"]); //now it prints Bill;

为了强制它在某个时刻提交到注册表,您可以使用 flush() 方法,如下所示

registry::iterator name=settings["UserName"];
name="John";
name.flush(); //at this point it will write value "John" to registry.

读取值也是如此 - 它们仅在您请求时才检索,而且仅检索一次! 因此,如果您知道(或认为)其他内容(也许是地球的磁场 :)) 已经修改了键的值,您可以使用 refresh() 方法。 但是,请小心!! 您之前分配的任何内容都不会被提交(它将被注册表返回的值覆盖)。

一个非常重要的一点。 当注册表的实例被销毁或超出范围时,那么您从中创建的所有值都将无法访问注册表。 也就是说,给定注册表实例上的所有迭代器都应该在它们的父注册表实例之前被销毁。 这就是为什么我将此类用作另一个类的成员的原因。 当父类被销毁时,它不需要访问注册表,并且在那个时候也不可能访问注册表。

就是这样。 希望它对某人有用。

更好的例子

#include "registry.h"
#include <iostream>


class my_app{
protected:
    registry reg;
    registry::iterator UserName;
public:
    my_app():reg("Software\\Company"),UserName(reg["UserName"]){}
    ~my_app(){}
    void SetUserName(const char * name){
        UserName = name;
    }
    const char * GetUserName(){
        return (const char *) UserName;
    }
};

int main (int, char *){
    my_app App;
    App.SetUserName("Alex");
    cout<<"The username is: "<<App.GetUserName()
        <<endl<<"Thanks for playing..."<<endl;
    return 0;
}
© . All rights reserved.