4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
7 * December 21, 1997 - Kevin Cozens
8 * Fixed bugs in the _w95_loadreg() function. Added extra information
9 * regarding the format of the Windows '95 registry files.
12 * When changing this file, please re-run the regtest program to ensure
13 * the conditions are handled properly.
18 * Time for RegEnumKey*, RegQueryInfoKey*
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
42 static void REGISTRY_Init();
43 /* FIXME: following defines should be configured global ... */
45 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
46 #define WINE_PREFIX "/.wine"
47 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
48 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
50 /* relative in ~user/.wine/ : */
51 #define SAVE_CURRENT_USER "user.reg"
52 #define SAVE_LOCAL_MACHINE "system.reg"
54 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
55 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57 /* one value of a key */
58 typedef struct tagKEYVALUE
60 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
61 DWORD type
; /* type of value */
62 DWORD len
; /* length of data in BYTEs */
63 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
64 LPBYTE data
; /* content, may be strings, binaries, etc. */
65 } KEYVALUE
,*LPKEYVALUE
;
68 typedef struct tagKEYSTRUCT
70 LPWSTR keyname
; /* name of THIS key (UNICODE) */
71 DWORD flags
; /* flags. */
74 DWORD nrofvalues
; /* nr of values in THIS key */
75 LPKEYVALUE values
; /* values in THIS key */
76 /* key management pointers */
77 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
78 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
79 } KEYSTRUCT
, *LPKEYSTRUCT
;
82 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
83 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
84 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
85 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
87 /* dynamic, not saved */
88 static KEYSTRUCT
*key_performance_data
=NULL
;
89 static KEYSTRUCT
*key_current_config
=NULL
;
90 static KEYSTRUCT
*key_dyn_data
=NULL
;
92 /* what valuetypes do we need to convert? */
93 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
96 static struct openhandle
{
101 static int nrofopenhandles
=0;
102 /* Starts after 1 because 0,1 are reserved for Win16 */
103 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
104 HKEYs for remote registry access */
105 static int currenthandle
=2;
110 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
111 * If so, can we remove them?
113 * No, the memory handling functions are called very often in here,
114 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
115 * loading 100 times slower. -MM
117 static LPWSTR
strdupA2W(LPCSTR src
)
120 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
121 lstrcpyAtoW(dest
,src
);
127 static LPWSTR
strdupW(LPCWSTR a
) {
132 len
=sizeof(WCHAR
)*(lstrlen32W(a
)+1);
133 b
=(LPWSTR
)xmalloc(len
);
140 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
143 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
145 lstrcpynAtoW(dest
,src
,nchars
+1);
151 /******************************************************************************
152 * is_standard_hkey [Internal]
153 * Determines if a hkey is a standard key
155 static BOOL32
is_standard_hkey( HKEY hkey
)
160 case HKEY_CLASSES_ROOT
:
161 case HKEY_CURRENT_CONFIG
:
162 case HKEY_CURRENT_USER
:
163 case HKEY_LOCAL_MACHINE
:
165 case HKEY_PERFORMANCE_DATA
:
173 /******************************************************************************
174 * add_handle [Internal]
176 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
180 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
181 /* Check for duplicates */
182 for (i
=0;i
<nrofopenhandles
;i
++) {
183 if (openhandles
[i
].lpkey
==lpkey
) {
184 /* This is not really an error - the user is allowed to create
185 two (or more) handles to the same key */
186 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
188 if (openhandles
[i
].hkey
==hkey
) {
189 WARN(reg
, "Adding handle %x twice\n",hkey
);
192 openhandles
=xrealloc( openhandles
,
193 sizeof(struct openhandle
)*(nrofopenhandles
+1));
195 openhandles
[i
].lpkey
= lpkey
;
196 openhandles
[i
].hkey
= hkey
;
197 openhandles
[i
].accessmask
= accessmask
;
202 /******************************************************************************
203 * get_handle [Internal]
206 * Success: Pointer to key
209 static LPKEYSTRUCT
get_handle( HKEY hkey
)
213 for (i
=0; i
<nrofopenhandles
; i
++)
214 if (openhandles
[i
].hkey
== hkey
)
215 return openhandles
[i
].lpkey
;
216 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
221 /******************************************************************************
222 * remove_handle [Internal]
225 * hkey [I] Handle of key to remove
228 * Success: ERROR_SUCCESS
229 * Failure: ERROR_INVALID_HANDLE
231 static DWORD
remove_handle( HKEY hkey
)
235 for (i
=0;i
<nrofopenhandles
;i
++)
236 if (openhandles
[i
].hkey
==hkey
)
239 if (i
== nrofopenhandles
) {
240 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
241 return ERROR_INVALID_HANDLE
;
244 memcpy( openhandles
+i
,
246 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
248 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
250 return ERROR_SUCCESS
;
253 /******************************************************************************
254 * lookup_hkey [Internal]
256 * Just as the name says. Creates the root keys on demand, so we can call the
257 * Reg* functions at any time.
260 * Success: Pointer to key structure
263 #define ADD_ROOT_KEY(xx) \
264 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
265 memset(xx,'\0',sizeof(KEYSTRUCT));\
266 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
268 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
271 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
272 * some programs. Do not remove those cases. -MM
276 case HKEY_CLASSES_ROOT
: {
277 if (!key_classes_root
) {
280 /* calls lookup_hkey recursively, TWICE */
281 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
282 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
285 key_classes_root
= lookup_hkey(cl_r_hkey
);
287 return key_classes_root
;
289 case HKEY_CURRENT_USER
:
290 if (!key_current_user
) {
294 pwd
=getpwuid(getuid());
295 /* calls lookup_hkey recursively, TWICE */
296 if (pwd
&& pwd
->pw_name
) {
297 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
298 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
301 key_current_user
= lookup_hkey(c_u_hkey
);
303 /* nothing found, use standalone */
304 ADD_ROOT_KEY(key_current_user
);
307 return key_current_user
;
308 case HKEY_LOCAL_MACHINE
:
309 if (!key_local_machine
) {
310 ADD_ROOT_KEY(key_local_machine
);
313 return key_local_machine
;
316 ADD_ROOT_KEY(key_users
);
319 case HKEY_PERFORMANCE_DATA
:
320 if (!key_performance_data
) {
321 ADD_ROOT_KEY(key_performance_data
);
323 return key_performance_data
;
326 ADD_ROOT_KEY(key_dyn_data
);
329 case HKEY_CURRENT_CONFIG
:
330 if (!key_current_config
) {
331 ADD_ROOT_KEY(key_current_config
);
333 return key_current_config
;
335 return get_handle(hkey
);
340 /* so we don't accidently access them ... */
341 #define key_current_config NULL NULL
342 #define key_current_user NULL NULL
343 #define key_users NULL NULL
344 #define key_local_machine NULL NULL
345 #define key_classes_root NULL NULL
346 #define key_dyn_data NULL NULL
347 #define key_performance_data NULL NULL
349 /******************************************************************************
350 * split_keypath [Internal]
351 * splits the unicode string 'wp' into an array of strings.
352 * the array is allocated by this function.
353 * Free the array using FREE_KEY_PATH
356 * wp [I] String to split up
357 * wpv [O] Array of pointers to strings
358 * wpc [O] Number of components
360 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
365 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
367 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
369 /* We know we have at least one substring */
372 /* Replace each backslash with NULL, and increment the count */
373 for (i
=0;ws
[i
];i
++) {
382 /* Allocate the space for the array of pointers, leaving room for the
384 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
387 /* Assign each pointer to the appropriate character in the string */
392 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
397 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
402 /******************************************************************************
403 * REGISTRY_Init [Internal]
404 * Registry initialisation, allocates some default keys.
406 static void REGISTRY_Init() {
410 TRACE(reg
,"(void)\n");
412 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
415 /* This was an Open, but since it is called before the real registries
416 are loaded, it was changed to a Create - MTB 980507*/
417 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
418 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
421 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
425 * string RegisteredOwner
426 * string RegisteredOrganization
429 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
434 if (-1!=gethostname(buf
,200)) {
435 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
436 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
442 /************************ SAVE Registry Function ****************************/
444 #define REGISTRY_SAVE_VERSION 0x00000001
446 /* Registry saveformat:
447 * If you change it, increase above number by 1, which will flush
448 * old registry database files.
451 * "WINE REGISTRY Version %d"
455 * valuename=lastmodified,type,data
459 * keyname,valuename,stringdata:
460 * the usual ascii characters from 0x00-0xff (well, not 0x00)
461 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
462 * ( "=\\\t" escaped in \uXXXX form.)
466 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
468 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
469 * SaveOnlyUpdatedKeys=yes
472 /******************************************************************************
473 * _save_check_tainted [Internal]
475 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
481 if (lpkey
->flags
& REG_OPTION_TAINTED
)
486 if (_save_check_tainted(lpkey
->nextsub
)) {
487 lpkey
->flags
|= REG_OPTION_TAINTED
;
495 /******************************************************************************
496 * _save_USTRING [Internal]
498 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
512 if (escapeeq
&& *s
=='=')
515 fputc(*s
,F
); /* if \\ then put it twice. */
517 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
524 /******************************************************************************
525 * _savesubkey [Internal]
527 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
534 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
535 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
537 for (tabs
=level
;tabs
--;)
539 _save_USTRING(F
,lpxkey
->keyname
,1);
541 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
542 LPKEYVALUE val
=lpxkey
->values
+i
;
544 for (tabs
=level
+1;tabs
--;)
546 _save_USTRING(F
,val
->name
,0);
548 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
549 if ((1<<val
->type
) & UNICONVMASK
)
550 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
552 for (j
=0;j
<val
->len
;j
++)
553 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
556 /* descend recursively */
557 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
566 /******************************************************************************
567 * _savesubreg [Internal]
569 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
571 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
572 _save_check_tainted(lpkey
->nextsub
);
573 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
577 /******************************************************************************
578 * _savereg [Internal]
580 static BOOL32
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
586 WARN(reg
,"Couldn't open %s for writing: %s\n",
591 if (!_savesubreg(F
,lpkey
,all
)) {
594 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
602 /******************************************************************************
603 * SHELL_SaveRegistry [Internal]
605 void SHELL_SaveRegistry( void )
613 TRACE(reg
,"(void)\n");
616 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
622 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
634 if (lstrcmpi32A(buf
,"yes"))
636 pwd
=getpwuid(getuid());
637 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
641 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
642 strlen(SAVE_CURRENT_USER
) + 2 );
643 strcpy(fn
,pwd
->pw_dir
);
644 strcat(fn
,WINE_PREFIX
);
645 /* create the directory. don't care about errorcodes. */
646 mkdir(fn
,0755); /* drwxr-xr-x */
647 strcat(fn
,"/"SAVE_CURRENT_USER
);
648 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
649 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
650 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
651 if (-1==rename(tmp
,fn
)) {
652 perror("rename tmp registry");
658 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
659 strcpy(fn
,pwd
->pw_dir
);
660 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
661 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
662 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
663 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
664 if (-1==rename(tmp
,fn
)) {
665 perror("rename tmp registry");
672 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
676 /************************ LOAD Registry Function ****************************/
680 /******************************************************************************
681 * _find_or_add_key [Internal]
683 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
685 LPKEYSTRUCT lpxkey
,*lplpkey
;
687 if ((!keyname
) || (keyname
[0]==0)) {
691 lplpkey
= &(lpkey
->nextsub
);
694 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
695 !lstrcmpi32W(lpxkey
->keyname
,keyname
)
698 lplpkey
= &(lpxkey
->next
);
702 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
704 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
705 lpxkey
->keyname
= keyname
;
711 /******************************************************************************
712 * _find_or_add_value [Internal]
714 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
715 LPBYTE data
, DWORD len
, DWORD lastmodified
)
720 if (name
&& !*name
) {/* empty string equals default (NULL) value */
725 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
731 if ( val
->name
!=NULL
&&
732 val
->name
[0]==name
[0] &&
733 !lstrcmpi32W(val
->name
,name
)
738 if (i
==lpkey
->nrofvalues
) {
739 lpkey
->values
= xrealloc(
741 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
744 memset(val
,'\0',sizeof(KEYVALUE
));
750 if (val
->lastmodified
<lastmodified
) {
751 val
->lastmodified
=lastmodified
;
762 /******************************************************************************
763 * _wine_read_line [Internal]
765 * reads a line including dynamically enlarging the readbuffer and throwing
768 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
778 s
=fgets(curread
,mylen
,F
);
781 if (NULL
==(s
=strchr(curread
,'\n'))) {
782 /* buffer wasn't large enough */
783 curoff
= strlen(*buf
);
784 *buf
= xrealloc(*buf
,*len
*2);
785 curread
= *buf
+ curoff
;
786 mylen
= *len
; /* we filled up the buffer and
787 * got new '*len' bytes to fill
795 /* throw away comments */
796 if (**buf
=='#' || **buf
==';') {
801 if (s
) /* got end of line */
808 /******************************************************************************
809 * _wine_read_USTRING [Internal]
811 * converts a char* into a UNICODE string (up to a special char)
812 * and returns the position exactly after that string
814 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
819 /* read up to "=" or "\0" or "\n" */
822 /* empty string is the win3.1 default value(NULL)*/
826 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
828 while (*s
&& (*s
!='\n') && (*s
!='=')) {
830 *ws
++=*((unsigned char*)s
++);
839 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
847 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
848 if (!sscanf(xbuf
,"%x",&wc
))
849 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
851 *ws
++ =(unsigned short)wc
;
858 *str
= strdupW(*str
);
866 /******************************************************************************
867 * _wine_loadsubkey [Internal]
870 * It seems like this is returning a boolean. Should it?
876 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
877 int *buflen
, DWORD optflag
)
884 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
887 lpkey
->flags
|= optflag
;
889 /* Good. We already got a line here ... so parse it */
899 WARN(reg
,"Got a subhierarchy without resp. key?\n");
902 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
906 /* let the caller handle this line */
907 if (i
<level
|| **buf
=='\0')
910 /* it can be: a value or a keyname. Parse the name first */
911 s
=_wine_read_USTRING(s
,&name
);
913 /* switch() default: hack to avoid gotos */
917 lpxkey
=_find_or_add_key(lpkey
,name
);
920 int len
,lastmodified
,type
;
923 WARN(reg
,"Unexpected character: %c\n",*s
);
927 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
928 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
934 if ((1<<type
) & UNICONVMASK
) {
935 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
937 len
= lstrlen32W((LPWSTR
)data
)*2+2;
942 data
= (LPBYTE
)xmalloc(len
+1);
943 for (i
=0;i
<len
;i
++) {
945 if (*s
>='0' && *s
<='9')
947 if (*s
>='a' && *s
<='f')
948 data
[i
]=(*s
-'a'+'\xa')<<4;
949 if (*s
>='A' && *s
<='F')
950 data
[i
]=(*s
-'A'+'\xa')<<4;
952 if (*s
>='0' && *s
<='9')
954 if (*s
>='a' && *s
<='f')
955 data
[i
]|=*s
-'a'+'\xa';
956 if (*s
>='A' && *s
<='F')
957 data
[i
]|=*s
-'A'+'\xa';
961 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
964 /* read the next line */
965 if (!_wine_read_line(F
,buf
,buflen
))
972 /******************************************************************************
973 * _wine_loadsubreg [Internal]
975 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
981 buf
=xmalloc(10);buflen
=10;
982 if (!_wine_read_line(F
,&buf
,&buflen
)) {
986 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
990 if (ver
!=REGISTRY_SAVE_VERSION
) {
991 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
995 if (!_wine_read_line(F
,&buf
,&buflen
)) {
999 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1008 /******************************************************************************
1009 * _wine_loadreg [Internal]
1011 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1015 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1019 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1022 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1031 /******************************************************************************
1032 * _copy_registry [Internal]
1034 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1042 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1044 for (j
=0;j
<from
->nrofvalues
;j
++) {
1048 valfrom
= from
->values
+j
;
1050 if (name
) name
=strdupW(name
);
1051 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1052 memcpy(data
,valfrom
->data
,valfrom
->len
);
1060 valfrom
->lastmodified
1063 _copy_registry(from
,lpxkey
);
1069 /* WINDOWS 95 REGISTRY LOADER */
1071 * Structure of a win95 registry database.
1073 * 0 : "CREG" - magic
1075 * 8 : DWORD offset_of_RGDB_part
1076 * 0C..0F: ? (someone fill in please)
1077 * 10: WORD number of RGDB blocks
1079 * 14: WORD always 0000?
1080 * 16: WORD always 0001?
1081 * 18..1F: ? (someone fill in please)
1085 * 0 : "RGKN" - magic
1086 * 4 : DWORD offset to first RGDB section
1087 * 8 : DWORD offset to the root record
1088 * C..0x1B: ? (fill in)
1089 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1091 * Disk Key Entry Structure:
1092 * 00: DWORD - Free entry indicator(?)
1093 * 04: DWORD - Hash = sum of bytes of keyname
1094 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1095 * 0C: DWORD - disk address of PreviousLevel Key.
1096 * 10: DWORD - disk address of Next Sublevel Key.
1097 * 14: DWORD - disk address of Next Key (on same level).
1098 * DKEP>18: WORD - Nr, Low Significant part.
1099 * 1A: WORD - Nr, High Significant part.
1101 * The disk address always points to the nr part of the previous key entry
1102 * of the referenced key. Don't ask me why, or even if I got this correct
1103 * from staring at 1kg of hexdumps. (DKEP)
1105 * The High significant part of the structure seems to equal the number
1106 * of the RGDB section. The low significant part is a unique ID within
1109 * There are two minor corrections to the position of that structure.
1110 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1111 * the DKE reread from there.
1112 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1113 * CPS - I have not experienced the above phenomenon in my registry files
1116 * 00: "RGDB" - magic
1117 * 04: DWORD offset to next RGDB section
1119 * 0C: WORD always 000d?
1120 * 0E: WORD RGDB block number
1121 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1123 * 20.....: disk keys
1126 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1127 * 08: WORD nrLS - low significant part of NR
1128 * 0A: WORD nrHS - high significant part of NR
1129 * 0C: DWORD bytesused - bytes used in this structure.
1130 * 10: WORD name_len - length of name in bytes. without \0
1131 * 12: WORD nr_of_values - number of values.
1132 * 14: char name[name_len] - name string. No \0.
1133 * 14+name_len: disk values
1134 * nextkeyoffset: ... next disk key
1137 * 00: DWORD type - value type (hmm, could be WORD too)
1138 * 04: DWORD - unknown, usually 0
1139 * 08: WORD namelen - length of Name. 0 means name=NULL
1140 * 0C: WORD datalen - length of Data.
1141 * 10: char name[namelen] - name, no \0
1142 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1143 * 10+namelen+datalen: next values or disk key
1145 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1146 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1147 * structure) and reading another RGDB_section.
1148 * repeat until end of file.
1150 * An interesting relationship exists in RGDB_section. The value at offset
1151 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1152 * idea at the moment what this means. (Kevin Cozens)
1154 * FIXME: this description needs some serious help, yes.
1157 struct _w95keyvalue
{
1159 unsigned short datalen
;
1161 unsigned char *data
;
1169 struct _w95keyvalue
*values
;
1170 struct _w95key
*prevlvl
;
1171 struct _w95key
*nextsub
;
1172 struct _w95key
*next
;
1186 /******************************************************************************
1187 * _w95_processKey [Internal]
1189 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1190 int nrLS
, int nrMS
, struct _w95_info
*info
)
1193 /* Disk Key Header structure (RGDB part) */
1195 unsigned long nextkeyoff
;
1196 unsigned short nrLS
;
1197 unsigned short nrMS
;
1198 unsigned long bytesused
;
1199 unsigned short keynamelen
;
1200 unsigned short values
;
1203 /* disk key values or nothing */
1205 /* Disk Key Value structure */
1209 unsigned short valnamelen
;
1210 unsigned short valdatalen
;
1211 /* valname, valdata */
1217 char *rgdbdata
= info
->rgdbbuffer
;
1218 int nbytes
= info
->rgdbsize
;
1219 char *curdata
= rgdbdata
;
1220 char *end
= rgdbdata
+ nbytes
;
1222 char *next
= rgdbdata
;
1228 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1230 memcpy(&off_next_rgdb
,curdata
+4,4);
1231 next
= curdata
+ off_next_rgdb
;
1232 nrgdb
= (int) *((short *)curdata
+ 7);
1234 } while (nrgdb
!= nrMS
&& (next
< end
));
1236 /* curdata now points to the start of the right RGDB section */
1239 #define XREAD(whereto,len) \
1240 if ((curdata + len) <end) {\
1241 memcpy(whereto,curdata,len);\
1246 while (curdata
< next
) {
1247 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1249 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1250 if (xdkh
->nrLS
== nrLS
) {
1251 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1252 curdata
+= sizeof(dkh
);
1255 curdata
+= xdkh
->nextkeyoff
;
1258 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1260 if (nrgdb
!= dkh
.nrMS
)
1263 assert((dkh
.keynamelen
<2) || curdata
[0]);
1264 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1265 curdata
+= dkh
.keynamelen
;
1267 for (i
=0;i
< dkh
.values
; i
++) {
1273 XREAD(&dkv
,sizeof(dkv
));
1275 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1276 curdata
+= dkv
.valnamelen
;
1278 if ((1 << dkv
.type
) & UNICONVMASK
) {
1279 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1280 len
= 2*(dkv
.valdatalen
+ 1);
1282 /* I don't think we want to NULL terminate all data */
1283 data
= xmalloc(dkv
.valdatalen
);
1284 memcpy (data
, curdata
, dkv
.valdatalen
);
1285 len
= dkv
.valdatalen
;
1288 curdata
+= dkv
.valdatalen
;
1302 /******************************************************************************
1303 * _w95_walkrgkn [Internal]
1305 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1306 struct _w95_info
*info
)
1309 /* Disk Key Entry structure (RGKN part) */
1313 unsigned long x3
;/*usually 0xFFFFFFFF */
1314 unsigned long prevlvl
;
1315 unsigned long nextsub
;
1317 unsigned short nrLS
;
1318 unsigned short nrMS
;
1319 } *dke
= (struct dke
*)off
;
1323 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1326 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1327 /* XXX <-- This is a hack*/
1332 if (dke
->nextsub
!= -1 &&
1333 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1334 && (dke
->nextsub
> 0x20)) {
1336 _w95_walkrgkn(lpxkey
,
1337 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1341 if (dke
->next
!= -1 &&
1342 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1343 (dke
->next
> 0x20)) {
1344 _w95_walkrgkn(prevkey
,
1345 info
->rgknbuffer
+ dke
->next
- 0x20,
1353 /******************************************************************************
1354 * _w95_loadreg [Internal]
1356 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1360 unsigned long where
,version
,rgdbsection
,end
;
1361 struct _w95_info info
;
1363 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1365 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1366 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1367 if (hfd
==HFILE_ERROR32
)
1370 if (4!=_lread32(hfd
,magic
,4))
1372 if (strcmp(magic
,"CREG")) {
1373 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1376 if (4!=_lread32(hfd
,&version
,4))
1378 if (4!=_lread32(hfd
,&rgdbsection
,4))
1380 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1382 if (4!=_lread32(hfd
,magic
,4))
1384 if (strcmp(magic
,"RGKN")) {
1385 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1389 /* STEP 1: Keylink structures */
1390 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1395 info
.rgknsize
= end
- where
;
1396 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1397 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1400 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1403 end
= hfdinfo
.nFileSizeLow
;
1404 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1406 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1409 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1410 info
.rgdbsize
= end
- rgdbsection
;
1412 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1416 _w95_walkrgkn(lpkey
, NULL
, &info
);
1418 free (info
.rgdbbuffer
);
1419 free (info
.rgknbuffer
);
1423 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1426 reghack - windows 3.11 registry data format demo program.
1428 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1429 a combined hash table and tree description, and finally a text table.
1431 The header is obvious from the struct header. The taboff1 and taboff2
1432 fields are always 0x20, and their usage is unknown.
1434 The 8-byte entry table has various entry types.
1436 tabent[0] is a root index. The second word has the index of the root of
1438 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1439 the index of the key/value that has that hash. Data with the same
1440 hash value are on a circular list. The other three words in the
1441 hash entry are always zero.
1442 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1443 entry: dirent and keyent/valent. They are identified by context.
1444 tabent[freeidx] is the first free entry. The first word in a free entry
1445 is the index of the next free entry. The last has 0 as a link.
1446 The other three words in the free list are probably irrelevant.
1448 Entries in text table are preceeded by a word at offset-2. This word
1449 has the value (2*index)+1, where index is the referring keyent/valent
1450 entry in the table. I have no suggestion for the 2* and the +1.
1451 Following the word, there are N bytes of data, as per the keyent/valent
1452 entry length. The offset of the keyent/valent entry is from the start
1453 of the text table to the first data byte.
1455 This information is not available from Microsoft. The data format is
1456 deduced from the reg.dat file by me. Mistakes may
1457 have been made. I claim no rights and give no guarantees for this program.
1459 Tor Sjøwall, tor@sn.no
1462 /* reg.dat header format */
1463 struct _w31_header
{
1464 char cookie
[8]; /* 'SHCC3.10' */
1465 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1466 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1467 unsigned long tabcnt
; /* number of entries in index table */
1468 unsigned long textoff
; /* offset of text part */
1469 unsigned long textsize
; /* byte size of text part */
1470 unsigned short hashsize
; /* hash size */
1471 unsigned short freeidx
; /* free index */
1474 /* generic format of table entries */
1475 struct _w31_tabent
{
1476 unsigned short w0
, w1
, w2
, w3
;
1479 /* directory tabent: */
1480 struct _w31_dirent
{
1481 unsigned short sibling_idx
; /* table index of sibling dirent */
1482 unsigned short child_idx
; /* table index of child dirent */
1483 unsigned short key_idx
; /* table index of key keyent */
1484 unsigned short value_idx
; /* table index of value valent */
1488 struct _w31_keyent
{
1489 unsigned short hash_idx
; /* hash chain index for string */
1490 unsigned short refcnt
; /* reference count */
1491 unsigned short length
; /* length of string */
1492 unsigned short string_off
; /* offset of string in text table */
1496 struct _w31_valent
{
1497 unsigned short hash_idx
; /* hash chain index for string */
1498 unsigned short refcnt
; /* reference count */
1499 unsigned short length
; /* length of string */
1500 unsigned short string_off
; /* offset of string in text table */
1503 /* recursive helper function to display a directory tree */
1505 __w31_dumptree( unsigned short idx
,
1507 struct _w31_tabent
*tab
,
1508 struct _w31_header
*head
,
1510 time_t lastmodified
,
1513 struct _w31_dirent
*dir
;
1514 struct _w31_keyent
*key
;
1515 struct _w31_valent
*val
;
1516 LPKEYSTRUCT xlpkey
= NULL
;
1518 static char tail
[400];
1521 dir
=(struct _w31_dirent
*)&tab
[idx
];
1524 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1526 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1527 tail
[key
->length
]='\0';
1528 /* all toplevel entries AND the entries in the
1529 * toplevel subdirectory belong to \SOFTWARE\Classes
1531 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1532 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1533 idx
=dir
->sibling_idx
;
1536 name
=strdupA2W(tail
);
1538 xlpkey
=_find_or_add_key(lpkey
,name
);
1540 /* only add if leaf node or valued node */
1541 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1542 if (dir
->value_idx
) {
1543 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1544 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1545 tail
[val
->length
]='\0';
1546 value
=strdupA2W(tail
);
1547 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1551 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1553 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1554 idx
=dir
->sibling_idx
;
1559 /******************************************************************************
1560 * _w31_loadreg [Internal]
1562 void _w31_loadreg() {
1564 struct _w31_header head
;
1565 struct _w31_tabent
*tab
;
1569 BY_HANDLE_FILE_INFORMATION hfinfo
;
1570 time_t lastmodified
;
1573 TRACE(reg
,"(void)\n");
1575 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1576 if (hf
==HFILE_ERROR32
)
1579 /* read & dump header */
1580 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1581 ERR(reg
, "reg.dat is too short.\n");
1585 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1586 ERR(reg
, "reg.dat has bad signature.\n");
1591 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1592 /* read and dump index table */
1594 if (len
!=_lread32(hf
,tab
,len
)) {
1595 ERR(reg
,"couldn't read %d bytes.\n",len
);
1602 txt
= xmalloc(head
.textsize
);
1603 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1604 ERR(reg
,"couldn't seek to textblock.\n");
1610 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1611 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1618 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1619 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1625 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1626 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1627 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1635 /**********************************************************************************
1636 * SHELL_LoadRegistry [Internal]
1638 void SHELL_LoadRegistry( void )
1645 TRACE(reg
,"(void)\n");
1647 /* Load windows 3.1 entries */
1649 /* Load windows 95 entries */
1650 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1651 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1652 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1654 /* the global user default is loaded under HKEY_USERS\\.Default */
1655 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1656 lpkey
= lookup_hkey(hkey
);
1658 WARN(reg
,"Could not create global user default key\n");
1659 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1661 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1662 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1665 /* the global machine defaults */
1666 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1668 /* load the user saved registries */
1670 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1672 pwd
=getpwuid(getuid());
1673 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1674 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1675 strcpy(fn
,pwd
->pw_dir
);
1676 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1677 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1679 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1680 strcpy(fn
,pwd
->pw_dir
);
1681 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1682 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1685 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1686 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1687 DWORD junk
,type
,len
;
1691 if (( RegQueryValueEx32A(
1698 )!=ERROR_SUCCESS
) ||
1701 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1707 /********************* API FUNCTIONS ***************************************/
1711 * All functions are stubs to RegOpenKeyEx32W where all the
1715 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1716 * RegOpenKey32W -> RegOpenKeyEx32W
1720 /******************************************************************************
1721 * RegOpenKeyEx32W [ADVAPI32.150]
1722 * Opens the specified key
1724 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1727 * hkey [I] Handle of open key
1728 * lpszSubKey [I] Name of subkey to open
1729 * dwReserved [I] Reserved - must be zero
1730 * samDesired [I] Security access mask
1731 * retkey [O] Address of handle of open key
1734 * Success: ERROR_SUCCESS
1735 * Failure: Error code
1737 DWORD WINAPI
RegOpenKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1738 REGSAM samDesired
, LPHKEY retkey
)
1740 LPKEYSTRUCT lpNextKey
,lpxkey
;
1744 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1747 lpNextKey
= lookup_hkey( hkey
);
1749 return ERROR_INVALID_HANDLE
;
1751 if (!lpszSubKey
|| !*lpszSubKey
) {
1752 /* Either NULL or pointer to empty string, so return a new handle
1753 to the original hkey */
1755 add_handle(currenthandle
,lpNextKey
,samDesired
);
1756 *retkey
=currenthandle
;
1757 return ERROR_SUCCESS
;
1760 if (lpszSubKey
[0] == '\\') {
1761 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1762 return ERROR_BAD_PATHNAME
;
1765 split_keypath(lpszSubKey
,&wps
,&wpc
);
1767 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1771 lpxkey
=lpNextKey
->nextsub
;
1773 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
)) {
1776 lpxkey
=lpxkey
->next
;
1780 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1782 return ERROR_FILE_NOT_FOUND
;
1789 add_handle(currenthandle
,lpxkey
,samDesired
);
1790 *retkey
= currenthandle
;
1791 TRACE(reg
," Returning %x\n", currenthandle
);
1793 return ERROR_SUCCESS
;
1797 /******************************************************************************
1798 * RegOpenKeyEx32A [ADVAPI32.149]
1800 DWORD WINAPI
RegOpenKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1801 REGSAM samDesired
, LPHKEY retkey
)
1803 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1806 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1808 ret
= RegOpenKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
1814 /******************************************************************************
1815 * RegOpenKey32W [ADVAPI32.151]
1818 * hkey [I] Handle of open key
1819 * lpszSubKey [I] Address of name of subkey to open
1820 * retkey [O] Address of handle of open key
1823 * Success: ERROR_SUCCESS
1824 * Failure: Error code
1826 DWORD WINAPI
RegOpenKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1828 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1829 return RegOpenKeyEx32W( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
1833 /******************************************************************************
1834 * RegOpenKey32A [ADVAPI32.148]
1836 DWORD WINAPI
RegOpenKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1839 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1840 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1841 ret
= RegOpenKey32W( hkey
, lpszSubKeyW
, retkey
);
1847 /******************************************************************************
1848 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1850 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1852 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1853 return RegOpenKey32A( hkey
, lpszSubKey
, retkey
);
1860 * All those functions convert their respective
1861 * arguments and call RegCreateKeyExW at the end.
1863 * We stay away from the Ex functions as long as possible because there are
1864 * differences in the return values
1867 * RegCreateKeyEx32A \
1868 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1872 /******************************************************************************
1873 * RegCreateKeyEx32W [ADVAPI32.131]
1876 * hkey [I] Handle of an open key
1877 * lpszSubKey [I] Address of subkey name
1878 * dwReserved [I] Reserved - must be 0
1879 * lpszClass [I] Address of class string
1880 * fdwOptions [I] Special options flag
1881 * samDesired [I] Desired security access
1882 * lpSecAttribs [I] Address of key security structure
1883 * retkey [O] Address of buffer for opened handle
1884 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1886 DWORD WINAPI
RegCreateKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
,
1887 DWORD dwReserved
, LPWSTR lpszClass
,
1888 DWORD fdwOptions
, REGSAM samDesired
,
1889 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1890 LPHKEY retkey
, LPDWORD lpDispos
)
1892 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1896 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
1897 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
1898 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
1900 lpNextKey
= lookup_hkey(hkey
);
1902 return ERROR_INVALID_HANDLE
;
1904 /* Check for valid options */
1905 switch(fdwOptions
) {
1906 case REG_OPTION_NON_VOLATILE
:
1907 case REG_OPTION_VOLATILE
:
1908 case REG_OPTION_BACKUP_RESTORE
:
1911 return ERROR_INVALID_PARAMETER
;
1914 /* Sam has to be a combination of the following */
1916 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
1917 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
1918 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
1919 return ERROR_INVALID_PARAMETER
;
1921 if (!lpszSubKey
|| !*lpszSubKey
) {
1923 add_handle(currenthandle
,lpNextKey
,samDesired
);
1924 *retkey
=currenthandle
;
1925 TRACE(reg
, "Returning %x\n", currenthandle
);
1926 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1927 return ERROR_SUCCESS
;
1930 if (lpszSubKey
[0] == '\\') {
1931 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1932 return ERROR_BAD_PATHNAME
;
1935 split_keypath(lpszSubKey
,&wps
,&wpc
);
1937 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1940 lpxkey
=lpNextKey
->nextsub
;
1942 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1944 lpxkey
=lpxkey
->next
;
1953 add_handle(currenthandle
,lpxkey
,samDesired
);
1954 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1955 *retkey
= currenthandle
;
1956 TRACE(reg
, "Returning %x\n", currenthandle
);
1958 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1960 return ERROR_SUCCESS
;
1963 /* Good. Now the hard part */
1965 lplpPrevKey
= &(lpNextKey
->nextsub
);
1966 lpxkey
= *lplpPrevKey
;
1968 lplpPrevKey
= &(lpxkey
->next
);
1969 lpxkey
= *lplpPrevKey
;
1971 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1972 if (!*lplpPrevKey
) {
1974 TRACE(reg
, "Returning OUTOFMEMORY\n");
1975 return ERROR_OUTOFMEMORY
;
1977 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1978 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
1979 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1980 (*lplpPrevKey
)->next
= NULL
;
1981 (*lplpPrevKey
)->nextsub
= NULL
;
1982 (*lplpPrevKey
)->values
= NULL
;
1983 (*lplpPrevKey
)->nrofvalues
= 0;
1984 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1986 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1988 (*lplpPrevKey
)->class = NULL
;
1989 lpNextKey
= *lplpPrevKey
;
1993 add_handle(currenthandle
,lpNextKey
,samDesired
);
1995 /*FIXME: flag handling correct? */
1996 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1998 lpNextKey
->class = strdupW(lpszClass
);
2000 lpNextKey
->class = NULL
;
2001 *retkey
= currenthandle
;
2002 TRACE(reg
, "Returning %x\n", currenthandle
);
2004 *lpDispos
= REG_CREATED_NEW_KEY
;
2006 return ERROR_SUCCESS
;
2010 /******************************************************************************
2011 * RegCreateKeyEx32A [ADVAPI32.130]
2013 DWORD WINAPI
RegCreateKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2014 LPSTR lpszClass
, DWORD fdwOptions
,
2016 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2017 LPHKEY retkey
, LPDWORD lpDispos
)
2019 LPWSTR lpszSubKeyW
, lpszClassW
;
2022 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2023 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2026 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2027 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2029 ret
= RegCreateKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2030 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2033 if(lpszSubKeyW
) free(lpszSubKeyW
);
2034 if(lpszClassW
) free(lpszClassW
);
2040 /******************************************************************************
2041 * RegCreateKey32W [ADVAPI32.132]
2043 DWORD WINAPI
RegCreateKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2046 LPKEYSTRUCT lpNextKey
;
2048 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2050 /* This check is here because the return value is different than the
2051 one from the Ex functions */
2052 lpNextKey
= lookup_hkey(hkey
);
2054 return ERROR_BADKEY
;
2056 return RegCreateKeyEx32W( hkey
, lpszSubKey
, 0, NULL
,
2057 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2062 /******************************************************************************
2063 * RegCreateKey32A [ADVAPI32.129]
2065 DWORD WINAPI
RegCreateKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2070 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2071 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2072 ret
= RegCreateKey32W( hkey
, lpszSubKeyW
, retkey
);
2073 if(lpszSubKeyW
) free(lpszSubKeyW
);
2078 /******************************************************************************
2079 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2081 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2083 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2084 return RegCreateKey32A( hkey
, lpszSubKey
, retkey
);
2089 * Query Value Functions
2090 * Win32 differs between keynames and valuenames.
2091 * multiple values may belong to one key, the special value
2092 * with name NULL is the default value used by the win31
2096 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2097 * RegQueryValue32W -> RegQueryValueEx32W
2101 /******************************************************************************
2102 * RegQueryValueEx32W [ADVAPI32.158]
2103 * Retrieves type and data for a specified name associated with an open key
2106 * hkey [I] Handle of key to query
2107 * lpValueName [I] Name of value to query
2108 * lpdwReserved [I] Reserved - must be NULL
2109 * lpdwType [O] Address of buffer for value type. If NULL, the type
2111 * lpbData [O] Address of data buffer. If NULL, the actual data is
2113 * lpcbData [I/O] Address of data buffer size
2116 * ERROR_SUCCESS: Success
2117 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2119 DWORD WINAPI
RegQueryValueEx32W( HKEY hkey
, LPWSTR lpValueName
,
2120 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2121 LPBYTE lpbData
, LPDWORD lpcbData
)
2126 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%ld)\n", hkey
, debugstr_w(lpValueName
),
2127 lpdwReserved
, lpdwType
, lpbData
, lpcbData
?*lpcbData
:0);
2129 lpkey
= lookup_hkey(hkey
);
2131 return ERROR_INVALID_HANDLE
;
2133 /* Reserved must be NULL (at least for now) */
2135 return ERROR_INVALID_PARAMETER
;
2137 /* An empty name string is equivalent to NULL */
2138 if (lpValueName
&& !*lpValueName
)
2141 if (lpValueName
==NULL
) {
2142 /* Use key's unnamed or default value, if any */
2143 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2144 if (lpkey
->values
[i
].name
==NULL
)
2147 /* Search for the key name */
2148 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2149 if ( lpkey
->values
[i
].name
&&
2150 !lstrcmpi32W(lpValueName
,lpkey
->values
[i
].name
)
2155 if (i
==lpkey
->nrofvalues
) {
2156 TRACE(reg
,"Key not found\n");
2157 if (lpValueName
==NULL
) {
2158 /* Empty keyname not found */
2160 *(WCHAR
*)lpbData
= 0;
2165 TRACE(reg
, "Returning an empty string\n");
2166 return ERROR_SUCCESS
;
2168 return ERROR_BAD_PATHNAME
;
2172 *lpdwType
= lpkey
->values
[i
].type
;
2174 if (lpbData
==NULL
) {
2175 /* Data is not required */
2176 if (lpcbData
==NULL
) {
2177 /* And data size is not required */
2178 /* So all that is returned is the type (set above) */
2179 return ERROR_SUCCESS
;
2181 /* Set the size required and return success */
2182 *lpcbData
= lpkey
->values
[i
].len
;
2183 return ERROR_SUCCESS
;
2186 if (*lpcbData
<lpkey
->values
[i
].len
) {
2187 /* The size was specified, but the data is too big for it */
2188 /* Instead of setting it to NULL, fill in with as much as possible */
2189 /* But the docs do not specify how to handle the lpbData here */
2190 /* *(WCHAR*)lpbData= 0; */
2191 memcpy(lpbData
,lpkey
->values
[i
].data
,*lpcbData
);
2192 *lpcbData
= lpkey
->values
[i
].len
;
2193 return ERROR_MORE_DATA
;
2196 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2198 /* Extra debugging output */
2202 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
2205 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)*lpbData
);
2208 TRACE(reg
," Data(binary)\n");
2209 /* Is there a way of printing this in readable form? */
2212 TRACE(reg
, "Unknown data type %ld\n", *lpdwType
);
2216 /* Set the actual size */
2217 *lpcbData
= lpkey
->values
[i
].len
;
2218 return ERROR_SUCCESS
;
2222 /******************************************************************************
2223 * RegQueryValue32W [ADVAPI32.159]
2225 DWORD WINAPI
RegQueryValue32W( HKEY hkey
, LPWSTR lpszSubKey
, LPWSTR lpszData
,
2231 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2232 lpcbData
?*lpcbData
:0);
2234 /* Only open subkey, if we really do descend */
2235 if (lpszSubKey
&& *lpszSubKey
) {
2236 ret
= RegOpenKey32W( hkey
, lpszSubKey
, &xhkey
);
2237 if (ret
!= ERROR_SUCCESS
) {
2238 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2245 ret
= RegQueryValueEx32W( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2253 /******************************************************************************
2254 * RegQueryValueEx32A [ADVAPI32.157]
2256 DWORD WINAPI
RegQueryValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2257 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2258 LPBYTE lpbData
, LPDWORD lpcbData
)
2260 LPWSTR lpszValueNameW
;
2266 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
,debugstr_a(lpszValueName
),
2267 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2269 lpszValueNameW
= lpszValueName
?strdupA2W(lpszValueName
):NULL
;
2271 /* Why would this be set? It is just an output */
2279 /* Only get the size for now */
2280 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
,
2281 &type
, buf
, mylen
);
2283 if (ret
==ERROR_MORE_DATA
) {
2284 buf
= (LPBYTE
)xmalloc(*mylen
);
2286 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2287 myxlen
= 2*(*lpcbData
);
2290 /* Data is not required */
2293 myxlen
= *lpcbData
*2;
2299 /* Now get the data */
2300 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
, &type
,
2305 if (ret
==ERROR_SUCCESS
) {
2307 if (UNICONVMASK
& (1<<(type
))) {
2308 /* convert UNICODE to ASCII */
2309 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2310 *lpcbData
= myxlen
/2;
2312 if (myxlen
>*lpcbData
)
2313 ret
= ERROR_MORE_DATA
;
2315 memcpy(lpbData
,buf
,myxlen
);
2320 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2321 *lpcbData
= myxlen
/2;
2324 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2325 *lpcbData
= myxlen
/2;
2329 if(lpszValueNameW
) free(lpszValueNameW
);
2334 /******************************************************************************
2335 * RegQueryValueEx16 [KERNEL.225]
2337 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2338 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2339 LPBYTE lpbData
, LPDWORD lpcbData
)
2341 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2342 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2343 return RegQueryValueEx32A( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2344 lpbData
, lpcbData
);
2348 /******************************************************************************
2349 * RegQueryValue32A [ADVAPI32.156]
2351 DWORD WINAPI
RegQueryValue32A( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2357 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2358 lpcbData
?*lpcbData
:0);
2360 if (lpszSubKey
&& *lpszSubKey
) {
2361 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2362 if( ret
!= ERROR_SUCCESS
)
2368 ret
= RegQueryValueEx32A( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2371 RegCloseKey( xhkey
);
2376 /******************************************************************************
2377 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2380 * Is this HACK still applicable?
2383 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2384 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2387 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2390 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2391 lpcbData
?*lpcbData
:0);
2394 *lpcbData
&= 0xFFFF;
2395 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2400 * Setting values of Registry keys
2403 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2404 * RegSetValue32W -> RegSetValueEx32W
2408 /******************************************************************************
2409 * RegSetValueEx32W [ADVAPI32.170]
2410 * Sets the data and type of a value under a register key
2413 * hkey [I] Handle of key to set value for
2414 * lpszValueName [I] Name of value to set
2415 * dwReserved [I] Reserved - must be zero
2416 * dwType [I] Flag for value type
2417 * lpbData [I] Address of value data
2418 * cbData [I] Size of value data
2421 * Success: ERROR_SUCCESS
2422 * Failure: Error code
2424 DWORD WINAPI
RegSetValueEx32W( HKEY hkey
, LPWSTR lpszValueName
,
2425 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2431 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2432 dwReserved
, dwType
, lpbData
, cbData
);
2436 TRACE(reg
," Data(sz)=%s\n", debugstr_w((LPCWSTR
)lpbData
));
2439 TRACE(reg
," Data(binary)\n");
2442 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)lpbData
);
2445 TRACE(reg
,"Unknown type: %ld\n", dwType
);
2448 lpkey
= lookup_hkey( hkey
);
2450 return ERROR_INVALID_HANDLE
;
2452 lpkey
->flags
|= REG_OPTION_TAINTED
;
2454 if (lpszValueName
==NULL
) {
2455 /* Sets type and name for key's unnamed or default value */
2456 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2457 if (lpkey
->values
[i
].name
==NULL
)
2460 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2461 if ( lpkey
->values
[i
].name
&&
2462 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2466 if (i
==lpkey
->nrofvalues
) {
2467 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2469 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2471 lpkey
->nrofvalues
++;
2472 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2474 if (lpkey
->values
[i
].name
==NULL
) {
2476 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2478 lpkey
->values
[i
].name
= NULL
;
2480 lpkey
->values
[i
].len
= cbData
;
2481 lpkey
->values
[i
].type
= dwType
;
2482 if (lpkey
->values
[i
].data
!=NULL
)
2483 free(lpkey
->values
[i
].data
);
2484 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2485 lpkey
->values
[i
].lastmodified
= time(NULL
);
2486 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2487 return ERROR_SUCCESS
;
2491 /******************************************************************************
2492 * RegSetValueEx32A [ADVAPI32.169]
2495 DWORD WINAPI
RegSetValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2496 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2500 LPWSTR lpszValueNameW
;
2503 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2504 dwReserved
,dwType
,lpbData
,cbData
);
2506 if ((1<<dwType
) & UNICONVMASK
) {
2507 buf
=(LPBYTE
)strdupA2W(lpbData
);
2508 cbData
=2*strlen(lpbData
)+2;
2512 lpszValueNameW
= strdupA2W(lpszValueName
);
2514 lpszValueNameW
= NULL
;
2515 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2517 free(lpszValueNameW
);
2524 /******************************************************************************
2525 * RegSetValueEx16 [KERNEL.226]
2527 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2528 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2530 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2531 dwReserved
,dwType
,lpbData
,cbData
);
2532 return RegSetValueEx32A( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2537 /******************************************************************************
2538 * RegSetValue32W [ADVAPI32.171]
2540 DWORD WINAPI
RegSetValue32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2541 LPCWSTR lpszData
, DWORD cbData
)
2546 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2547 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2549 if (lpszSubKey
&& *lpszSubKey
) {
2550 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2551 if (ret
!=ERROR_SUCCESS
)
2555 if (dwType
!=REG_SZ
) {
2556 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2559 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2560 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2561 cbData
,debugstr_w(lpszData
),2*lstrlen32W(lpszData
)+2
2563 cbData
=2*lstrlen32W(lpszData
)+2;
2565 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2572 /******************************************************************************
2573 * RegSetValue32A [ADVAPI32.168]
2576 DWORD WINAPI
RegSetValue32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2577 LPCSTR lpszData
, DWORD cbData
)
2582 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2583 if (lpszSubKey
&& *lpszSubKey
) {
2584 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2585 if (ret
!=ERROR_SUCCESS
)
2590 if (dwType
!=REG_SZ
) {
2591 TRACE(reg
,"dwType=%ld!\n",dwType
);
2594 if (cbData
!=strlen(lpszData
)+1)
2595 cbData
=strlen(lpszData
)+1;
2596 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2603 /******************************************************************************
2604 * RegSetValue16 [KERNEL.221] [SHELL.5]
2606 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2607 LPCSTR lpszData
, DWORD cbData
)
2609 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2610 debugstr_a(lpszData
),cbData
);
2611 return RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2619 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2620 * RegEnumKey32W -> RegEnumKeyEx32W
2624 /******************************************************************************
2625 * RegEnumKeyEx32W [ADVAPI32.139]
2628 * hkey [I] Handle to key to enumerate
2629 * iSubKey [I] Index of subkey to enumerate
2630 * lpszName [O] Buffer for subkey name
2631 * lpcchName [O] Size of subkey buffer
2632 * lpdwReserved [I] Reserved
2633 * lpszClass [O] Buffer for class string
2634 * lpcchClass [O] Size of class buffer
2635 * ft [O] Time key last written to
2637 DWORD WINAPI
RegEnumKeyEx32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2638 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2639 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2642 LPKEYSTRUCT lpkey
,lpxkey
;
2644 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2645 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2647 lpkey
= lookup_hkey( hkey
);
2649 return ERROR_INVALID_HANDLE
;
2651 if (!lpkey
->nextsub
)
2652 return ERROR_NO_MORE_ITEMS
;
2653 lpxkey
=lpkey
->nextsub
;
2655 /* Traverse the subkeys */
2656 while (iSubkey
&& lpxkey
) {
2658 lpxkey
=lpxkey
->next
;
2661 if (iSubkey
|| !lpxkey
)
2662 return ERROR_NO_MORE_ITEMS
;
2663 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2664 return ERROR_MORE_DATA
;
2665 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2668 *lpcchName
= lstrlen32W(lpszName
);
2671 /* FIXME: what should we write into it? */
2675 return ERROR_SUCCESS
;
2679 /******************************************************************************
2680 * RegEnumKey32W [ADVAPI32.140]
2682 DWORD WINAPI
RegEnumKey32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2687 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2688 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2692 /******************************************************************************
2693 * RegEnumKeyEx32A [ADVAPI32.138]
2695 DWORD WINAPI
RegEnumKeyEx32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2696 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2697 LPSTR lpszClass
, LPDWORD lpcchClass
,
2700 DWORD ret
,lpcchNameW
,lpcchClassW
;
2701 LPWSTR lpszNameW
,lpszClassW
;
2704 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2705 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2708 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2709 lpcchNameW
= *lpcchName
*2;
2715 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2716 lpcchClassW
= *lpcchClass
*2;
2721 ret
=RegEnumKeyEx32W(
2731 if (ret
==ERROR_SUCCESS
) {
2732 lstrcpyWtoA(lpszName
,lpszNameW
);
2733 *lpcchName
=strlen(lpszName
);
2735 lstrcpyWtoA(lpszClass
,lpszClassW
);
2736 *lpcchClass
=strlen(lpszClass
);
2747 /******************************************************************************
2748 * RegEnumKey32A [ADVAPI32.137]
2750 DWORD WINAPI
RegEnumKey32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2755 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2756 return RegEnumKeyEx32A( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2761 /******************************************************************************
2762 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2764 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2767 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2768 return RegEnumKey32A( hkey
, iSubkey
, lpszName
, lpcchName
);
2773 * Enumerate Registry Values
2776 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2780 /******************************************************************************
2781 * RegEnumValue32W [ADVAPI32.142]
2784 * hkey [I] Handle to key to query
2785 * iValue [I] Index of value to query
2786 * lpszValue [O] Value string
2787 * lpcchValue [O] Size of value buffer
2788 * lpdReserved [I] Reserved
2789 * lpdwType [O] Type code
2790 * lpbData [O] Value data
2791 * lpcbData [O] Size of data buffer
2793 DWORD WINAPI
RegEnumValue32W( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
2794 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2795 LPDWORD lpdwType
, LPBYTE lpbData
,
2801 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
2802 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2804 lpkey
= lookup_hkey( hkey
);
2806 return ERROR_INVALID_HANDLE
;
2808 if (lpkey
->nrofvalues
<= iValue
)
2809 return ERROR_NO_MORE_ITEMS
;
2811 /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2812 val
= lpkey
->values
+ iValue
;
2815 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2816 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2817 return ERROR_MORE_DATA
;
2819 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2820 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2826 /* Can be NULL if the type code is not required */
2828 *lpdwType
= val
->type
;
2831 if (val
->len
>*lpcbData
)
2832 return ERROR_MORE_DATA
;
2833 memcpy(lpbData
,val
->data
,val
->len
);
2834 *lpcbData
= val
->len
;
2836 return ERROR_SUCCESS
;
2840 /******************************************************************************
2841 * RegEnumValue32A [ADVAPI32.141]
2843 DWORD WINAPI
RegEnumValue32A( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2844 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2845 LPDWORD lpdwType
, LPBYTE lpbData
,
2850 DWORD ret
,lpcbDataW
;
2853 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2854 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2856 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2858 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2859 lpcbDataW
= *lpcbData
*2;
2863 ret
= RegEnumValue32W( hkey
, iValue
, lpszValueW
, lpcchValue
,
2864 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
2869 if (ret
==ERROR_SUCCESS
) {
2870 lstrcpyWtoA(lpszValue
,lpszValueW
);
2872 if ((1<<dwType
) & UNICONVMASK
) {
2873 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2875 if (lpcbDataW
> *lpcbData
)
2876 ret
= ERROR_MORE_DATA
;
2878 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2880 *lpcbData
= lpcbDataW
;
2883 if (lpbDataW
) free(lpbDataW
);
2884 if (lpszValueW
) free(lpszValueW
);
2889 /******************************************************************************
2890 * RegEnumValue16 [KERNEL.223]
2892 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2893 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2894 LPDWORD lpdwType
, LPBYTE lpbData
,
2897 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2898 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2899 return RegEnumValue32A( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
2900 lpdwType
, lpbData
, lpcbData
);
2904 /******************************************************************************
2905 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2906 * Releases the handle of the specified key
2909 * hkey [I] Handle of key to close
2912 * Success: ERROR_SUCCESS
2913 * Failure: Error code
2915 DWORD WINAPI
RegCloseKey( HKEY hkey
)
2917 TRACE(reg
,"(%x)\n",hkey
);
2919 /* The standard handles are allowed to succeed, even though they are not
2921 if (is_standard_hkey(hkey
))
2922 return ERROR_SUCCESS
;
2924 return remove_handle(hkey
);
2929 * Delete registry key
2932 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2936 /******************************************************************************
2937 * RegDeleteKey32W [ADVAPI32.134]
2940 * hkey [I] Handle to open key
2941 * lpszSubKey [I] Name of subkey to delete
2944 * Success: ERROR_SUCCESS
2945 * Failure: Error code
2947 DWORD WINAPI
RegDeleteKey32W( HKEY hkey
, LPWSTR lpszSubKey
)
2949 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2953 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
2955 lpNextKey
= lookup_hkey(hkey
);
2957 return ERROR_INVALID_HANDLE
;
2959 /* Subkey param cannot be NULL */
2960 if (!lpszSubKey
|| !*lpszSubKey
)
2961 return ERROR_BADKEY
;
2963 /* We need to know the previous key in the hier. */
2964 split_keypath(lpszSubKey
,&wps
,&wpc
);
2968 lpxkey
=lpNextKey
->nextsub
;
2970 TRACE(reg
, " Scanning [%s]\n",
2971 debugstr_w(lpxkey
->keyname
));
2972 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2974 lpxkey
=lpxkey
->next
;
2978 TRACE(reg
, " Not found.\n");
2979 /* not found is success */
2980 return ERROR_SUCCESS
;
2985 lpxkey
= lpNextKey
->nextsub
;
2986 lplpPrevKey
= &(lpNextKey
->nextsub
);
2988 TRACE(reg
, " Scanning [%s]\n",
2989 debugstr_w(lpxkey
->keyname
));
2990 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2992 lplpPrevKey
= &(lpxkey
->next
);
2993 lpxkey
= lpxkey
->next
;
2998 WARN(reg
, " Not found.\n");
2999 return ERROR_FILE_NOT_FOUND
;
3002 if (lpxkey
->nextsub
) {
3004 WARN(reg
, " Not empty.\n");
3005 return ERROR_CANTWRITE
;
3007 *lplpPrevKey
= lpxkey
->next
;
3008 free(lpxkey
->keyname
);
3010 free(lpxkey
->class);
3012 free(lpxkey
->values
);
3015 TRACE(reg
, " Done.\n");
3016 return ERROR_SUCCESS
;
3020 /******************************************************************************
3021 * RegDeleteKey32A [ADVAPI32.133]
3023 DWORD WINAPI
RegDeleteKey32A( HKEY hkey
, LPCSTR lpszSubKey
)
3028 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3029 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3030 ret
= RegDeleteKey32W( hkey
, lpszSubKeyW
);
3031 if(lpszSubKeyW
) free(lpszSubKeyW
);
3036 /******************************************************************************
3037 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3039 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3041 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3042 return RegDeleteKey32A( hkey
, lpszSubKey
);
3047 * Delete registry value
3050 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3054 /******************************************************************************
3055 * RegDeleteValue32W [ADVAPI32.136]
3063 DWORD WINAPI
RegDeleteValue32W( HKEY hkey
, LPWSTR lpszValue
)
3069 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3071 lpkey
= lookup_hkey( hkey
);
3073 return ERROR_INVALID_HANDLE
;
3076 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3077 if ( lpkey
->values
[i
].name
&&
3078 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
3082 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3083 if (lpkey
->values
[i
].name
==NULL
)
3087 if (i
== lpkey
->nrofvalues
)
3088 return ERROR_FILE_NOT_FOUND
;
3090 val
= lpkey
->values
+i
;
3091 if (val
->name
) free(val
->name
);
3092 if (val
->data
) free(val
->data
);
3096 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3098 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3100 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3102 lpkey
->nrofvalues
--;
3103 return ERROR_SUCCESS
;
3107 /******************************************************************************
3108 * RegDeleteValue32A [ADVAPI32.135]
3110 DWORD WINAPI
RegDeleteValue32A( HKEY hkey
, LPSTR lpszValue
)
3115 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3116 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3117 ret
= RegDeleteValue32W( hkey
, lpszValueW
);
3118 if(lpszValueW
) free(lpszValueW
);
3123 /******************************************************************************
3124 * RegDeleteValue16 [KERNEL.222]
3126 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3128 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3129 return RegDeleteValue32A( hkey
, lpszValue
);
3133 /******************************************************************************
3134 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3135 * Writes key to registry
3138 * hkey [I] Handle of key to write
3141 * Success: ERROR_SUCCESS
3142 * Failure: Error code
3144 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3149 TRACE(reg
, "(%x)\n", hkey
);
3151 lpkey
= lookup_hkey( hkey
);
3153 return ERROR_INVALID_HANDLE
;
3155 ERR(reg
, "What is the correct filename?\n");
3157 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3160 return ERROR_SUCCESS
;
3162 return ERROR_UNKNOWN
; /* FIXME */
3166 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3169 /******************************************************************************
3170 * RegQueryInfoKey32W [ADVAPI32.153]
3173 * hkey [I] Handle to key to query
3174 * lpszClass [O] Buffer for class string
3175 * lpcchClass [O] Size of class string buffer
3176 * lpdwReserved [I] Reserved
3177 * lpcSubKeys [I] Buffer for number of subkeys
3178 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3179 * lpcchMaxClass [O] Buffer for longest class string length
3180 * lpcValues [O] Buffer for number of value entries
3181 * lpcchMaxValueName [O] Buffer for longest value name length
3182 * lpccbMaxValueData [O] Buffer for longest value data length
3183 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3186 DWORD WINAPI
RegQueryInfoKey32W( HKEY hkey
, LPWSTR lpszClass
,
3187 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3188 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3189 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3190 LPDWORD lpcchMaxValueName
,
3191 LPDWORD lpccbMaxValueData
,
3192 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3194 LPKEYSTRUCT lpkey
,lpxkey
;
3195 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3198 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3199 lpkey
= lookup_hkey(hkey
);
3201 return ERROR_INVALID_HANDLE
;
3204 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
3205 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3206 return ERROR_MORE_DATA
;
3208 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3209 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
3216 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
3218 lpxkey
=lpkey
->nextsub
;
3219 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3222 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
3223 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
3224 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
3225 maxclass
=lstrlen32W(lpxkey
->class);
3226 lpxkey
=lpxkey
->next
;
3228 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3229 LPKEYVALUE val
=lpkey
->values
+i
;
3231 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
3232 maxvname
=lstrlen32W(val
->name
);
3233 if (val
->len
>maxvdata
)
3236 if (!maxclass
) maxclass
= 1;
3237 if (!maxvname
) maxvname
= 1;
3239 *lpcValues
= lpkey
->nrofvalues
;
3241 *lpcSubKeys
= nrofkeys
;
3243 *lpcchMaxSubkey
= maxsubkey
*2;
3245 *lpcchMaxClass
= maxclass
*2;
3246 if (lpcchMaxValueName
)
3247 *lpcchMaxValueName
= maxvname
;
3248 if (lpccbMaxValueData
)
3249 *lpccbMaxValueData
= maxvdata
;
3250 return ERROR_SUCCESS
;
3254 /******************************************************************************
3255 * RegQueryInfoKey32A [ADVAPI32.152]
3257 DWORD WINAPI
RegQueryInfoKey32A( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3258 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3259 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3260 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3261 LPDWORD lpccbMaxValueData
,
3262 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3267 TRACE(reg
,"(%x,......)\n",hkey
);
3270 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
3274 ret
=RegQueryInfoKey32W(
3285 lpcbSecurityDescriptor
,
3288 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3289 lstrcpyWtoA(lpszClass
,lpszClassW
);
3296 if (lpcchMaxValueName
)
3297 *lpcchMaxValueName
/=2;
3304 /******************************************************************************
3305 * RegConnectRegistry32W [ADVAPI32.128]
3308 * lpMachineName [I] Address of name of remote computer
3309 * hHey [I] Predefined registry handle
3310 * phkResult [I] Address of buffer for remote registry handle
3312 LONG WINAPI
RegConnectRegistry32W( LPCWSTR lpMachineName
, HKEY hKey
,
3315 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3317 if (!lpMachineName
|| !*lpMachineName
) {
3318 /* Use the local machine name */
3319 return RegOpenKey16( hKey
, "", phkResult
);
3322 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3323 return ERROR_BAD_NETPATH
;
3327 /******************************************************************************
3328 * RegConnectRegistry32A [ADVAPI32.127]
3330 LONG WINAPI
RegConnectRegistry32A( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3333 LPWSTR machineW
= strdupA2W(machine
);
3334 ret
= RegConnectRegistry32W( machineW
, hkey
, reskey
);
3340 /******************************************************************************
3341 * RegGetKeySecurity [ADVAPI32.144]
3342 * Retrieves a copy of security descriptor protecting the registry key
3345 * hkey [I] Open handle of key to set
3346 * SecurityInformation [I] Descriptor contents
3347 * pSecurityDescriptor [O] Address of descriptor for key
3348 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3351 * Success: ERROR_SUCCESS
3352 * Failure: Error code
3354 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3355 SECURITY_INFORMATION SecurityInformation
,
3356 LPSECURITY_DESCRIPTOR pSecurityDescriptor
,
3357 LPDWORD lpcbSecurityDescriptor
)
3361 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3362 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3364 lpkey
= lookup_hkey( hkey
);
3366 return ERROR_INVALID_HANDLE
;
3368 /* FIXME: Check for valid SecurityInformation values */
3370 if (*lpcbSecurityDescriptor
< sizeof(*pSecurityDescriptor
))
3371 return ERROR_INSUFFICIENT_BUFFER
;
3373 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3374 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3376 return ERROR_SUCCESS
;
3380 /******************************************************************************
3381 * RegLoadKey32W [ADVAPI32.???]
3384 * hkey [I] Handle of open key
3385 * lpszSubKey [I] Address of name of subkey
3386 * lpszFile [I] Address of filename for registry information
3388 LONG WINAPI
RegLoadKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3391 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3393 /* Do this check before the hkey check */
3394 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3395 return ERROR_INVALID_PARAMETER
;
3397 lpkey
= lookup_hkey( hkey
);
3399 return ERROR_INVALID_HANDLE
;
3401 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3402 debugstr_w(lpszFile
));
3404 return ERROR_SUCCESS
;
3408 /******************************************************************************
3409 * RegLoadKey32A [ADVAPI32.???]
3411 LONG WINAPI
RegLoadKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3414 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3415 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3416 ret
= RegLoadKey32W( hkey
, lpszSubKeyW
, lpszFileW
);
3417 if(lpszFileW
) free(lpszFileW
);
3418 if(lpszSubKeyW
) free(lpszSubKeyW
);
3423 /******************************************************************************
3424 * RegNotifyChangeKeyValue [ADVAPI32.???]
3427 * hkey [I] Handle of key to watch
3428 * fWatchSubTree [I] Flag for subkey notification
3429 * fdwNotifyFilter [I] Changes to be reported
3430 * hEvent [I] Handle of signaled event
3431 * fAsync [I] Flag for asynchronous reporting
3433 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL32 fWatchSubTree
,
3434 DWORD fdwNotifyFilter
, HANDLE32 hEvent
,
3438 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3441 lpkey
= lookup_hkey( hkey
);
3443 return ERROR_INVALID_HANDLE
;
3445 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3448 return ERROR_SUCCESS
;
3452 /******************************************************************************
3453 * RegUnLoadKey32W [ADVAPI32.173]
3456 * hkey [I] Handle of open key
3457 * lpSubKey [I] Address of name of subkey to unload
3459 LONG WINAPI
RegUnLoadKey32W( HKEY hkey
, LPCWSTR lpSubKey
)
3461 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3462 return ERROR_SUCCESS
;
3466 /******************************************************************************
3467 * RegUnLoadKey32A [ADVAPI32.172]
3469 LONG WINAPI
RegUnLoadKey32A( HKEY hkey
, LPCSTR lpSubKey
)
3472 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3473 ret
= RegUnLoadKey32W( hkey
, lpSubKeyW
);
3474 if(lpSubKeyW
) free(lpSubKeyW
);
3479 /******************************************************************************
3480 * RegSetKeySecurity [ADVAPI32.167]
3483 * hkey [I] Open handle of key to set
3484 * SecurityInfo [I] Descriptor contents
3485 * pSecurityDesc [I] Address of descriptor for key
3487 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3488 LPSECURITY_DESCRIPTOR pSecurityDesc
)
3492 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3494 /* It seems to perform this check before the hkey check */
3495 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3496 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3497 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3498 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3501 return ERROR_INVALID_PARAMETER
;
3504 return ERROR_INVALID_PARAMETER
;
3506 lpkey
= lookup_hkey( hkey
);
3508 return ERROR_INVALID_HANDLE
;
3510 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3512 return ERROR_SUCCESS
;
3516 /******************************************************************************
3517 * RegSaveKey32W [ADVAPI32.166]
3520 * hkey [I] Handle of key where save begins
3521 * lpFile [I] Address of filename to save to
3522 * sa [I] Address of security structure
3524 LONG WINAPI
RegSaveKey32W( HKEY hkey
, LPCWSTR lpFile
,
3525 LPSECURITY_ATTRIBUTES sa
)
3529 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3531 /* It appears to do this check before the hkey check */
3532 if (!lpFile
|| !*lpFile
)
3533 return ERROR_INVALID_PARAMETER
;
3535 lpkey
= lookup_hkey( hkey
);
3537 return ERROR_INVALID_HANDLE
;
3539 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3541 return ERROR_SUCCESS
;
3545 /******************************************************************************
3546 * RegSaveKey32A [ADVAPI32.165]
3548 LONG WINAPI
RegSaveKey32A( HKEY hkey
, LPCSTR lpFile
,
3549 LPSECURITY_ATTRIBUTES sa
)
3552 LPWSTR lpFileW
= strdupA2W(lpFile
);
3553 ret
= RegSaveKey32W( hkey
, lpFileW
, sa
);
3559 /******************************************************************************
3560 * RegRestoreKey32W [ADVAPI32.164]
3563 * hkey [I] Handle of key where restore begins
3564 * lpFile [I] Address of filename containing saved tree
3565 * dwFlags [I] Optional flags
3567 LONG WINAPI
RegRestoreKey32W( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3571 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3573 /* It seems to do this check before the hkey check */
3574 if (!lpFile
|| !*lpFile
)
3575 return ERROR_INVALID_PARAMETER
;
3577 lpkey
= lookup_hkey( hkey
);
3579 return ERROR_INVALID_HANDLE
;
3581 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3583 /* Check for file existence */
3585 return ERROR_SUCCESS
;
3589 /******************************************************************************
3590 * RegRestoreKey32A [ADVAPI32.163]
3592 LONG WINAPI
RegRestoreKey32A( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3595 LPWSTR lpFileW
= strdupA2W(lpFile
);
3596 ret
= RegRestoreKey32W( hkey
, lpFileW
, dwFlags
);
3597 if(lpFileW
) free(lpFileW
);
3602 /******************************************************************************
3603 * RegReplaceKey32W [ADVAPI32.162]
3606 * hkey [I] Handle of open key
3607 * lpSubKey [I] Address of name of subkey
3608 * lpNewFile [I] Address of filename for file with new data
3609 * lpOldFile [I] Address of filename for backup file
3611 LONG WINAPI
RegReplaceKey32W( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3616 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3617 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3619 lpkey
= lookup_hkey( hkey
);
3621 return ERROR_INVALID_HANDLE
;
3623 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3624 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3626 return ERROR_SUCCESS
;
3630 /******************************************************************************
3631 * RegReplaceKey32A [ADVAPI32.161]
3633 LONG WINAPI
RegReplaceKey32A( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3637 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3638 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3639 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3640 ret
= RegReplaceKey32W( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);