|
一、问题的提出 ; a; L1 N- X2 t
Windows 已由原来的16位 windows 3.x 升级为现今我们使用的32位windows 95/97/98( [$ }8 v5 `. y" F' {6 R
以其 Windows NT,用户不仅在使用上应逐步适应,对于程序开发人员来说在编程技术; O, l' A# W$ U
上也应紧跟操作系统的技术发展,就如同 在 Linux 操作系统下, X-Window 编程就显3 f5 ]1 c4 ~9 _5 D
得很重要一样。作为一个完整成熟的 Windows 程序,需要保存程序所有的环境变量和8 u; L3 a. u/ P0 B. a
私有信息。诸如用户的偏好,文件装入的列表、退出时用户使用的窗口位置 .存盘历史$ r7 H0 x0 D# @; Y
纪录等。过去在 windows 3.x时代 ,常用 Win16函数 Get/RegWrite ProfileString
% B8 ~/ e) M% }* e, D6 J' A将有关程序的信息写入 *.ini 文件,但现在该项技术由 Win32注册表所替代。/ Z3 q# @% j8 B1 [4 r* E
可以这样说,注册表是当今32位 Windows 操作系统的灵魂,一切信息都在其中,也就
$ O( j& [; N% x# o; u: U是为什么Windows98在Windows95的基础上升级可以不重装软件等等
* Q$ y( V& x% H B6 T% R的如此方便的应用,其原理就是根据了原注册表中的信息来完成各种方便的处理,所以
7 l4 c* m; j/ |& D$ JWindows注册表对应用程序的重要性就显而易见了。+ ?, I* v B8 A) d2 g9 w( b
原来的 Win16程序存储私有信息是在一个平面文件INI中,这样做有很多弊端,例如该: _0 L$ @0 n5 b9 U8 Z$ r
INI文件没有任何安全机制,用户可以直接在INI文件中修改各种参数和程序入口,这样
' E+ ]3 B4 d* ^, k" F# }就可能造成不可估计的严重后果,还有该文件只能支持和文本数据不能存入二进制数据
/ @& E- b6 i% o$ D; F; `等各种不利因素,所以微软的工程师也认识到这一点,于是注册数据库就诞生了,注册9 D5 n" e' o6 y" x! M
数据库就是为了解决在 Windows 3.x 的一些关于 OLE 的此类问题而创建的,现在
6 x0 b( W/ v i; XWin32 应用程序的注册数据库通过微软带给我们的新的 Win32 API 得到了显著的改7 @! S3 h4 [4 D" w* @
善。使用访问注册表的 Win32 函数比起使用管理 INI 文件的 Win16函数要灵活的多,+ g; Z% z7 f) v1 s
这意味着在功能上将大大增强,但是,另一方面,如果你还未用过,就会对处理注册表
/ s% g* B; d2 \的Win32 API 的新规则感到困惑或不知所措。本文就是本着这一目的,逐步让你懂得并
- r5 g9 p# \+ w! `# d掌握怎样用 Win32API 函数来处理32位 Windows 程序注册表的方法。
" Q* S( F8 I& _6 D d/ n. W# S% }0 V# U0 x v9 F& W* c
二 . 技术的实现原理
$ a- n: E+ [' v# G为了在以后自己编写的程序中更多的体现模块化思想以及使编程变得更加简单,应尽可
4 L+ l6 J! }( l+ Z5 @ u. }能的建立自己实现各种功能的类,以类作为实现应用程序各种功能的单位。 在此,可; M4 L* J8 l6 x/ T
以创建一个包括注册表许多常用功能而接口简单的类库,下面将建立 CMyRegKey类,对, w! c0 ?2 l& L
应用程序处理注册表的具体细节进行封装,从而在外部通过这个功能类方便地实现进行: D! A0 d* T, d) Z
访问注册表信息的各种操作,在外部调用其成员函数即可。以后,你就可以在每一个应
2 J/ T& U: a. S3 i: B( h! z6 l用程序中包含此类并用其外部接口进行编程了。 & M1 u, S9 `2 o# k: _9 D9 W$ S
三 . 实现代码与步骤 9 K+ K4 R+ M- `! E# C) T
2 j+ P2 }6 q- {3 b: Q- T" t1. 建立功能类的头文件:
# l h: e3 k5 m* N; f2 J9 R- A创建一个新的头文件 MyRegKey.h ,在其中加入以下的代码。
* Z$ X2 S" X3 V) k- ^' q
4 r& n0 V+ ]3 |: w4 i! g- H ~$ a#include "winreg.h"
: a- m: {: l1 F% }6 t- B- u& [1 m. @// 包含头文件 winreg.h , 因注册表Win32 API 函数在其内定义 # r: R& u5 I6 U5 i3 @) \
// 建立 CMyRegKey 类:
% k- k: k9 I; ~+ _- l0 e( I# Iclass CMyRegKey
( a' ]7 w% D4 a( n, r7 n' t; ]' P{
$ }8 u+ r% }! ~8 \) M" r! m# J _
// Construction
" P. @& }- K/ D4 c5 S1 ]- \- q, dpublic:
) }5 l6 M& A5 l" g" l2 |CMyRegKey();
& \! M! A2 J5 q& |0 t D6 hvirtual ~CMyRegKey ();
9 B7 b/ k. j, N0 s4 e& N/ Q// Attributes; q$ j9 U' G3 n' v" f, y3 @
public:
2 n6 W5 P) e v// 定义打开和关闭注册表的成员函数:
9 a3 {; `$ j$ s7 YLONG RegRegOpen(HKEY hKeyRoot,LPCTSTR pszPath);* L7 z) ]9 K( R+ h# e
void RegRegClose();
$ d- }: B* }7 T- P- Z7 H6 }// 利用函数重载实现对注册表键值(串值,二进制值,DWORD值 ) 的读和写:
" t3 K" x6 [. F: H/ ^LONG RegRead (LPCTSTR pszKey,DWORD& dwVal);
: J" o& o1 R1 t% u5 T S" |& ?" yLONG RegRead (LPCTSTR pszKey,CString& sVal);8 C! n4 d/ c1 X: M& W
LONG RegRead (LPCTSTR pszKey,BYTE *pData,DWORD& dwLength);
4 b3 |; \9 ^" {( ~& CLONG RegWrite (LPCTSTR pszKey,DWORD dwVal);
8 f9 z+ z- j# j1 U" d/ ^LONG RegWrite (LPCTSTR pszKey,LPCTSTR pszVal);' ^; q+ ?" n" J' A1 C
LONG RegWrite (LPCTSTR pszKey,const BYTE *pData,DWORD dwLength);
7 Y2 i2 E$ |$ k& R/ Qprotected:; r( H8 a/ d. s+ d( D
HKEY m_hKey;" q ~0 X' O# o* U. P0 A; X
CString m_sPath;! X1 A7 s3 |% f) B. `- m5 |% [
}; * b% t! J: X7 J; i& Q
2. 建立功能类的Cpp文件定义 CMyRegKey类: ; q; V \& r$ b) [& ~. L3 T5 u% B
创建一个新文件 MyRegKey.cpp ,代码如下:
( _3 e6 ]3 y; B( m+ Q$ u! Y1 _+ U6 g, O5 G: ?) l" l6 W
#include "MyRegKey.h"
7 D# X5 f! Q: c( s2 c! \2 \% |2 f////////////////////////////////////////////////////////////////////////////
2 g' N+ W; ~4 `' @. R; \" k/" m2 [! J6 b; J0 U4 E) t9 c
// CMyRegKey
5 l3 _+ s2 c: J o////////////////////////////////////////////////////////////////////////////; H- |* T( _8 C2 u
/
/ o7 B; U9 v& h2 M$ m2 UCMyRegKey:: CMyRegKey()
( A* _, Y0 h# [- h8 `{
y8 e" w+ b7 t0 |1 vm_hKey = NULL;
% Q6 q* p; i# [% v2 R# j} $ @- G: U N3 d1 ^5 b# Y
CMyRegKey:: ~CMyRegKey()" S, n0 |6 w) a: o7 [/ p3 i
{8 \3 s* O/ h* u5 l
RegClose();
9 z" \( t% o1 n5 h}
Z. I) A! ]1 s7 [% T" M// 定义打开注册表的函数,RegOpen 函数带有两个参数:指定要访问注册表根结点的, E( D' F2 k- ~( T4 ~& w; V v# n1 `7 D
HKEY, 以及注 . h% i' z8 l( i9 `
// 册表中信息的全路径。如果给入的路径不存在,则需创建一个新路径。从
4 S: w1 J. i! `: ?9 |7 ` o& h wRegCreateKeyEx API函数返// 回的 HKEY 作为 m_hKey 存储。
6 `8 Z2 m4 ]+ G% cLONG CMyRegKey::RegOpen(HKEY hKeyRoot,LPCTSTR pszPath) + Y( ] |: R3 u$ a2 b
{
, ~+ j: M3 _4 E S8 M l K$ @DWORD dw;
2 y1 C- ?, {; b3 ^7 `1 Q7 \m_sPath = pszPath; " s. w9 W; C) d' t% \0 ~% o3 w
return
7 C& H7 |" |3 p$ r) u! M" f- DRegCreateKeyEx(hKeyRoot,pszPath,0L,NULL,REG_OPTION_VOLATILE,KEY_ALL_ACCESS,N
3 X0 ?9 c1 c/ ?- }5 ZULL,
, `2 n) {/ G* ?&m_hKey,&dw);/ ?4 Y% f2 q0 ~* J+ P k2 {
}
J" r" @. [, evoid CMyRegKey::RegClose()
3 s: _3 ~! K! v9 n& L{ D+ W* f6 i' j5 g& Z1 w
if(m_hKey)
9 u& y3 P9 z7 d) F6 I( l' U ^{: E# u# t% m3 j$ o$ c9 W7 j: L
RegCloseKey (m_hKey);7 o8 I: b m4 d; Z" @
m_hKey = NULL; 7 g7 [- c/ |7 @0 q" P. l
}
: ^7 @7 e: y* ]. I8 I% V! a} 6 @7 m3 B% c8 e$ c k; m
LONG CMyRegKey::RegWrite(LPCTSTR pszKey,DWORD dwVal)' W6 s F# ?" I* W2 N5 Y7 N' o) I
{
7 }; R4 m3 q* B% z- L8 K: eASSERT(m_hKey); * Z. V' |4 {/ h& ?1 I
ASSERT(pszKey);
. L3 j% p0 N. e! F) @' Q9 mASSERT(pData&&dwLength>0);( @; L8 f- f: ]
ASSERT(AfxIsValidAddress(pData,dwLength,FALSE));
3 y1 K. G [! F$ @return RegSetValueEx(m_hKey,pszKey,0L,REG_DWORD,(CONST BYTE- r9 z* S# Z y' b6 @& {
*)&dwVal,sizeof(DWORD));
' ]3 i- _$ A: M+ u2 l! T} * {6 y2 k5 s' x) x; r6 j9 _
LONG CMyRegKey::RegWrite(LPCTSTR pszKey,LPCTSTR pszData)* J7 p# j( H$ S& ?! s6 r5 K
{ 9 c) d# j) {( F9 X+ J4 E2 g
ASSERT(m_hKey);
" y8 x( i8 H6 [. g E# U+ hASSERT(pszKey);
/ o9 }$ G" Q% A. @ASSERT(pszData);
$ I9 q* i( c& UASSERT(pData&&dwLength>0);
( \+ O( e1 e; Y2 p8 ~9 e3 ?3 _3 eASSERT(AfxIsValidAddress(pszData,strlen(pszData),FALSE));
1 {; H) _$ A1 f0 _+ sreturn RegSetValueEx(m_hKey,pszKey,0L,REG_SZ,(CONST BYTE *)pszData,strlen
5 Y3 s& I, S/ a. R3 T# \1 i(pszData)+1);
" `3 V) U# n/ j# v} & Z( x& S* _9 a, E
LONG CMyRegKey::RegWrite(LPCTSTR pszKey,const BYTE *pData,DWORD dwLength)# T2 S( ^) k# j# ?
{ # r; o! G( R; x) p
ASSERT(m_hKey);* F* a U2 n& d* A D- r
ASSERT(pszKey);
+ b/ Q' n9 u( D! ?, v( C9 iASSERT(AfxIsValidAddress (pData,dwLength,FALSE));
$ T9 Y8 ^3 f8 K6 v. ~: H( PASSERT(pData&&dwLength>0);0 @. u, a/ `1 L, ]7 o6 V# l9 Z
ASSERT(AfxIsValidAddress(pData,dwLength,FALSE)); E& {9 f8 K* W [2 A. A3 D' v
return RegSetValueEx(m_hKey,pszKey,0L,REG_BINARY,pData,dwLength);
" N* ?$ g- p0 L0 _% L7 m/ [1 Y; e* x5 g}
4 j# [+ K6 v2 k- P3 aLONG CMyRegKey::RegRead (LPCTSTR pszKey,DWORD& dwVal)8 K6 y$ ^" F3 T; o, b" ~. G
{ 1 G5 h4 j1 q$ f
ASSERT(m_hKey);
+ Z2 C7 M5 ~4 Z! m4 MASSERT(pszKey); ) g" B+ x) ?( S9 }4 a" M' P1 r" I
DWORD dwType;! l' } f6 ?. m' Z! w, W, E
DWORD dwSize = sizeof (DWORD);" `4 ]/ l% z( m* a: B! z7 u' `5 G
DWORD dwDest;
( V1 W' t, T& E: P" OLONG LRet = RegQueryValueEx(m_hKey,(LPSTR)pszKey,NULL,&dwType,(BYTE *)* U" b' |) |# a5 q$ D! U, @' g
&dwDest,&dwSize);
5 D1 ?- S5 R! L% _2 C( K/ kif(LRet==ERROR_SUCCESS) b* s( |. U& J/ @: u6 E1 v" m
dwVal = dwDest;+ C* g* J0 f6 ~
return LRet; : R3 ?. P$ H# I2 ?
} 9 o/ z& ?2 X8 v' y7 v7 T: q
LONG CMyRegKey::RegRead (LPCTSTR pszKey,CString& sVal)
. ^0 N' k2 D Z; t/ |( T{
6 x+ D2 G2 [1 k7 i! w% OASSERT(m_hKey);9 I, b( F6 z* X9 \; a: k
ASSERT(pszKey); ' W% {; ?" j5 [' n
DWORD dwType;
) i2 j' H: b% \( iDWORD dwSize = 200;, U; t c8 P3 J' ^ h
char string[200]; # h+ y1 u! p! G
LONG IReturn = RegQueryValueEx(m_hKey,(LPSTR)pszKey,NULL,&dwType,(BYTE *)2 K% V# ^( c, U; R% U
string,&dwSize); X: k( j- x( D6 Q, A% s3 d
if(IReturn==ERROR_SUCCESS) ( E9 }4 P& N9 [. W/ N' u
sVal = string;
8 a& I) B5 ]% \5 mreturn IReturn; 4 `2 A2 N5 r9 @ Q$ U
}
, i, z- f9 A8 F& T2 LLONG CMyRegKey::RegRead (LPCTSTR pszKey,BYTE * pData,DWORD& dwLen)+ E* n+ f1 O0 v) q% j) ]
{ 6 k7 Z- D( ]8 X+ ?
ASSERT(m_hKey);! P" \1 f6 \" ?& M0 l( _
ASSERT(pszKey); 8 \- F6 P9 A7 B
DWORD dwType;% E* T9 b% A) H: Z4 G( x* }
return RegQueryValueEx(m_hKey,(LPSTR)pszKey,NULL,&dwType,pData,&dwLen); $ M7 ]; I0 D$ |) Q; Q: `9 l
} , A: e. r, i/ F/ P- W1 x$ U
在用户需要使用时只需在你的 Project 中的 SorceFile 和 HeadFile 中分别加入
* ~* R1 ^7 B& J; b( s5 t: m$ E+ mMyRegKey.cpp 以及 MyRegKey.h 程序文件。 ! X# H& D u$ c+ D
四 . 使用外部接口示例
4 Z2 x" T/ n7 u+ x: E* J% ]3 w$ d3 W. }0 W0 {
在VC中建立一个基于对话框(Dialog Base) 的应用程序,在对话框上放上几个Edit5 \% h- r1 d/ v& F' s7 a% J$ J0 q1 |, V
control 的控件,如同示例小程序 RegTech 框(见图一), 程序执行时,首先读出注
4 S- l* x3 G' S/ o+ J册表信息分别显示在三个编辑栏中,为了演示写入操作,你可以在注册用户栏中重新输
# W% l! l7 a8 i) P+ R b入用户名,按更改完成写入,重新运行程序,查看写入是否成功。在RegTech 框中安置
- W' h' x3 m( Y) w) r/ u了三个编辑栏,ID 为 IDC_INSTALL,IDC_USERID,IDC_VERSION,( q. X6 ^ r E; Z }* C
用ClassWizard 的Member Variable 分别加上对象参数:m_Install, m_UserID 和% `4 F! r8 O# O, P8 l# n) \: d" ]: j& P
m_Version.3 e0 c" d! o( p* Y; ~$ v
用参数来传递注册表键值。 . q+ o% J R' B9 u* Q/ b. p/ z
在初始化对话框时就应打开注册表并读取所需的信息,这三项存放路径为+ K$ k" C6 w: _" v+ X
HKEY_LOCAL_MACHINE \SOFTWARE \Microsoft \Windows \CurrentVersion下,) y+ ~2 n5 I+ q( ~3 t& U. k$ U
分别读出windows 版本号(放置于Version键值中),注册用户名(放置于
! F1 W# Y0 _: x2 i, cRegisteredOwner键值中),Windows 安装目录(放置于SystemRoot 键值中 ),更多2 Z5 F/ W! o! `4 j
的信息请使用Windows 目录下的 RegEdit.exe程序.
7 q; k0 G$ I( m0 K# W$ r* P需用到注册表类的原程序文件中加上 #inxlude " MyRegKey.h" 即可。
+ D, v/ h$ v( l/ J# b, Y4 s* q( q在文件 RegTechDlg.cpp 中初始化对话框的地方加上以下代码打开路径并读取键值:
: r) u3 R5 M( e( T* {$ LBOOL CRegtechDlg::OnInitDialog()* n2 X5 r$ z |: s9 N
{ 9 P: \$ n) l' B2 q* u
CDialog::OnInitDialog(); 4 K0 }* v4 y0 f ~4 V4 ?0 ?% A- Z
......................1 G* B+ ^3 `( `- r s
......................
8 M) b% x3 T; Y4 L! x// TOD Add extra initialization here
1 V9 ^/ z7 d' Y# g' e" O/ L# @+ h
file://########################################### 4 y/ S& j3 w! W' B3 J& g- Q
// 打开注册表路径 .
2 z7 X' m. S; f* aCMyRegKey regKey1,regKey2,regKey3; ( O) ]6 L& h7 ]" d# D! @
regKey1.RegOpen(HKEY_LOCAL_MACHINE,
* h8 A) P+ v2 J/ E9 l_T("Software\\Microsoft\\Windows\\CurrentVersion"));+ @! R' p, b7 V. H
regKey2.RegOpen(HKEY_LOCAL_MACHINE, R5 L# t' A0 r3 p1 p9 X
_T("Software\\Microsoft\\Windows\\CurrentVersion"));
) S! v: N" m2 s+ M. _2 T2 f+ EregKey3.RegOpen(HKEY_LOCAL_MACHINE,
9 P, J$ n- F; O_T("Software\\Microsoft\\Windows\\CurrentVersion"));
4 p5 N' C9 k1 ? r* D ]0 P6 F
! W9 A/ ~1 M: _. C# S+ D+ }// 读取键值并分别传递到编辑控件参数中去:
# F! q; n( O7 J" A; XregKey1.RegRead(_T("Version"),m_Version);* Q& J, e/ N A: H6 j1 V
regKey2.RegRead(_T("RegisteredOwner"),m_UserID);
6 ?- x8 X: k% k$ gregKey3.RegRead(_T("SystemRoot"),m_Install);) r8 r0 u- U7 ^) Y4 W( {1 n1 U8 K# b
UpdateData(FALSE); 5 ]) M9 j0 Q! |' B$ U8 F
file://############################################
+ n6 ^5 E( `1 T8 s4 g! E( S* Jreturn TRUE; // return TRUE unless you set the focus to a control
! E: p* E; T" e. s3 s8 \6 P) p}
9 i D. }- F y' l: s在重新输入了注册用户名后,按下更改按钮(按钮控件ID_ChangeID),将完成注册表( T6 N* ?- p* @6 C
的写入操作: ) E" m$ ~8 P5 y P. K
void CRegtechDlg::OnChangeID()) A( p& |' M3 s( a+ U
{
1 o i6 Y+ h, t* A' C1 K9 c
# B2 i' l; \9 [2 @2 h$ r* r( dfile://######################## ; j9 l; K2 r1 r
CMyRegKey regKey;
3 s- ?; q$ T, ?) {
8 g! {" ?0 S0 {- @ Q, aregKey.RegOpen(HKEY_LOCAL_MACHINE,! b( R. R# c) Z7 X& j$ X0 f
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")); $ b l( A+ k; T+ a8 r
// 传递从编辑拦输入的值并写入打开路径的指定键值名中:
- {' h* q$ p* l7 PUpdateData(TRUE);
( ]" @, r6 f$ e& k5 a/ m, N4 FregKey.RegWrite(_T("RegisteredOwner"),m_UserID);
0 \# q1 a& Q/ w0 xMessageBox("更改注册用户名完毕!","Message",MB_ICONINFORMATION|MB_OK);
) \5 k0 U! y9 s7 J
5 L4 [8 _% ?% S0 m9 O$ k///#########################
3 V1 I% ?. q: ]3 {$ y, z: r
- z3 i4 F& P9 }// TOD Add your control notification handler code here 5 p- p$ o7 o: a2 v8 Y
}
6 r" S+ |& t4 z) m& }注册表类在实际应用程序编制中使用频率极高,比如程序员自定义的文件的图标选择等8 i% N/ l* E z% u- k" H
的很多地方都要用到,所以一个成熟优秀的应用程序应尽可能的适应环境及发挥操作系0 m; @: i H( M) H2 m
统的各种优势,在此,使用win32 API对Windows灵魂--注册表存取技术的操作已完
6 r, Z, [$ G& D* }% K,你就可以利用它来完善自己的应用程序了。 |