注册表编程技术.docx
《注册表编程技术.docx》由会员分享,可在线阅读,更多相关《注册表编程技术.docx(85页珍藏版)》请在冰豆网上搜索。
注册表编程技术
SomeTipsforRegistryProgramming
作者:
osmose(ph4nt0m)
来源:
幻影旅团()&&补天网()
EMAIL:
osmose@
2003.7.18
写在前面的话
不敢给这篇文章起个太大的名字,毕竟这只是我这一段时间学习心得的一点总结,顶多仅仅是一些tips而已。
其实我什么都不懂,所以我尽量写的详细,希望大家不要厌烦。
注册表编程其实并不是一件困难的事情,如果看一点材料,查一查msdn,本可以很快掌握。
我在网上搜索了一下,发现很多高手提供的只是MFC的一个关于注册表的类,都很泛泛,真正的代码还需要自己添加。
对于像我一样急功近利,希望一口吃成胖子的菜鸟们,如果很快上手是大家最关心的问题。
说实话,我没有找到一个比较详细的说明,所以我开始写这篇文章,手边有的就是一个API函数表和MSDN。
在此感谢CSDN上各位大牛(Skt32(Skt32),shilong(星矢の诗龙),firela(firela),laolaoliu2002(老刘)等)对我的指点,那里也许是一个对程序爱好的人最应该去的地方之一。
也感谢幻影旅团的各位弟兄的帮助,那是一个只关心技术的地方。
或许这些知识都很浅显,但是我们在学习。
这篇文章最初的目的是写出一些属于自己的程序,或许适合热衷于开启别人机器某个服务的人,学会编写一些程序操作注册表,也许就不用总等着拾人牙慧了。
随着点滴的积累,逐渐觉得有更多的东西可以深挖或者涵括,于是就有了这篇整理的总结。
我从自己学习的角度,对遇到的困难尽可能的分析,给出结果。
但是文中仍然遗留了一些问题无法解决。
如果您有什么建议,欢迎指正。
BTW:
文中的程序如无特殊说明,都是支持MFC的。
新建项目时请注意。
第一章
概述
先让我们活动一下脑筋,想想看要修改或者保存注册表,有哪些途径?
1.在windows下面打开运行窗口(按住win键和r键),输入regedit,OK,在FILE菜单里有导入导出,保存什么,修改什么,不多说了。
2.到古老的DOS方式,让我们重新幼稚一下。
(下面的内容前人已经写过多次,抄过来用一下,像前辈们致敬!
)
在DOS提示符下键入Regedit命令,将出现一个帮助屏幕。
此屏幕给出了其命令行参数及其使用方法。
语法:
Regedit[/L:
system][/R:
user]filename1
Regedit[/L:
system][/R:
user]/Cfilename2
Regedit[/L:
system][/R:
user]/Efilename3[regpath]
其中:
/L:
system指定system.dat文件的存放位置。
/R:
user指定user.dat文件的存放位置。
filename1指定引入注册表数据库的文件名。
/Cfilename2指定形成注册表数据库的文件名。
/Efilename3指定导出注册表文件的文件名。
regpath指定导出注册表文件的开始关键字(缺省为全部关键字)
现举几个例子说明regedit.exe在DOS下的使用方法。
【例1】将系统注册表数据库registry导出到reg1.reg文件中。
regedit/Ereg1.reg
【例2】reg1.reg形成系统注册表数据库registry(全部)中。
regedit/Creg1.reg
【例3】将reg.dat引入系统注册表数据库中(部分)。
regeditreg.dat
【例4】将CJH开始的关键字导出注册表数据库,并命名为cjh.reg。
regedit/Ecjh.regcjh
【例5】指定system/dat存放在D:
\PWIN中和user.dat存放在E:
\PWIN中,将reg.dat数据文件形成一个新的注册表数据库registry。
regedit/L:
D:
\PWIN/R:
E:
\PWIN/Creg.dat
DOS下的手段当然不止这些,如果想体验程序的感觉,还需要麻烦你看看批处理:
@echooff
path=c:
\windows;c:
\windows\command;c:
\dos
cls
echo正在导出注册表……
regedit/Etxt.regHKEY_CLASSES_ROOT\txtfile
echo.
echo注册表导出完毕!
按任一键开始编辑注册表……
echo.
pause
edittxt.reg
echo正在将修改后的注册表导入……
regedittxt.reg
echo恭喜您!
在MS-DOS方式下成功修改了注册表!
pause
cls
@echoon
把上面这段代码复制到一个.bat文件中,你可以用EDIT这个命令编辑。
从某种意义上说,充分发挥EDIT编辑器的强大功能,我们可以在遵循导出的注册表文件的格式的前提下,对注册表进行随心所欲的修改、删除或者增加任一子键。
如果觉得这还不够程序化,您可以发挥DOS环境下各种程序设计语言的优势,加上交互性的界面,将这一过程真正的程序化,应该丝毫不亚于Windows状态下的利用API函数做出来的效果。
3.在C程序中调用regedit命令,不要忘记C程序可以调用DOS命令的哟。
记得加入
#includeDOS.h
这种方法和上面一种比起来换汤不换药,不多说了。
3.MFC有专门操作注册表的库,据说很方便,我没有用过,因为我不会MFC,也许只是那几个类吧,也许有很多。
没做过的东西,就不能说它简单。
如果哪位高人研究过,请补充一下。
4.调用API函数。
API函数是个好东西,VB,Delphi,BCB,什么都可以用它。
有人建议最后学API,因为最难。
是的,可是我急功近利,只学那几个注册表的函数,试试看能不能学到点什么。
好了,上面是关于修改注册表的一些方法。
下面让我们来看看注册表函数都有哪些。
键管理类
RegCloseKey()
RegCreateKey()
RegCreateKeyEx()
RegDeleteKey()
RegDeleteKeyEx()
RegOpenKey()
RegOpenKeyEx()
值管理类
RegDeleteValue()
RegQueryValue()
RegQueryValueEx()
RegSetValue()
RegSetValueEx()
查询计数类
RegQueryInfoKey()
RegEnumKey()
RegEnumKeyEx()
RegEnumValue()
备份/恢复类
RegLoadKey()
RegReplaceKey()
RegRestoreKey()
RegSaveKey()
实用类
RegConnectRegistry()
RegNotifyChangeKeyValue()
RegUnloadKey()
安全类
(仅适用于NT)
RegGetKeySecurity()
RegSetKeySecurity()
我会选其中的一部分作具体介绍,这个文章能写到什么地步,能不能全部写完,我也不知道,看大家的反映了。
大家都知道,2001年微软停止开发win98系统内核,专攻NT,上面的一些函数还有专门服务于win3.1的,够古老的吧。
比如,RegSetValueEx()和RegSetValue()有什么不同呢?
前者可用于基于win32系统的应用开发。
RegSetValue()则是服务于win3.1系统的。
使用的时候要注意:
WindowsNT:
HKEY_PERFORMANCE_DATA
Windows95andWindows98:
HKEY_DYN_DATA
这两个子键是不一样的,虽然其他的都一样(HKEY_CLASSES_ROOT,EY_CURRENT_CONFIG,HKEY_CURRENT_USER,HKEY_LOCAL_MACHINE,HKEY_USERS)
不要误会,这两个函数都可以用在95,98系统上,具体什么差别呢,看看MSDN的话:
Win32-basedapplicationsshouldusetheRegSetValueExfunction,whichallowsyoutosetanynumberofnamedvaluesofanydatatype.(基于win32的应用程序推荐使用RegSetValueEx函数,可以对设置任意类型任意键名任意值。
。
。
)所以,以后有带Ex的函数,我们尽量都用它啦。
OK,第一部分先写到这里。
第二部分,我会给出一个完整的例子,如何保存注册表里任意一个键和他的所有子键,里面涉及到一些权限的问题,调用了一些API函数获得操作注册表的权限。
第三部分,引用并且分析MSDN中的一个例子,通过注册表列举函数保存HKEY_LOCAL_MACHINE这样一个大键。
第四部分是关于修改注册表键值,也有一个具体的例子,同时可能会谈到一点创建子键的问题,希望让大家都能看得轻松一点。
我会结合MSDN中的解释尽量把每一个函数讲清楚,至少是我遇到的问题都说清楚。
第二章
保存注册表的特定键
这一部分,我们来看看如何保存注册表里任意一个键以及它的所有子键。
所需要用到的函数是RegOpenKeyEx,RegSaveKey和RegCloseKey。
看他们的名字,你也可以看出来他们是做什么用的。
RegOpenKeyEx负责打开指定的键。
在后文,也许我们会用到另一个函数打开某个特定的键:
RegCreateKeyEx。
这里先把他们做一个比较:
这两个函数都适用于基于win32的应用程序,都可以打开指定子键。
所不同的是,当指定子键不存在时,RegCreateKeyEx会自动生成这个键,而RegOpenKeyEx仅仅是负责打开。
如果指定键不存在,RegOpenKeyEx返回失败信号。
下面,让我们看看具体的操作:
LONGRegOpenKeyEx(
HKEYhKey,//用于打开键的句柄
LPCTSTRlpSubKey,//储存打开子键名称的变量的地址
DWORDulOptions,//保留值
REGSAMsamDesired,//访问形式
PHKEYphkResult//句柄的地址
);
这个函数是一个long型函数,如果执行成功,会返回ERROR_SUCCESS。
为了大家看得明白,我把每个变量都解释一下,磨刀不误砍柴工。
HKEYhKey:
这个句柄其实就是下面几个东西里的一个,打开注册表,大家对他们都不陌生吧。
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
WindowsNT:
HKEY_PERFORMANCE_DATA
Windows95andWindows98:
HKEY_DYN_DATA
LPCTSTRlpSubKey:
LPCTSTR是一个指向字符串常量的一个32位指针类型,字符可以是Unicode和DBCS。
lpSubKey里可以放指针,也可以用变量,就像本文所用的。
DWORDulOptions:
这个没什么好说的,保留值,永远都是0,如果你想要继续干活的话。
REGSAMsamDesired:
访问形式,可以有下面几个值:
Value
Meaning
KEY_ALL_ACCESS
包括KEY_QUERY_VALUE,KEY_ENUMERATE_SUB_KEYS,KEY_NOTIFY,KEY_CREATE_SUB_KEY,KEY_CREATE_LINK和KEY_SET_VALUE.
KEY_CREATE_LINK
Permissiontocreateasymboliclink.(我不太明白)
KEY_CREATE_SUB_KEY
可以生成子键
KEY_ENUMERATE_SUB_KEYS
可以枚举子键
KEY_EXECUTE
可读
KEY_NOTIFY
Permissionforchangenotification.(也不太明白,没用过)
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.
PHKEYphkResult:
函数生成的指向打开键的一个句柄,后面的RegSaveKey函数就要用到它。
使用完毕后,我们需要用RegCloseKey回收。
解释完了RegOpenKeyEx函数,让我们看看如何回收句柄RegCloseKey:
LONGRegCloseKey(
HKEYhKey//需要回收的句柄,就是上文的“PHKEYphkResult”
);
如果函数执行成功,返回值也是ERROR_SUCCESS。
另外一个回收句柄的函数是RegFlushKey。
退出前,RegFlushKey会往注册表里写一些信息,这个步骤可能会需要好几秒,机器需要完成一个从内存写入硬盘的过程,同时,这个函数会占用大量的系统资源,非必要时不要使用。
RegCloseKey则是一个退出迅速的家伙,不会拖泥带水,“我们一直都用它”:
D
现在你可能对打开一个键和关闭一个键都有点了解了,下面是操作的重点,打起精神来吧:
)
LONGRegSaveKey(
HKEYhKey,//所要备份键的句柄
LPCTSTRlpFile,//储存文件的指针
LPSECURITY_ATTRIBUTES//生成文件的安全权限
);
HKEYhKey:
就是我们用RegOpenKeyEx得到的那个新句柄。
LPCTSTRlpFile:
这个函数把一个键和他的所有子键存储到一个文件中,这里的lpFile代表文件名的变量的地址,不过你也可以直接把文件名放在这里,我会show给你看的。
LPSECURITY_ATTRIBUTES:
这个东西说来话长,MSDN专门开了一页解释SECURITY_ATTRIBUTES这个东西,感兴趣的朋友可以自己看看,我们这里用得很简单,NULL就可以了。
使用NULL意味着生成文件遵从默认的安全准则。
好了,呼出一口气,枯燥的教条终于完了。
也许你已经跃跃欲试了。
好,就让我们写一个简单的程序。
测试条件:
VC6.0,WindowXPPrefessional,登陆账号:
管理员(这个条件后面会提到)
#include"stdafx.h"
#include"windows.h"
#include"stdio.h"
#include"stdlib.h"
voidmain()
{
CStringstrKey="Software\\Microsoft\\InternetExplorer\\Main";
LPTSTRszSaveFileName;
HKEYhResult;
szSaveFileName=LPTSTR("1.dat");//要保存的文件名
RegOpenKeyEx(
HKEY_CURRENT_USER,
(LPCTSTR)strKey,
0,
KEY_ALL_ACCESS,
&hResult);//获得句柄
RegSaveKey(hResult,szSaveFileName,NULL);//保存键值
RegCloseKey(hResult);//释放句柄
}
没错就是这么简单,如果你仔细阅读了上面的讲解,看懂这一段一定没有问题。
编译通过,没有问题。
以后就可以这样照葫芦画瓢了。
你要做的只是把
CStringstrKey="Software\\Microsoft\\InternetExplorer\\Main"和RegOpenKeyEx里的“HKEY_CURRENT_USER”换成你要保存的键就可以了。
运行吧,你会看到当前目录下生成了一个1.dat文件。
成功了?
仔细看看文件大小。
0K?
!
!
怎么回事?
一定是哪里出了错误。
我们一共就调用了三个函数,是哪一个出错了呢?
加入一些语句调试一下。
#defineERROR111
#defineERROR222
#defineERROR333
#defineSUCCESS44
if(RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
(LPCTSTR)strKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,KEY_CREATE_SUB_KEY|KEY_WRITE|KEY_READ,
NULL,
&Result,
NULL)!
=ERROR_SUCCESS)
{
cout<<"ErrorOpeningRegister...\n";
returnERROR1;
}
if(RegSaveKey(Result,szSaveFileName,NULL)!
=ERROR_SUCCESS)
{
cout<<"ErrorsavingRegister...\n";
returnERROR2;
}
RegCloseKey(Result);
returnSUCCESS;
注意,这里我换用了RegCreateKeyEx这个函数,只是想show一下这个函数的用法。
大家可以跳过去,或者依然是用RegOpenKeyEx。
最后发现,在调用RegSvaeKey的时候出错了。
所有的这一些都是按照MSDN上的指示一步步来的,语法也没有问题,那会是哪里的原因呢?
我在RegSaveKey后面使用了一段测试代码,发现运行的时候,系统提示没有权限备份注册表。
请注意,我可是用管理员的身份登陆XP的……真正的原因我们还是要去权限里找(在MSDN里搜索WindowsNTPrivileges,可以看到相关的东西)。
这里简单说一下,在NT/2K/XP下失败的原因是没有SE_BACKUP_NAME权限。
我们需要加入下面一段代码(基本功能是开一个线程申请权限,具体的恕不多介绍了,以后大家只要直接加入就可以了)。
HANDLEhToken;
TOKEN_PRIVILEGEStkp;
if(!
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
return;
LookupPrivilegeValue(NULL,SE_BACKUP_NAME,&tkp.Privileges[0].Luid);
tkp.PrivilegeCount=1;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
好了,大家辛苦了。
完整的程序如下:
#include"stdafx.h"//请千万不要忘记
#include"windows.h"//这两个头文件
#include"stdio.h"
#include"stdlib.h"
voidmain()
{
CStringstrKey="Software\\Microsoft\\InternetExplorer\\Main";
LPTSTRszSaveFileName;
HKEYhResult;
//申请备份权限
HANDLEhToken;
TOKEN_PRIVILEGEStkp;
if(!
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
return;
LookupPrivilegeValue(NULL,SE_BACKUP_NAME,&tkp.Privileges[0].Luid);
tkp.PrivilegeCount=1;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
//开始备份工作
szSaveFileName=LPTSTR("1.dat");
RegOpenKeyEx(HKEY_CURRENT_USER,(LPCTSTR)strKey,0,KEY_ALL_ACCESS,&hResult);
RegSaveKey(hResult,szSaveFileName,NULL);
RegCloseKey(hResult);
}
好了,到目前为止,我们已经学会了如何备份一个子键。
可是如何备份整个HKEY_CURRENT_USER乃至于整个注册表呢?
这是我们第三部分的内容。
下一讲我们将会学到如何枚举所有的子键,并且结合MSDN上的一个例子,给大家做一个分析,同时也对这一讲的内容作一个复习。
Thankyousomuchforreadingthisarticle.
===============================================================
附录:
测试出错的代码:
longt=RegSaveKey(Result,szSaveFileName,NULL);
{
LPVOIDlpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
t,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//Defaultlanguage
(LPTSTR)&lpMsgBuf,
0,
NULL);
AfxMessageBox((LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
}
第三章保存整个注册表
PARTI一个MSDN上的例子
上次我们学习了如何保存一个子键以及其所有从属子键。
不过,你有没有想过要备份整个HKEY_LOCAL_MACHINE这个根键或者整个注册表五个根键呢?
上一次的方法如果你试试看,就会发现不适用了,呵呵。
今天我打算结合MSDN上的一个例子谈一谈远程备份注册表的问题。
学会远程备份,结合下一次的内容(修改注册表),大家可能自己就能够写程