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>
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
43 #include "winversion.h"
45 static void REGISTRY_Init(void);
46 /* FIXME: following defines should be configured global ... */
48 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
49 #define WINE_PREFIX "/.wine"
50 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
51 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
53 /* relative in ~user/.wine/ : */
54 #define SAVE_CURRENT_USER "user.reg"
55 #define SAVE_LOCAL_MACHINE "system.reg"
57 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
58 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
60 /* one value of a key */
61 typedef struct tagKEYVALUE
63 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
64 DWORD type
; /* type of value */
65 DWORD len
; /* length of data in BYTEs */
66 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
67 LPBYTE data
; /* content, may be strings, binaries, etc. */
68 } KEYVALUE
,*LPKEYVALUE
;
71 typedef struct tagKEYSTRUCT
73 LPWSTR keyname
; /* name of THIS key (UNICODE) */
74 DWORD flags
; /* flags. */
77 DWORD nrofvalues
; /* nr of values in THIS key */
78 LPKEYVALUE values
; /* values in THIS key */
79 /* key management pointers */
80 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
81 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
82 } KEYSTRUCT
, *LPKEYSTRUCT
;
85 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
86 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
87 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
88 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
90 /* dynamic, not saved */
91 static KEYSTRUCT
*key_performance_data
=NULL
;
92 static KEYSTRUCT
*key_current_config
=NULL
;
93 static KEYSTRUCT
*key_dyn_data
=NULL
;
95 /* what valuetypes do we need to convert? */
96 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
99 static struct openhandle
{
104 static int nrofopenhandles
=0;
105 /* Starts after 1 because 0,1 are reserved for Win16 */
106 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
107 HKEYs for remote registry access */
108 static int currenthandle
=2;
113 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
114 * If so, can we remove them?
116 * No, the memory handling functions are called very often in here,
117 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
118 * loading 100 times slower. -MM
120 static LPWSTR
strdupA2W(LPCSTR src
)
123 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
124 lstrcpyAtoW(dest
,src
);
130 static LPWSTR
strdupW(LPCWSTR a
) {
135 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
136 b
=(LPWSTR
)xmalloc(len
);
143 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
146 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
148 lstrcpynAtoW(dest
,src
,nchars
+1);
153 * we need to convert A to W with '\0' in strings (MULTI_SZ)
156 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
159 TRACE(reg
,"\"%s\" %i\n",src
, n
);
161 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
165 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
168 TRACE(string
,"L\"%s\" %i\n",debugstr_w(src
), n
);
170 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
175 static void debug_print_value (LPBYTE lpbData
, DWORD type
, DWORD len
)
176 { if (TRACE_ON(reg
) && lpbData
)
179 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
183 TRACE(reg
," Data(dword)=0x%08lx\n",(DWORD
)*lpbData
);
188 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
190 { TRACE(reg
, " MULTI_SZ(%i=%s)\n", i
, debugstr_w(ptr
));
191 ptr
+= lstrlenW(ptr
)+1;
197 { char szTemp
[100]; /* 3*32 + 3 + 1 */
199 for ( i
= 0; i
< len
; i
++)
200 { sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
202 { sprintf (&(szTemp
[i
*3+3]),"...");
206 TRACE(reg
," Data(raw)=(%s)\n", szTemp
);
211 FIXME(reg
, " Unknown data type %ld\n", type
);
218 /******************************************************************************
219 * is_standard_hkey [Internal]
220 * Determines if a hkey is a standard key
222 static BOOL
is_standard_hkey( HKEY hkey
)
227 case HKEY_CLASSES_ROOT
:
228 case HKEY_CURRENT_CONFIG
:
229 case HKEY_CURRENT_USER
:
230 case HKEY_LOCAL_MACHINE
:
232 case HKEY_PERFORMANCE_DATA
:
240 /******************************************************************************
241 * add_handle [Internal]
243 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
247 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
248 /* Check for duplicates */
249 for (i
=0;i
<nrofopenhandles
;i
++) {
250 if (openhandles
[i
].lpkey
==lpkey
) {
251 /* This is not really an error - the user is allowed to create
252 two (or more) handles to the same key */
253 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
255 if (openhandles
[i
].hkey
==hkey
) {
256 WARN(reg
, "Adding handle %x twice\n",hkey
);
259 openhandles
=xrealloc( openhandles
,
260 sizeof(struct openhandle
)*(nrofopenhandles
+1));
262 openhandles
[i
].lpkey
= lpkey
;
263 openhandles
[i
].hkey
= hkey
;
264 openhandles
[i
].accessmask
= accessmask
;
269 /******************************************************************************
270 * get_handle [Internal]
273 * Success: Pointer to key
276 static LPKEYSTRUCT
get_handle( HKEY hkey
)
280 for (i
=0; i
<nrofopenhandles
; i
++)
281 if (openhandles
[i
].hkey
== hkey
)
282 return openhandles
[i
].lpkey
;
283 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
288 /******************************************************************************
289 * remove_handle [Internal]
292 * hkey [I] Handle of key to remove
295 * Success: ERROR_SUCCESS
296 * Failure: ERROR_INVALID_HANDLE
298 static DWORD
remove_handle( HKEY hkey
)
302 for (i
=0;i
<nrofopenhandles
;i
++)
303 if (openhandles
[i
].hkey
==hkey
)
306 if (i
== nrofopenhandles
) {
307 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
308 return ERROR_INVALID_HANDLE
;
311 memcpy( openhandles
+i
,
313 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
315 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
317 return ERROR_SUCCESS
;
320 /******************************************************************************
321 * lookup_hkey [Internal]
323 * Just as the name says. Creates the root keys on demand, so we can call the
324 * Reg* functions at any time.
327 * Success: Pointer to key structure
330 #define ADD_ROOT_KEY(xx) \
331 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
332 memset(xx,'\0',sizeof(KEYSTRUCT));\
333 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
335 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
338 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
339 * some programs. Do not remove those cases. -MM
343 case HKEY_CLASSES_ROOT
: {
344 if (!key_classes_root
) {
347 /* calls lookup_hkey recursively, TWICE */
348 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
349 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
352 key_classes_root
= lookup_hkey(cl_r_hkey
);
354 return key_classes_root
;
356 case HKEY_CURRENT_USER
:
357 if (!key_current_user
) {
361 pwd
=getpwuid(getuid());
362 /* calls lookup_hkey recursively, TWICE */
363 if (pwd
&& pwd
->pw_name
) {
364 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
365 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
368 key_current_user
= lookup_hkey(c_u_hkey
);
370 /* nothing found, use standalone */
371 ADD_ROOT_KEY(key_current_user
);
374 return key_current_user
;
375 case HKEY_LOCAL_MACHINE
:
376 if (!key_local_machine
) {
377 ADD_ROOT_KEY(key_local_machine
);
380 return key_local_machine
;
383 ADD_ROOT_KEY(key_users
);
386 case HKEY_PERFORMANCE_DATA
:
387 if (!key_performance_data
) {
388 ADD_ROOT_KEY(key_performance_data
);
390 return key_performance_data
;
393 ADD_ROOT_KEY(key_dyn_data
);
396 case HKEY_CURRENT_CONFIG
:
397 if (!key_current_config
) {
398 ADD_ROOT_KEY(key_current_config
);
400 return key_current_config
;
402 return get_handle(hkey
);
407 /* so we don't accidently access them ... */
408 #define key_current_config NULL NULL
409 #define key_current_user NULL NULL
410 #define key_users NULL NULL
411 #define key_local_machine NULL NULL
412 #define key_classes_root NULL NULL
413 #define key_dyn_data NULL NULL
414 #define key_performance_data NULL NULL
416 /******************************************************************************
417 * split_keypath [Internal]
418 * splits the unicode string 'wp' into an array of strings.
419 * the array is allocated by this function.
420 * Free the array using FREE_KEY_PATH
423 * wp [I] String to split up
424 * wpv [O] Array of pointers to strings
425 * wpc [O] Number of components
427 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
432 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
434 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
436 /* We know we have at least one substring */
439 /* Replace each backslash with NULL, and increment the count */
440 for (i
=0;ws
[i
];i
++) {
449 /* Allocate the space for the array of pointers, leaving room for the
451 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
454 /* Assign each pointer to the appropriate character in the string */
459 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
464 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
469 /******************************************************************************
470 * REGISTRY_Init [Internal]
471 * Registry initialisation, allocates some default keys.
473 static void REGISTRY_Init(void) {
477 TRACE(reg
,"(void)\n");
479 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
482 /* This was an Open, but since it is called before the real registries
483 are loaded, it was changed to a Create - MTB 980507*/
484 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
485 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
488 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
492 * string RegisteredOwner
493 * string RegisteredOrganization
496 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
501 if (-1!=gethostname(buf
,200)) {
502 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
503 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
509 /************************ SAVE Registry Function ****************************/
511 #define REGISTRY_SAVE_VERSION 0x00000001
513 /* Registry saveformat:
514 * If you change it, increase above number by 1, which will flush
515 * old registry database files.
518 * "WINE REGISTRY Version %d"
522 * valuename=lastmodified,type,data
526 * keyname,valuename,stringdata:
527 * the usual ascii characters from 0x00-0xff (well, not 0x00)
528 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
529 * ( "=\\\t" escaped in \uXXXX form.)
533 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
535 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
536 * SaveOnlyUpdatedKeys=yes
539 /******************************************************************************
540 * _save_check_tainted [Internal]
542 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
548 if (lpkey
->flags
& REG_OPTION_TAINTED
)
553 if (_save_check_tainted(lpkey
->nextsub
)) {
554 lpkey
->flags
|= REG_OPTION_TAINTED
;
562 /******************************************************************************
563 * _save_USTRING [Internal]
565 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
579 if (escapeeq
&& *s
=='=')
582 fputc(*s
,F
); /* if \\ then put it twice. */
584 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
591 /******************************************************************************
592 * _savesubkey [Internal]
595 * REG_MULTI_SZ is handled as binary (like in win95) (js)
597 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
604 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
605 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
607 for (tabs
=level
;tabs
--;)
609 _save_USTRING(F
,lpxkey
->keyname
,1);
611 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
612 LPKEYVALUE val
=lpxkey
->values
+i
;
614 for (tabs
=level
+1;tabs
--;)
616 _save_USTRING(F
,val
->name
,0);
618 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
619 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
620 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
622 for (j
=0;j
<val
->len
;j
++)
623 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
626 /* descend recursively */
627 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
636 /******************************************************************************
637 * _savesubreg [Internal]
639 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
641 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
642 _save_check_tainted(lpkey
->nextsub
);
643 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
647 /******************************************************************************
648 * _savereg [Internal]
650 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
656 WARN(reg
,"Couldn't open %s for writing: %s\n",
661 if (!_savesubreg(F
,lpkey
,all
)) {
664 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
672 /******************************************************************************
673 * SHELL_SaveRegistry [Internal]
675 void SHELL_SaveRegistry( void )
683 TRACE(reg
,"(void)\n");
686 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
692 if ( (ERROR_SUCCESS
!=RegQueryValueExA(
704 if (lstrcmpiA(buf
,"yes"))
706 pwd
=getpwuid(getuid());
707 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
711 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
712 strlen(SAVE_CURRENT_USER
) + 2 );
713 strcpy(fn
,pwd
->pw_dir
);
714 strcat(fn
,WINE_PREFIX
);
715 /* create the directory. don't care about errorcodes. */
716 mkdir(fn
,0755); /* drwxr-xr-x */
717 strcat(fn
,"/"SAVE_CURRENT_USER
);
718 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
719 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
720 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
721 if (-1==rename(tmp
,fn
)) {
722 perror("rename tmp registry");
728 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
729 strcpy(fn
,pwd
->pw_dir
);
730 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
731 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
732 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
733 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
734 if (-1==rename(tmp
,fn
)) {
735 perror("rename tmp registry");
742 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
746 /************************ LOAD Registry Function ****************************/
750 /******************************************************************************
751 * _find_or_add_key [Internal]
753 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
755 LPKEYSTRUCT lpxkey
,*lplpkey
;
757 if ((!keyname
) || (keyname
[0]==0)) {
761 lplpkey
= &(lpkey
->nextsub
);
764 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
765 !lstrcmpiW(lpxkey
->keyname
,keyname
)
768 lplpkey
= &(lpxkey
->next
);
772 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
774 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
775 lpxkey
->keyname
= keyname
;
781 /******************************************************************************
782 * _find_or_add_value [Internal]
784 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
785 LPBYTE data
, DWORD len
, DWORD lastmodified
)
790 if (name
&& !*name
) {/* empty string equals default (NULL) value */
795 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
801 if ( val
->name
!=NULL
&&
802 val
->name
[0]==name
[0] &&
803 !lstrcmpiW(val
->name
,name
)
808 if (i
==lpkey
->nrofvalues
) {
809 lpkey
->values
= xrealloc(
811 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
814 memset(val
,'\0',sizeof(KEYVALUE
));
820 if (val
->lastmodified
<lastmodified
) {
821 val
->lastmodified
=lastmodified
;
832 /******************************************************************************
833 * _wine_read_line [Internal]
835 * reads a line including dynamically enlarging the readbuffer and throwing
838 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
848 s
=fgets(curread
,mylen
,F
);
851 if (NULL
==(s
=strchr(curread
,'\n'))) {
852 /* buffer wasn't large enough */
853 curoff
= strlen(*buf
);
854 *buf
= xrealloc(*buf
,*len
*2);
855 curread
= *buf
+ curoff
;
856 mylen
= *len
; /* we filled up the buffer and
857 * got new '*len' bytes to fill
865 /* throw away comments */
866 if (**buf
=='#' || **buf
==';') {
871 if (s
) /* got end of line */
878 /******************************************************************************
879 * _wine_read_USTRING [Internal]
881 * converts a char* into a UNICODE string (up to a special char)
882 * and returns the position exactly after that string
884 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
889 /* read up to "=" or "\0" or "\n" */
892 /* empty string is the win3.1 default value(NULL)*/
896 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
898 while (*s
&& (*s
!='\n') && (*s
!='=')) {
900 *ws
++=*((unsigned char*)s
++);
904 /* Dangling \ ... may only happen if a registry
905 * write was short. FIXME: What do to?
915 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
923 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
924 if (!sscanf(xbuf
,"%x",&wc
))
925 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
927 *ws
++ =(unsigned short)wc
;
934 *str
= strdupW(*str
);
942 /******************************************************************************
943 * _wine_loadsubkey [Internal]
946 * It seems like this is returning a boolean. Should it?
952 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
953 int *buflen
, DWORD optflag
)
960 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
963 lpkey
->flags
|= optflag
;
965 /* Good. We already got a line here ... so parse it */
975 WARN(reg
,"Got a subhierarchy without resp. key?\n");
978 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
982 /* let the caller handle this line */
983 if (i
<level
|| **buf
=='\0')
986 /* it can be: a value or a keyname. Parse the name first */
987 s
=_wine_read_USTRING(s
,&name
);
989 /* switch() default: hack to avoid gotos */
993 lpxkey
=_find_or_add_key(lpkey
,name
);
996 int len
,lastmodified
,type
;
999 WARN(reg
,"Unexpected character: %c\n",*s
);
1003 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1004 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
1008 s
=strchr(s
,',');s
++;
1009 s
=strchr(s
,',');s
++;
1010 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1011 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1013 len
= lstrlenW((LPWSTR
)data
)*2+2;
1018 data
= (LPBYTE
)xmalloc(len
+1);
1019 for (i
=0;i
<len
;i
++) {
1021 if (*s
>='0' && *s
<='9')
1022 data
[i
]=(*s
-'0')<<4;
1023 if (*s
>='a' && *s
<='f')
1024 data
[i
]=(*s
-'a'+'\xa')<<4;
1025 if (*s
>='A' && *s
<='F')
1026 data
[i
]=(*s
-'A'+'\xa')<<4;
1028 if (*s
>='0' && *s
<='9')
1030 if (*s
>='a' && *s
<='f')
1031 data
[i
]|=*s
-'a'+'\xa';
1032 if (*s
>='A' && *s
<='F')
1033 data
[i
]|=*s
-'A'+'\xa';
1037 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1040 /* read the next line */
1041 if (!_wine_read_line(F
,buf
,buflen
))
1048 /******************************************************************************
1049 * _wine_loadsubreg [Internal]
1051 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1057 buf
=xmalloc(10);buflen
=10;
1058 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1062 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1066 if (ver
!=REGISTRY_SAVE_VERSION
) {
1067 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1071 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1075 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1084 /******************************************************************************
1085 * _wine_loadreg [Internal]
1087 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1091 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1095 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1098 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1107 /******************************************************************************
1108 * _copy_registry [Internal]
1110 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1118 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1120 for (j
=0;j
<from
->nrofvalues
;j
++) {
1124 valfrom
= from
->values
+j
;
1126 if (name
) name
=strdupW(name
);
1127 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1128 memcpy(data
,valfrom
->data
,valfrom
->len
);
1136 valfrom
->lastmodified
1139 _copy_registry(from
,lpxkey
);
1145 /* WINDOWS 95 REGISTRY LOADER */
1147 * Structure of a win95 registry database.
1149 * 0 : "CREG" - magic
1151 * 8 : DWORD offset_of_RGDB_part
1152 * 0C..0F: ? (someone fill in please)
1153 * 10: WORD number of RGDB blocks
1155 * 14: WORD always 0000?
1156 * 16: WORD always 0001?
1157 * 18..1F: ? (someone fill in please)
1161 * 0 : "RGKN" - magic
1162 * 4 : DWORD offset to first RGDB section
1163 * 8 : DWORD offset to the root record
1164 * C..0x1B: ? (fill in)
1165 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1167 * Disk Key Entry Structure:
1168 * 00: DWORD - Free entry indicator(?)
1169 * 04: DWORD - Hash = sum of bytes of keyname
1170 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1171 * 0C: DWORD - disk address of PreviousLevel Key.
1172 * 10: DWORD - disk address of Next Sublevel Key.
1173 * 14: DWORD - disk address of Next Key (on same level).
1174 * DKEP>18: WORD - Nr, Low Significant part.
1175 * 1A: WORD - Nr, High Significant part.
1177 * The disk address always points to the nr part of the previous key entry
1178 * of the referenced key. Don't ask me why, or even if I got this correct
1179 * from staring at 1kg of hexdumps. (DKEP)
1181 * The High significant part of the structure seems to equal the number
1182 * of the RGDB section. The low significant part is a unique ID within
1185 * There are two minor corrections to the position of that structure.
1186 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1187 * the DKE reread from there.
1188 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1189 * CPS - I have not experienced the above phenomenon in my registry files
1192 * 00: "RGDB" - magic
1193 * 04: DWORD offset to next RGDB section
1195 * 0C: WORD always 000d?
1196 * 0E: WORD RGDB block number
1197 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1199 * 20.....: disk keys
1202 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1203 * 08: WORD nrLS - low significant part of NR
1204 * 0A: WORD nrHS - high significant part of NR
1205 * 0C: DWORD bytesused - bytes used in this structure.
1206 * 10: WORD name_len - length of name in bytes. without \0
1207 * 12: WORD nr_of_values - number of values.
1208 * 14: char name[name_len] - name string. No \0.
1209 * 14+name_len: disk values
1210 * nextkeyoffset: ... next disk key
1213 * 00: DWORD type - value type (hmm, could be WORD too)
1214 * 04: DWORD - unknown, usually 0
1215 * 08: WORD namelen - length of Name. 0 means name=NULL
1216 * 0C: WORD datalen - length of Data.
1217 * 10: char name[namelen] - name, no \0
1218 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1219 * 10+namelen+datalen: next values or disk key
1221 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1222 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1223 * structure) and reading another RGDB_section.
1224 * repeat until end of file.
1226 * An interesting relationship exists in RGDB_section. The value at offset
1227 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1228 * idea at the moment what this means. (Kevin Cozens)
1230 * FIXME: this description needs some serious help, yes.
1233 struct _w95keyvalue
{
1235 unsigned short datalen
;
1237 unsigned char *data
;
1245 struct _w95keyvalue
*values
;
1246 struct _w95key
*prevlvl
;
1247 struct _w95key
*nextsub
;
1248 struct _w95key
*next
;
1262 /******************************************************************************
1263 * _w95_processKey [Internal]
1265 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1266 int nrLS
, int nrMS
, struct _w95_info
*info
)
1269 /* Disk Key Header structure (RGDB part) */
1271 unsigned long nextkeyoff
;
1272 unsigned short nrLS
;
1273 unsigned short nrMS
;
1274 unsigned long bytesused
;
1275 unsigned short keynamelen
;
1276 unsigned short values
;
1279 /* disk key values or nothing */
1281 /* Disk Key Value structure */
1285 unsigned short valnamelen
;
1286 unsigned short valdatalen
;
1287 /* valname, valdata */
1293 char *rgdbdata
= info
->rgdbbuffer
;
1294 int nbytes
= info
->rgdbsize
;
1295 char *curdata
= rgdbdata
;
1296 char *end
= rgdbdata
+ nbytes
;
1298 char *next
= rgdbdata
;
1304 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1306 memcpy(&off_next_rgdb
,curdata
+4,4);
1307 next
= curdata
+ off_next_rgdb
;
1308 nrgdb
= (int) *((short *)curdata
+ 7);
1310 } while (nrgdb
!= nrMS
&& (next
< end
));
1312 /* curdata now points to the start of the right RGDB section */
1315 #define XREAD(whereto,len) \
1316 if ((curdata + len) <end) {\
1317 memcpy(whereto,curdata,len);\
1322 while (curdata
< next
) {
1323 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1325 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1326 if (xdkh
->nrLS
== nrLS
) {
1327 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1328 curdata
+= sizeof(dkh
);
1331 curdata
+= xdkh
->nextkeyoff
;
1334 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1336 if (nrgdb
!= dkh
.nrMS
)
1339 assert((dkh
.keynamelen
<2) || curdata
[0]);
1340 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1341 curdata
+= dkh
.keynamelen
;
1343 for (i
=0;i
< dkh
.values
; i
++) {
1349 XREAD(&dkv
,sizeof(dkv
));
1351 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1352 curdata
+= dkv
.valnamelen
;
1354 if ((1 << dkv
.type
) & UNICONVMASK
) {
1355 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1356 len
= 2*(dkv
.valdatalen
+ 1);
1358 /* I don't think we want to NULL terminate all data */
1359 data
= xmalloc(dkv
.valdatalen
);
1360 memcpy (data
, curdata
, dkv
.valdatalen
);
1361 len
= dkv
.valdatalen
;
1364 curdata
+= dkv
.valdatalen
;
1378 /******************************************************************************
1379 * _w95_walkrgkn [Internal]
1381 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1382 struct _w95_info
*info
)
1385 /* Disk Key Entry structure (RGKN part) */
1389 unsigned long x3
;/*usually 0xFFFFFFFF */
1390 unsigned long prevlvl
;
1391 unsigned long nextsub
;
1393 unsigned short nrLS
;
1394 unsigned short nrMS
;
1395 } *dke
= (struct dke
*)off
;
1399 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1402 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1403 /* XXX <-- This is a hack*/
1408 if (dke
->nextsub
!= -1 &&
1409 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1410 && (dke
->nextsub
> 0x20)) {
1412 _w95_walkrgkn(lpxkey
,
1413 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1417 if (dke
->next
!= -1 &&
1418 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1419 (dke
->next
> 0x20)) {
1420 _w95_walkrgkn(prevkey
,
1421 info
->rgknbuffer
+ dke
->next
- 0x20,
1429 /******************************************************************************
1430 * _w95_loadreg [Internal]
1432 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1436 unsigned long where
,version
,rgdbsection
,end
;
1437 struct _w95_info info
;
1439 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1441 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1442 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1443 if (hfd
==HFILE_ERROR
)
1446 if (4!=_lread(hfd
,magic
,4))
1448 if (strcmp(magic
,"CREG")) {
1449 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1452 if (4!=_lread(hfd
,&version
,4))
1454 if (4!=_lread(hfd
,&rgdbsection
,4))
1456 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1458 if (4!=_lread(hfd
,magic
,4))
1460 if (strcmp(magic
,"RGKN")) {
1461 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1465 /* STEP 1: Keylink structures */
1466 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1471 info
.rgknsize
= end
- where
;
1472 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1473 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1476 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1479 end
= hfdinfo
.nFileSizeLow
;
1480 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1482 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1485 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1486 info
.rgdbsize
= end
- rgdbsection
;
1488 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1492 _w95_walkrgkn(lpkey
, NULL
, &info
);
1494 free (info
.rgdbbuffer
);
1495 free (info
.rgknbuffer
);
1499 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1502 reghack - windows 3.11 registry data format demo program.
1504 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1505 a combined hash table and tree description, and finally a text table.
1507 The header is obvious from the struct header. The taboff1 and taboff2
1508 fields are always 0x20, and their usage is unknown.
1510 The 8-byte entry table has various entry types.
1512 tabent[0] is a root index. The second word has the index of the root of
1514 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1515 the index of the key/value that has that hash. Data with the same
1516 hash value are on a circular list. The other three words in the
1517 hash entry are always zero.
1518 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1519 entry: dirent and keyent/valent. They are identified by context.
1520 tabent[freeidx] is the first free entry. The first word in a free entry
1521 is the index of the next free entry. The last has 0 as a link.
1522 The other three words in the free list are probably irrelevant.
1524 Entries in text table are preceeded by a word at offset-2. This word
1525 has the value (2*index)+1, where index is the referring keyent/valent
1526 entry in the table. I have no suggestion for the 2* and the +1.
1527 Following the word, there are N bytes of data, as per the keyent/valent
1528 entry length. The offset of the keyent/valent entry is from the start
1529 of the text table to the first data byte.
1531 This information is not available from Microsoft. The data format is
1532 deduced from the reg.dat file by me. Mistakes may
1533 have been made. I claim no rights and give no guarantees for this program.
1535 Tor Sjøwall, tor@sn.no
1538 /* reg.dat header format */
1539 struct _w31_header
{
1540 char cookie
[8]; /* 'SHCC3.10' */
1541 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1542 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1543 unsigned long tabcnt
; /* number of entries in index table */
1544 unsigned long textoff
; /* offset of text part */
1545 unsigned long textsize
; /* byte size of text part */
1546 unsigned short hashsize
; /* hash size */
1547 unsigned short freeidx
; /* free index */
1550 /* generic format of table entries */
1551 struct _w31_tabent
{
1552 unsigned short w0
, w1
, w2
, w3
;
1555 /* directory tabent: */
1556 struct _w31_dirent
{
1557 unsigned short sibling_idx
; /* table index of sibling dirent */
1558 unsigned short child_idx
; /* table index of child dirent */
1559 unsigned short key_idx
; /* table index of key keyent */
1560 unsigned short value_idx
; /* table index of value valent */
1564 struct _w31_keyent
{
1565 unsigned short hash_idx
; /* hash chain index for string */
1566 unsigned short refcnt
; /* reference count */
1567 unsigned short length
; /* length of string */
1568 unsigned short string_off
; /* offset of string in text table */
1572 struct _w31_valent
{
1573 unsigned short hash_idx
; /* hash chain index for string */
1574 unsigned short refcnt
; /* reference count */
1575 unsigned short length
; /* length of string */
1576 unsigned short string_off
; /* offset of string in text table */
1579 /* recursive helper function to display a directory tree */
1581 __w31_dumptree( unsigned short idx
,
1583 struct _w31_tabent
*tab
,
1584 struct _w31_header
*head
,
1586 time_t lastmodified
,
1589 struct _w31_dirent
*dir
;
1590 struct _w31_keyent
*key
;
1591 struct _w31_valent
*val
;
1592 LPKEYSTRUCT xlpkey
= NULL
;
1594 static char tail
[400];
1597 dir
=(struct _w31_dirent
*)&tab
[idx
];
1600 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1602 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1603 tail
[key
->length
]='\0';
1604 /* all toplevel entries AND the entries in the
1605 * toplevel subdirectory belong to \SOFTWARE\Classes
1607 if (!level
&& !lstrcmpA(tail
,".classes")) {
1608 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1609 idx
=dir
->sibling_idx
;
1612 name
=strdupA2W(tail
);
1614 xlpkey
=_find_or_add_key(lpkey
,name
);
1616 /* only add if leaf node or valued node */
1617 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1618 if (dir
->value_idx
) {
1619 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1620 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1621 tail
[val
->length
]='\0';
1622 value
=strdupA2W(tail
);
1623 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1627 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1629 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1630 idx
=dir
->sibling_idx
;
1635 /******************************************************************************
1636 * _w31_loadreg [Internal]
1638 void _w31_loadreg(void) {
1640 struct _w31_header head
;
1641 struct _w31_tabent
*tab
;
1645 BY_HANDLE_FILE_INFORMATION hfinfo
;
1646 time_t lastmodified
;
1649 TRACE(reg
,"(void)\n");
1651 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1652 if (hf
==HFILE_ERROR
)
1655 /* read & dump header */
1656 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1657 ERR(reg
, "reg.dat is too short.\n");
1661 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1662 ERR(reg
, "reg.dat has bad signature.\n");
1667 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1668 /* read and dump index table */
1670 if (len
!=_lread(hf
,tab
,len
)) {
1671 ERR(reg
,"couldn't read %d bytes.\n",len
);
1678 txt
= xmalloc(head
.textsize
);
1679 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1680 ERR(reg
,"couldn't seek to textblock.\n");
1686 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1687 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1694 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1695 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1701 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1702 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1703 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1711 /**********************************************************************************
1712 * SHELL_LoadRegistry [Internal]
1714 void SHELL_LoadRegistry( void )
1721 TRACE(reg
,"(void)\n");
1723 /* Load windows 3.1 entries */
1725 /* Load windows 95 entries */
1726 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1727 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1728 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1730 /* the global user default is loaded under HKEY_USERS\\.Default */
1731 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1732 lpkey
= lookup_hkey(hkey
);
1734 WARN(reg
,"Could not create global user default key\n");
1735 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1737 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1738 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1741 /* the global machine defaults */
1742 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1744 /* load the user saved registries */
1746 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1748 pwd
=getpwuid(getuid());
1749 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1750 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1751 strcpy(fn
,pwd
->pw_dir
);
1752 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1753 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1755 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1756 strcpy(fn
,pwd
->pw_dir
);
1757 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1758 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1761 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1762 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1763 DWORD junk
,type
,len
;
1767 if (( RegQueryValueExA(
1774 )!=ERROR_SUCCESS
) ||
1777 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1783 /********************* API FUNCTIONS ***************************************/
1787 * All functions are stubs to RegOpenKeyEx32W where all the
1791 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1792 * RegOpenKey32W -> RegOpenKeyEx32W
1796 /******************************************************************************
1797 * RegOpenKeyEx32W [ADVAPI32.150]
1798 * Opens the specified key
1800 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1803 * hkey [I] Handle of open key
1804 * lpszSubKey [I] Name of subkey to open
1805 * dwReserved [I] Reserved - must be zero
1806 * samDesired [I] Security access mask
1807 * retkey [O] Address of handle of open key
1810 * Success: ERROR_SUCCESS
1811 * Failure: Error code
1813 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1814 REGSAM samDesired
, LPHKEY retkey
)
1816 LPKEYSTRUCT lpNextKey
,lpxkey
;
1820 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1823 lpNextKey
= lookup_hkey( hkey
);
1825 return ERROR_INVALID_HANDLE
;
1827 if (!lpszSubKey
|| !*lpszSubKey
) {
1828 /* Either NULL or pointer to empty string, so return a new handle
1829 to the original hkey */
1831 add_handle(currenthandle
,lpNextKey
,samDesired
);
1832 *retkey
=currenthandle
;
1833 return ERROR_SUCCESS
;
1836 if (lpszSubKey
[0] == '\\') {
1837 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1838 return ERROR_BAD_PATHNAME
;
1841 split_keypath(lpszSubKey
,&wps
,&wpc
);
1843 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1847 lpxkey
=lpNextKey
->nextsub
;
1849 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
1852 lpxkey
=lpxkey
->next
;
1856 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1858 return ERROR_FILE_NOT_FOUND
;
1865 add_handle(currenthandle
,lpxkey
,samDesired
);
1866 *retkey
= currenthandle
;
1867 TRACE(reg
," Returning %x\n", currenthandle
);
1869 return ERROR_SUCCESS
;
1873 /******************************************************************************
1874 * RegOpenKeyEx32A [ADVAPI32.149]
1876 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1877 REGSAM samDesired
, LPHKEY retkey
)
1879 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1882 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1884 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
1890 /******************************************************************************
1891 * RegOpenKey32W [ADVAPI32.151]
1894 * hkey [I] Handle of open key
1895 * lpszSubKey [I] Address of name of subkey to open
1896 * retkey [O] Address of handle of open key
1899 * Success: ERROR_SUCCESS
1900 * Failure: Error code
1902 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1904 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1905 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
1909 /******************************************************************************
1910 * RegOpenKey32A [ADVAPI32.148]
1912 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1915 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1916 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1917 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
1923 /******************************************************************************
1924 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1926 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1928 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1929 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
1936 * All those functions convert their respective
1937 * arguments and call RegCreateKeyExW at the end.
1939 * We stay away from the Ex functions as long as possible because there are
1940 * differences in the return values
1943 * RegCreateKeyEx32A \
1944 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1948 /******************************************************************************
1949 * RegCreateKeyEx32W [ADVAPI32.131]
1952 * hkey [I] Handle of an open key
1953 * lpszSubKey [I] Address of subkey name
1954 * dwReserved [I] Reserved - must be 0
1955 * lpszClass [I] Address of class string
1956 * fdwOptions [I] Special options flag
1957 * samDesired [I] Desired security access
1958 * lpSecAttribs [I] Address of key security structure
1959 * retkey [O] Address of buffer for opened handle
1960 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1962 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
1963 DWORD dwReserved
, LPWSTR lpszClass
,
1964 DWORD fdwOptions
, REGSAM samDesired
,
1965 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1966 LPHKEY retkey
, LPDWORD lpDispos
)
1968 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1972 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
1973 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
1974 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
1976 lpNextKey
= lookup_hkey(hkey
);
1978 return ERROR_INVALID_HANDLE
;
1980 /* Check for valid options */
1981 switch(fdwOptions
) {
1982 case REG_OPTION_NON_VOLATILE
:
1983 case REG_OPTION_VOLATILE
:
1984 case REG_OPTION_BACKUP_RESTORE
:
1987 return ERROR_INVALID_PARAMETER
;
1990 /* Sam has to be a combination of the following */
1992 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
1993 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
1994 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
1995 return ERROR_INVALID_PARAMETER
;
1997 if (!lpszSubKey
|| !*lpszSubKey
) {
1999 add_handle(currenthandle
,lpNextKey
,samDesired
);
2000 *retkey
=currenthandle
;
2001 TRACE(reg
, "Returning %x\n", currenthandle
);
2002 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2003 return ERROR_SUCCESS
;
2006 if (lpszSubKey
[0] == '\\') {
2007 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2008 return ERROR_BAD_PATHNAME
;
2011 split_keypath(lpszSubKey
,&wps
,&wpc
);
2013 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2016 lpxkey
=lpNextKey
->nextsub
;
2018 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2020 lpxkey
=lpxkey
->next
;
2029 add_handle(currenthandle
,lpxkey
,samDesired
);
2030 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2031 *retkey
= currenthandle
;
2032 TRACE(reg
, "Returning %x\n", currenthandle
);
2034 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2036 return ERROR_SUCCESS
;
2039 /* Good. Now the hard part */
2041 lplpPrevKey
= &(lpNextKey
->nextsub
);
2042 lpxkey
= *lplpPrevKey
;
2044 lplpPrevKey
= &(lpxkey
->next
);
2045 lpxkey
= *lplpPrevKey
;
2047 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2048 if (!*lplpPrevKey
) {
2050 TRACE(reg
, "Returning OUTOFMEMORY\n");
2051 return ERROR_OUTOFMEMORY
;
2053 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2054 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
2055 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2056 (*lplpPrevKey
)->next
= NULL
;
2057 (*lplpPrevKey
)->nextsub
= NULL
;
2058 (*lplpPrevKey
)->values
= NULL
;
2059 (*lplpPrevKey
)->nrofvalues
= 0;
2060 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2062 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2064 (*lplpPrevKey
)->class = NULL
;
2065 lpNextKey
= *lplpPrevKey
;
2069 add_handle(currenthandle
,lpNextKey
,samDesired
);
2071 /*FIXME: flag handling correct? */
2072 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2074 lpNextKey
->class = strdupW(lpszClass
);
2076 lpNextKey
->class = NULL
;
2077 *retkey
= currenthandle
;
2078 TRACE(reg
, "Returning %x\n", currenthandle
);
2080 *lpDispos
= REG_CREATED_NEW_KEY
;
2082 return ERROR_SUCCESS
;
2086 /******************************************************************************
2087 * RegCreateKeyEx32A [ADVAPI32.130]
2089 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2090 LPSTR lpszClass
, DWORD fdwOptions
,
2092 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2093 LPHKEY retkey
, LPDWORD lpDispos
)
2095 LPWSTR lpszSubKeyW
, lpszClassW
;
2098 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2099 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2102 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2103 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2105 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2106 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2109 if(lpszSubKeyW
) free(lpszSubKeyW
);
2110 if(lpszClassW
) free(lpszClassW
);
2116 /******************************************************************************
2117 * RegCreateKey32W [ADVAPI32.132]
2119 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2122 LPKEYSTRUCT lpNextKey
;
2124 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2126 /* This check is here because the return value is different than the
2127 one from the Ex functions */
2128 lpNextKey
= lookup_hkey(hkey
);
2130 return ERROR_BADKEY
;
2132 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2133 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2138 /******************************************************************************
2139 * RegCreateKey32A [ADVAPI32.129]
2141 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2146 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2147 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2148 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2149 if(lpszSubKeyW
) free(lpszSubKeyW
);
2154 /******************************************************************************
2155 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2157 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2159 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2160 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2165 * Query Value Functions
2166 * Win32 differs between keynames and valuenames.
2167 * multiple values may belong to one key, the special value
2168 * with name NULL is the default value used by the win31
2172 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2173 * RegQueryValue32W -> RegQueryValueEx32W
2177 /******************************************************************************
2178 * RegQueryValueEx32W [ADVAPI32.158]
2179 * Retrieves type and data for a specified name associated with an open key
2182 * hkey [I] Handle of key to query
2183 * lpValueName [I] Name of value to query
2184 * lpdwReserved [I] Reserved - must be NULL
2185 * lpdwType [O] Address of buffer for value type. If NULL, the type
2187 * lpbData [O] Address of data buffer. If NULL, the actual data is
2189 * lpcbData [I/O] Address of data buffer size
2192 * ERROR_SUCCESS: Success
2193 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2194 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2196 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2197 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2198 LPBYTE lpbData
, LPDWORD lpcbData
)
2204 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2205 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2207 lpkey
= lookup_hkey(hkey
);
2210 return ERROR_INVALID_HANDLE
;
2212 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2213 return ERROR_INVALID_PARAMETER
;
2215 /* An empty name string is equivalent to NULL */
2216 if (lpValueName
&& !*lpValueName
)
2219 if (lpValueName
==NULL
)
2220 { /* Use key's unnamed or default value, if any */
2221 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2222 if (lpkey
->values
[i
].name
==NULL
)
2226 { /* Search for the key name */
2227 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2228 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2232 if (i
==lpkey
->nrofvalues
)
2233 { TRACE(reg
," Key not found\n");
2234 if (lpValueName
==NULL
)
2235 { /* Empty keyname not found */
2237 { *(WCHAR
*)lpbData
= 0;
2242 TRACE(reg
, " Returning an empty string\n");
2243 return ERROR_SUCCESS
;
2245 return ERROR_FILE_NOT_FOUND
;
2248 ret
= ERROR_SUCCESS
;
2250 if (lpdwType
) /* type required ?*/
2251 *lpdwType
= lpkey
->values
[i
].type
;
2253 if (lpbData
) /* data required ?*/
2254 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2255 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2257 ret
= ERROR_MORE_DATA
;
2260 if (lpcbData
) /* size required ?*/
2261 { *lpcbData
= lpkey
->values
[i
].len
;
2264 debug_print_value ( lpbData
, lpkey
->values
[i
].type
, lpkey
->values
[i
].len
);
2266 TRACE(reg
," (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2272 /******************************************************************************
2273 * RegQueryValue32W [ADVAPI32.159]
2275 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2281 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2282 lpcbData
?*lpcbData
:0);
2284 /* Only open subkey, if we really do descend */
2285 if (lpszSubKey
&& *lpszSubKey
) {
2286 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2287 if (ret
!= ERROR_SUCCESS
) {
2288 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2295 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2303 /******************************************************************************
2304 * RegQueryValueEx32A [ADVAPI32.157]
2307 * the documantation is wrong: if the buffer is to small it remains untouched
2309 * FIXME: check returnvalue (len) for an empty key
2311 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2312 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2313 LPBYTE lpbData
, LPDWORD lpcbData
)
2315 LPWSTR lpszValueNameW
;
2316 LPBYTE mybuf
= NULL
;
2317 DWORD ret
, mytype
, mylen
= 0;
2319 TRACE(reg
,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2320 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2322 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2323 { return ERROR_INVALID_PARAMETER
;
2326 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2328 /* get just the type first */
2329 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2331 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2332 { if(lpszValueNameW
) free(lpszValueNameW
);
2336 if (lpcbData
) /* at least length requested? */
2337 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2338 { if (lpbData
) /* value requested? */
2339 { mylen
= 2*( *lpcbData
);
2340 mybuf
= (LPBYTE
)xmalloc( mylen
);
2343 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2345 if (ret
== ERROR_SUCCESS
)
2347 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2351 *lpcbData
= mylen
/2; /* size is in byte! */
2353 else /* no strings, call it straight */
2354 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2358 if (lpdwType
) /* type when requested */
2359 { *lpdwType
= mytype
;
2362 TRACE(reg
," (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2364 if(mybuf
) free(mybuf
);
2365 if(lpszValueNameW
) free(lpszValueNameW
);
2370 /******************************************************************************
2371 * RegQueryValueEx16 [KERNEL.225]
2373 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2374 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2375 LPBYTE lpbData
, LPDWORD lpcbData
)
2377 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2378 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2379 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2380 lpbData
, lpcbData
);
2384 /******************************************************************************
2385 * RegQueryValue32A [ADVAPI32.156]
2387 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2393 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2394 lpcbData
?*lpcbData
:0);
2396 if (lpszSubKey
&& *lpszSubKey
) {
2397 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2398 if( ret
!= ERROR_SUCCESS
)
2404 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2407 RegCloseKey( xhkey
);
2412 /******************************************************************************
2413 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2416 * Is this HACK still applicable?
2419 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2420 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2423 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2426 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2427 lpcbData
?*lpcbData
:0);
2430 *lpcbData
&= 0xFFFF;
2431 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2436 * Setting values of Registry keys
2439 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2440 * RegSetValue32W -> RegSetValueEx32W
2444 /******************************************************************************
2445 * RegSetValueEx32W [ADVAPI32.170]
2446 * Sets the data and type of a value under a register key
2449 * hkey [I] Handle of key to set value for
2450 * lpszValueName [I] Name of value to set
2451 * dwReserved [I] Reserved - must be zero
2452 * dwType [I] Flag for value type
2453 * lpbData [I] Address of value data
2454 * cbData [I] Size of value data
2457 * Success: ERROR_SUCCESS
2458 * Failure: Error code
2461 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2463 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2464 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2470 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2471 dwReserved
, dwType
, lpbData
, cbData
);
2473 debug_print_value ( lpbData
, dwType
, cbData
);
2475 lpkey
= lookup_hkey( hkey
);
2478 return ERROR_INVALID_HANDLE
;
2480 lpkey
->flags
|= REG_OPTION_TAINTED
;
2482 if (lpszValueName
==NULL
) {
2483 /* Sets type and name for key's unnamed or default value */
2484 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2485 if (lpkey
->values
[i
].name
==NULL
)
2488 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2489 if ( lpkey
->values
[i
].name
&&
2490 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2494 if (i
==lpkey
->nrofvalues
) {
2495 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2497 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2499 lpkey
->nrofvalues
++;
2500 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2502 if (lpkey
->values
[i
].name
==NULL
) {
2504 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2506 lpkey
->values
[i
].name
= NULL
;
2509 if (dwType
== REG_SZ
)
2510 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2512 lpkey
->values
[i
].len
= cbData
;
2513 lpkey
->values
[i
].type
= dwType
;
2514 if (lpkey
->values
[i
].data
!=NULL
)
2515 free(lpkey
->values
[i
].data
);
2516 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2517 lpkey
->values
[i
].lastmodified
= time(NULL
);
2518 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2519 return ERROR_SUCCESS
;
2523 /******************************************************************************
2524 * RegSetValueEx32A [ADVAPI32.169]
2527 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2529 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2530 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2534 LPWSTR lpszValueNameW
;
2538 return (ERROR_INVALID_PARAMETER
);
2540 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2541 dwReserved
,dwType
,lpbData
,cbData
);
2543 if ((1<<dwType
) & UNICONVMASK
)
2544 { if (dwType
== REG_SZ
)
2545 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2547 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2548 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2555 lpszValueNameW
= strdupA2W(lpszValueName
);
2557 lpszValueNameW
= NULL
;
2559 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2562 free(lpszValueNameW
);
2571 /******************************************************************************
2572 * RegSetValueEx16 [KERNEL.226]
2574 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2575 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2577 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2578 dwReserved
,dwType
,lpbData
,cbData
);
2579 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2584 /******************************************************************************
2585 * RegSetValue32W [ADVAPI32.171]
2587 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2588 LPCWSTR lpszData
, DWORD cbData
)
2593 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2594 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2596 if (lpszSubKey
&& *lpszSubKey
) {
2597 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2598 if (ret
!=ERROR_SUCCESS
)
2602 if (dwType
!=REG_SZ
) {
2603 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2606 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2607 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2608 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2610 cbData
=2*lstrlenW(lpszData
)+2;
2612 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2619 /******************************************************************************
2620 * RegSetValue32A [ADVAPI32.168]
2623 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2624 LPCSTR lpszData
, DWORD cbData
)
2629 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2630 if (lpszSubKey
&& *lpszSubKey
) {
2631 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2632 if (ret
!=ERROR_SUCCESS
)
2637 if (dwType
!=REG_SZ
) {
2638 TRACE(reg
,"dwType=%ld!\n",dwType
);
2641 if (cbData
!=strlen(lpszData
)+1)
2642 cbData
=strlen(lpszData
)+1;
2643 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2650 /******************************************************************************
2651 * RegSetValue16 [KERNEL.221] [SHELL.5]
2653 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2654 LPCSTR lpszData
, DWORD cbData
)
2656 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2657 debugstr_a(lpszData
),cbData
);
2658 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2666 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2667 * RegEnumKey32W -> RegEnumKeyEx32W
2671 /******************************************************************************
2672 * RegEnumKeyEx32W [ADVAPI32.139]
2675 * hkey [I] Handle to key to enumerate
2676 * iSubKey [I] Index of subkey to enumerate
2677 * lpszName [O] Buffer for subkey name
2678 * lpcchName [O] Size of subkey buffer
2679 * lpdwReserved [I] Reserved
2680 * lpszClass [O] Buffer for class string
2681 * lpcchClass [O] Size of class buffer
2682 * ft [O] Time key last written to
2684 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2685 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2686 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2689 LPKEYSTRUCT lpkey
,lpxkey
;
2691 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2692 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2694 lpkey
= lookup_hkey( hkey
);
2696 return ERROR_INVALID_HANDLE
;
2698 if (!lpkey
->nextsub
)
2699 return ERROR_NO_MORE_ITEMS
;
2700 lpxkey
=lpkey
->nextsub
;
2702 /* Traverse the subkeys */
2703 while (iSubkey
&& lpxkey
) {
2705 lpxkey
=lpxkey
->next
;
2708 if (iSubkey
|| !lpxkey
)
2709 return ERROR_NO_MORE_ITEMS
;
2710 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
2711 return ERROR_MORE_DATA
;
2712 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
2715 *lpcchName
= lstrlenW(lpszName
);
2718 /* FIXME: what should we write into it? */
2722 return ERROR_SUCCESS
;
2726 /******************************************************************************
2727 * RegEnumKey32W [ADVAPI32.140]
2729 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2734 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2735 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2739 /******************************************************************************
2740 * RegEnumKeyEx32A [ADVAPI32.138]
2742 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2743 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2744 LPSTR lpszClass
, LPDWORD lpcchClass
,
2747 DWORD ret
,lpcchNameW
,lpcchClassW
;
2748 LPWSTR lpszNameW
,lpszClassW
;
2751 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2752 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2755 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2756 lpcchNameW
= *lpcchName
;
2762 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2763 lpcchClassW
= *lpcchClass
;
2778 if (ret
==ERROR_SUCCESS
) {
2779 lstrcpyWtoA(lpszName
,lpszNameW
);
2780 *lpcchName
=strlen(lpszName
);
2782 lstrcpyWtoA(lpszClass
,lpszClassW
);
2783 *lpcchClass
=strlen(lpszClass
);
2794 /******************************************************************************
2795 * RegEnumKey32A [ADVAPI32.137]
2797 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2802 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2803 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2808 /******************************************************************************
2809 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2811 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2814 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2815 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
2820 * Enumerate Registry Values
2823 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2827 /******************************************************************************
2828 * RegEnumValue32W [ADVAPI32.142]
2831 * hkey [I] Handle to key to query
2832 * iValue [I] Index of value to query
2833 * lpszValue [O] Value string
2834 * lpcchValue [I/O] Size of value buffer (in wchars)
2835 * lpdReserved [I] Reserved
2836 * lpdwType [O] Type code
2837 * lpbData [O] Value data
2838 * lpcbData [I/O] Size of data buffer (in bytes)
2840 * Note: wide character functions that take and/or return "character counts"
2841 * use TCHAR (that is unsigned short or char) not byte counts.
2843 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
2844 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2845 LPDWORD lpdwType
, LPBYTE lpbData
,
2851 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
2852 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2854 lpkey
= lookup_hkey( hkey
);
2856 if (!lpcbData
&& lpbData
)
2857 return ERROR_INVALID_PARAMETER
;
2860 return ERROR_INVALID_HANDLE
;
2862 if (lpkey
->nrofvalues
<= iValue
)
2863 return ERROR_NO_MORE_ITEMS
;
2865 val
= &(lpkey
->values
[iValue
]);
2868 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
2869 *lpcchValue
= lstrlenW(val
->name
)+1;
2870 return ERROR_MORE_DATA
;
2872 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
2873 *lpcchValue
=lstrlenW(val
->name
);
2879 /* Can be NULL if the type code is not required */
2881 *lpdwType
= val
->type
;
2884 if (val
->len
>*lpcbData
)
2885 return ERROR_MORE_DATA
;
2886 memcpy(lpbData
,val
->data
,val
->len
);
2887 *lpcbData
= val
->len
;
2890 debug_print_value ( val
->data
, val
->type
, val
->len
);
2891 return ERROR_SUCCESS
;
2895 /******************************************************************************
2896 * RegEnumValue32A [ADVAPI32.141]
2898 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2899 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2900 LPDWORD lpdwType
, LPBYTE lpbData
,
2905 DWORD ret
,lpcbDataW
;
2908 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2909 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2911 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2913 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2914 lpcbDataW
= *lpcbData
;
2918 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
2919 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
2924 if (ret
==ERROR_SUCCESS
) {
2925 lstrcpyWtoA(lpszValue
,lpszValueW
);
2927 if ((1<<dwType
) & UNICONVMASK
) {
2928 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2930 if (lpcbDataW
> *lpcbData
)
2931 ret
= ERROR_MORE_DATA
;
2933 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2935 *lpcbData
= lpcbDataW
;
2938 if (lpbDataW
) free(lpbDataW
);
2939 if (lpszValueW
) free(lpszValueW
);
2944 /******************************************************************************
2945 * RegEnumValue16 [KERNEL.223]
2947 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2948 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2949 LPDWORD lpdwType
, LPBYTE lpbData
,
2952 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2953 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2954 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
2955 lpdwType
, lpbData
, lpcbData
);
2959 /******************************************************************************
2960 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2961 * Releases the handle of the specified key
2964 * hkey [I] Handle of key to close
2967 * Success: ERROR_SUCCESS
2968 * Failure: Error code
2970 DWORD WINAPI
RegCloseKey( HKEY hkey
)
2972 TRACE(reg
,"(%x)\n",hkey
);
2974 /* The standard handles are allowed to succeed, even though they are not
2976 if (is_standard_hkey(hkey
))
2977 return ERROR_SUCCESS
;
2979 return remove_handle(hkey
);
2984 * Delete registry key
2987 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2991 /******************************************************************************
2992 * RegDeleteKey32W [ADVAPI32.134]
2995 * hkey [I] Handle to open key
2996 * lpszSubKey [I] Name of subkey to delete
2999 * Success: ERROR_SUCCESS
3000 * Failure: Error code
3002 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3004 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3008 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3010 lpNextKey
= lookup_hkey(hkey
);
3012 return ERROR_INVALID_HANDLE
;
3014 /* Subkey param cannot be NULL */
3015 if (!lpszSubKey
|| !*lpszSubKey
)
3016 return ERROR_BADKEY
;
3018 /* We need to know the previous key in the hier. */
3019 split_keypath(lpszSubKey
,&wps
,&wpc
);
3023 lpxkey
=lpNextKey
->nextsub
;
3025 TRACE(reg
, " Scanning [%s]\n",
3026 debugstr_w(lpxkey
->keyname
));
3027 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3029 lpxkey
=lpxkey
->next
;
3033 TRACE(reg
, " Not found.\n");
3034 /* not found is success */
3035 return ERROR_SUCCESS
;
3040 lpxkey
= lpNextKey
->nextsub
;
3041 lplpPrevKey
= &(lpNextKey
->nextsub
);
3043 TRACE(reg
, " Scanning [%s]\n",
3044 debugstr_w(lpxkey
->keyname
));
3045 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3047 lplpPrevKey
= &(lpxkey
->next
);
3048 lpxkey
= lpxkey
->next
;
3053 WARN(reg
, " Not found.\n");
3054 return ERROR_FILE_NOT_FOUND
;
3057 if (lpxkey
->nextsub
) {
3059 WARN(reg
, " Not empty.\n");
3060 return ERROR_CANTWRITE
;
3062 *lplpPrevKey
= lpxkey
->next
;
3063 free(lpxkey
->keyname
);
3065 free(lpxkey
->class);
3067 free(lpxkey
->values
);
3070 TRACE(reg
, " Done.\n");
3071 return ERROR_SUCCESS
;
3075 /******************************************************************************
3076 * RegDeleteKey32A [ADVAPI32.133]
3078 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3083 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3084 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3085 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3086 if(lpszSubKeyW
) free(lpszSubKeyW
);
3091 /******************************************************************************
3092 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3094 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3096 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3097 return RegDeleteKeyA( hkey
, lpszSubKey
);
3102 * Delete registry value
3105 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3109 /******************************************************************************
3110 * RegDeleteValue32W [ADVAPI32.136]
3118 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3124 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3126 lpkey
= lookup_hkey( hkey
);
3128 return ERROR_INVALID_HANDLE
;
3131 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3132 if ( lpkey
->values
[i
].name
&&
3133 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3137 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3138 if (lpkey
->values
[i
].name
==NULL
)
3142 if (i
== lpkey
->nrofvalues
)
3143 return ERROR_FILE_NOT_FOUND
;
3145 val
= lpkey
->values
+i
;
3146 if (val
->name
) free(val
->name
);
3147 if (val
->data
) free(val
->data
);
3151 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3153 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3155 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3157 lpkey
->nrofvalues
--;
3158 return ERROR_SUCCESS
;
3162 /******************************************************************************
3163 * RegDeleteValue32A [ADVAPI32.135]
3165 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3170 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3171 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3172 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3173 if(lpszValueW
) free(lpszValueW
);
3178 /******************************************************************************
3179 * RegDeleteValue16 [KERNEL.222]
3181 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3183 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3184 return RegDeleteValueA( hkey
, lpszValue
);
3188 /******************************************************************************
3189 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3190 * Writes key to registry
3193 * hkey [I] Handle of key to write
3196 * Success: ERROR_SUCCESS
3197 * Failure: Error code
3199 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3204 TRACE(reg
, "(%x)\n", hkey
);
3206 lpkey
= lookup_hkey( hkey
);
3208 return ERROR_BADKEY
;
3210 ERR(reg
, "What is the correct filename?\n");
3212 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3215 return ERROR_SUCCESS
;
3217 return ERROR_UNKNOWN
; /* FIXME */
3221 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3224 /******************************************************************************
3225 * RegQueryInfoKey32W [ADVAPI32.153]
3228 * hkey [I] Handle to key to query
3229 * lpszClass [O] Buffer for class string
3230 * lpcchClass [O] Size of class string buffer
3231 * lpdwReserved [I] Reserved
3232 * lpcSubKeys [I] Buffer for number of subkeys
3233 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3234 * lpcchMaxClass [O] Buffer for longest class string length
3235 * lpcValues [O] Buffer for number of value entries
3236 * lpcchMaxValueName [O] Buffer for longest value name length
3237 * lpccbMaxValueData [O] Buffer for longest value data length
3238 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3240 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3241 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3242 * lpcchClass is NULL
3243 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3244 * (it's hard to test validity, so test !NULL instead)
3246 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3247 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3248 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3249 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3250 LPDWORD lpcchMaxValueName
,
3251 LPDWORD lpccbMaxValueData
,
3252 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3254 LPKEYSTRUCT lpkey
,lpxkey
;
3255 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3258 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3259 lpkey
= lookup_hkey(hkey
);
3261 return ERROR_INVALID_HANDLE
;
3263 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3264 return ERROR_INVALID_PARAMETER
;
3266 /* either lpcchClass is valid or this is win95 and lpcchClass
3269 DWORD classLen
= lstrlenW(lpkey
->class);
3271 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3272 *lpcchClass
=classLen
+1;
3273 return ERROR_MORE_DATA
;
3276 *lpcchClass
=classLen
;
3277 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3285 *lpcchClass
= lstrlenW(lpkey
->class);
3287 lpxkey
=lpkey
->nextsub
;
3288 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3291 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3292 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3293 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3294 maxclass
=lstrlenW(lpxkey
->class);
3295 lpxkey
=lpxkey
->next
;
3297 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3298 LPKEYVALUE val
=lpkey
->values
+i
;
3300 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3301 maxvname
=lstrlenW(val
->name
);
3302 if (val
->len
>maxvdata
)
3305 if (!maxclass
) maxclass
= 1;
3306 if (!maxvname
) maxvname
= 1;
3308 *lpcValues
= lpkey
->nrofvalues
;
3310 *lpcSubKeys
= nrofkeys
;
3312 *lpcchMaxSubkey
= maxsubkey
;
3314 *lpcchMaxClass
= maxclass
;
3315 if (lpcchMaxValueName
)
3316 *lpcchMaxValueName
= maxvname
;
3317 if (lpccbMaxValueData
)
3318 *lpccbMaxValueData
= maxvdata
;
3319 return ERROR_SUCCESS
;
3323 /******************************************************************************
3324 * RegQueryInfoKey32A [ADVAPI32.152]
3326 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3327 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3328 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3329 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3330 LPDWORD lpccbMaxValueData
,
3331 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3333 LPWSTR lpszClassW
= NULL
;
3336 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3339 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3340 } else if (VERSION_GetVersion() == WIN95
) {
3341 /* win95 allows lpcchClass to be null */
3342 /* we don't know how big lpszClass is, would
3343 MAX_PATHNAME_LEN be the correct default? */
3344 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3349 ret
=RegQueryInfoKeyW(
3360 lpcbSecurityDescriptor
,
3363 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3364 lstrcpyWtoA(lpszClass
,lpszClassW
);
3371 /******************************************************************************
3372 * RegConnectRegistry32W [ADVAPI32.128]
3375 * lpMachineName [I] Address of name of remote computer
3376 * hHey [I] Predefined registry handle
3377 * phkResult [I] Address of buffer for remote registry handle
3379 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3382 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3384 if (!lpMachineName
|| !*lpMachineName
) {
3385 /* Use the local machine name */
3386 return RegOpenKey16( hKey
, "", phkResult
);
3389 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3390 return ERROR_BAD_NETPATH
;
3394 /******************************************************************************
3395 * RegConnectRegistry32A [ADVAPI32.127]
3397 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3400 LPWSTR machineW
= strdupA2W(machine
);
3401 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3407 /******************************************************************************
3408 * RegGetKeySecurity [ADVAPI32.144]
3409 * Retrieves a copy of security descriptor protecting the registry key
3412 * hkey [I] Open handle of key to set
3413 * SecurityInformation [I] Descriptor contents
3414 * pSecurityDescriptor [O] Address of descriptor for key
3415 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3418 * Success: ERROR_SUCCESS
3419 * Failure: Error code
3421 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3422 SECURITY_INFORMATION SecurityInformation
,
3423 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3424 LPDWORD lpcbSecurityDescriptor
)
3428 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3429 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3431 lpkey
= lookup_hkey( hkey
);
3433 return ERROR_INVALID_HANDLE
;
3435 /* FIXME: Check for valid SecurityInformation values */
3437 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3438 return ERROR_INSUFFICIENT_BUFFER
;
3440 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3441 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3443 return ERROR_SUCCESS
;
3447 /******************************************************************************
3448 * RegLoadKey32W [ADVAPI32.???]
3451 * hkey [I] Handle of open key
3452 * lpszSubKey [I] Address of name of subkey
3453 * lpszFile [I] Address of filename for registry information
3455 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3458 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3460 /* Do this check before the hkey check */
3461 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3462 return ERROR_INVALID_PARAMETER
;
3464 lpkey
= lookup_hkey( hkey
);
3466 return ERROR_INVALID_HANDLE
;
3468 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3469 debugstr_w(lpszFile
));
3471 return ERROR_SUCCESS
;
3475 /******************************************************************************
3476 * RegLoadKey32A [ADVAPI32.???]
3478 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3481 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3482 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3483 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3484 if(lpszFileW
) free(lpszFileW
);
3485 if(lpszSubKeyW
) free(lpszSubKeyW
);
3490 /******************************************************************************
3491 * RegNotifyChangeKeyValue [ADVAPI32.???]
3494 * hkey [I] Handle of key to watch
3495 * fWatchSubTree [I] Flag for subkey notification
3496 * fdwNotifyFilter [I] Changes to be reported
3497 * hEvent [I] Handle of signaled event
3498 * fAsync [I] Flag for asynchronous reporting
3500 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3501 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3505 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3508 lpkey
= lookup_hkey( hkey
);
3510 return ERROR_INVALID_HANDLE
;
3512 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3515 return ERROR_SUCCESS
;
3519 /******************************************************************************
3520 * RegUnLoadKey32W [ADVAPI32.173]
3523 * hkey [I] Handle of open key
3524 * lpSubKey [I] Address of name of subkey to unload
3526 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3528 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3529 return ERROR_SUCCESS
;
3533 /******************************************************************************
3534 * RegUnLoadKey32A [ADVAPI32.172]
3536 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3539 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3540 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3541 if(lpSubKeyW
) free(lpSubKeyW
);
3546 /******************************************************************************
3547 * RegSetKeySecurity [ADVAPI32.167]
3550 * hkey [I] Open handle of key to set
3551 * SecurityInfo [I] Descriptor contents
3552 * pSecurityDesc [I] Address of descriptor for key
3554 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3555 PSECURITY_DESCRIPTOR pSecurityDesc
)
3559 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3561 /* It seems to perform this check before the hkey check */
3562 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3563 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3564 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3565 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3568 return ERROR_INVALID_PARAMETER
;
3571 return ERROR_INVALID_PARAMETER
;
3573 lpkey
= lookup_hkey( hkey
);
3575 return ERROR_INVALID_HANDLE
;
3577 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3579 return ERROR_SUCCESS
;
3583 /******************************************************************************
3584 * RegSaveKey32W [ADVAPI32.166]
3587 * hkey [I] Handle of key where save begins
3588 * lpFile [I] Address of filename to save to
3589 * sa [I] Address of security structure
3591 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3592 LPSECURITY_ATTRIBUTES sa
)
3596 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3598 /* It appears to do this check before the hkey check */
3599 if (!lpFile
|| !*lpFile
)
3600 return ERROR_INVALID_PARAMETER
;
3602 lpkey
= lookup_hkey( hkey
);
3604 return ERROR_INVALID_HANDLE
;
3606 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3608 return ERROR_SUCCESS
;
3612 /******************************************************************************
3613 * RegSaveKey32A [ADVAPI32.165]
3615 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3616 LPSECURITY_ATTRIBUTES sa
)
3619 LPWSTR lpFileW
= strdupA2W(lpFile
);
3620 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3626 /******************************************************************************
3627 * RegRestoreKey32W [ADVAPI32.164]
3630 * hkey [I] Handle of key where restore begins
3631 * lpFile [I] Address of filename containing saved tree
3632 * dwFlags [I] Optional flags
3634 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3638 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3640 /* It seems to do this check before the hkey check */
3641 if (!lpFile
|| !*lpFile
)
3642 return ERROR_INVALID_PARAMETER
;
3644 lpkey
= lookup_hkey( hkey
);
3646 return ERROR_INVALID_HANDLE
;
3648 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3650 /* Check for file existence */
3652 return ERROR_SUCCESS
;
3656 /******************************************************************************
3657 * RegRestoreKey32A [ADVAPI32.163]
3659 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3662 LPWSTR lpFileW
= strdupA2W(lpFile
);
3663 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3664 if(lpFileW
) free(lpFileW
);
3669 /******************************************************************************
3670 * RegReplaceKey32W [ADVAPI32.162]
3673 * hkey [I] Handle of open key
3674 * lpSubKey [I] Address of name of subkey
3675 * lpNewFile [I] Address of filename for file with new data
3676 * lpOldFile [I] Address of filename for backup file
3678 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3683 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3684 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3686 lpkey
= lookup_hkey( hkey
);
3688 return ERROR_INVALID_HANDLE
;
3690 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3691 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3693 return ERROR_SUCCESS
;
3697 /******************************************************************************
3698 * RegReplaceKey32A [ADVAPI32.161]
3700 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3704 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3705 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3706 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3707 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);