4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
40 #include "debugtools.h"
44 #include "winversion.h"
46 DECLARE_DEBUG_CHANNEL(reg
)
47 DECLARE_DEBUG_CHANNEL(string
)
49 static void REGISTRY_Init(void);
50 /* FIXME: following defines should be configured global ... */
52 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
53 #define WINE_PREFIX "/.wine"
54 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
55 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
57 /* relative in ~user/.wine/ : */
58 #define SAVE_CURRENT_USER "user.reg"
59 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
60 #define SAVE_LOCAL_MACHINE "system.reg"
62 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
63 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
65 /* one value of a key */
66 typedef struct tagKEYVALUE
68 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
69 DWORD type
; /* type of value */
70 DWORD len
; /* length of data in BYTEs */
71 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
72 LPBYTE data
; /* content, may be strings, binaries, etc. */
73 } KEYVALUE
,*LPKEYVALUE
;
76 typedef struct tagKEYSTRUCT
78 LPWSTR keyname
; /* name of THIS key (UNICODE) */
79 DWORD flags
; /* flags. */
82 DWORD nrofvalues
; /* nr of values in THIS key */
83 LPKEYVALUE values
; /* values in THIS key */
84 /* key management pointers */
85 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
86 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
87 } KEYSTRUCT
, *LPKEYSTRUCT
;
90 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
91 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
92 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
93 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
95 /* dynamic, not saved */
96 static KEYSTRUCT
*key_performance_data
=NULL
;
97 static KEYSTRUCT
*key_current_config
=NULL
;
98 static KEYSTRUCT
*key_dyn_data
=NULL
;
100 /* what valuetypes do we need to convert? */
101 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
104 static struct openhandle
{
109 static int nrofopenhandles
=0;
110 /* Starts after 1 because 0,1 are reserved for Win16 */
111 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
112 HKEYs for remote registry access */
113 static int currenthandle
=2;
118 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
119 * If so, can we remove them?
121 * No, the memory handling functions are called very often in here,
122 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
123 * loading 100 times slower. -MM
125 static LPWSTR
strdupA2W(LPCSTR src
)
128 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
129 lstrcpyAtoW(dest
,src
);
135 static LPWSTR
strdupW(LPCWSTR a
) {
140 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
141 b
=(LPWSTR
)xmalloc(len
);
148 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
151 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
153 lstrcpynAtoW(dest
,src
,nchars
+1);
158 * we need to convert A to W with '\0' in strings (MULTI_SZ)
161 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
164 TRACE_(reg
)("\"%s\" %i\n",src
, n
);
166 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
170 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
173 TRACE_(string
)("L\"%s\" %i\n",debugstr_w(src
), n
);
175 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
180 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
182 if (TRACE_ON(reg
) && lpbData
)
188 TRACE_(reg
)(" Value %s, Data(sz)=%s\n",
189 debugstr_w(key
->name
),
190 debugstr_w((LPCWSTR
)lpbData
));
194 TRACE_(reg
)(" Value %s, Data(dword)=0x%08lx\n",
195 debugstr_w(key
->name
),
202 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
205 TRACE_(reg
)(" Value %s, MULTI_SZ(%i=%s)\n",
206 debugstr_w(key
->name
),
210 ptr
+= lstrlenW(ptr
)+1;
217 char szTemp
[100]; /* 3*32 + 3 + 1 */
219 for ( i
= 0; i
< key
->len
; i
++)
221 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
224 sprintf (&(szTemp
[i
*3+3]),"...");
228 TRACE_(reg
)(" Value %s, Data(raw)=(%s)\n",
229 debugstr_w(key
->name
),
237 /******************************************************************************
238 * is_standard_hkey [Internal]
239 * Determines if a hkey is a standard key
241 static BOOL
is_standard_hkey( HKEY hkey
)
246 case HKEY_CLASSES_ROOT
:
247 case HKEY_CURRENT_CONFIG
:
248 case HKEY_CURRENT_USER
:
249 case HKEY_LOCAL_MACHINE
:
251 case HKEY_PERFORMANCE_DATA
:
259 /******************************************************************************
260 * add_handle [Internal]
262 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
266 TRACE_(reg
)("(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
267 /* Check for duplicates */
268 for (i
=0;i
<nrofopenhandles
;i
++) {
269 if (openhandles
[i
].lpkey
==lpkey
) {
270 /* This is not really an error - the user is allowed to create
271 two (or more) handles to the same key */
272 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
274 if (openhandles
[i
].hkey
==hkey
) {
275 WARN_(reg
)("Adding handle %x twice\n",hkey
);
278 openhandles
=xrealloc( openhandles
,
279 sizeof(struct openhandle
)*(nrofopenhandles
+1));
281 openhandles
[i
].lpkey
= lpkey
;
282 openhandles
[i
].hkey
= hkey
;
283 openhandles
[i
].accessmask
= accessmask
;
288 /******************************************************************************
289 * get_handle [Internal]
292 * Success: Pointer to key
295 static LPKEYSTRUCT
get_handle( HKEY hkey
)
299 for (i
=0; i
<nrofopenhandles
; i
++)
300 if (openhandles
[i
].hkey
== hkey
)
301 return openhandles
[i
].lpkey
;
302 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
307 /******************************************************************************
308 * remove_handle [Internal]
311 * hkey [I] Handle of key to remove
314 * Success: ERROR_SUCCESS
315 * Failure: ERROR_INVALID_HANDLE
317 static DWORD
remove_handle( HKEY hkey
)
321 for (i
=0;i
<nrofopenhandles
;i
++)
322 if (openhandles
[i
].hkey
==hkey
)
325 if (i
== nrofopenhandles
) {
326 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
327 return ERROR_INVALID_HANDLE
;
330 memcpy( openhandles
+i
,
332 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
334 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
336 return ERROR_SUCCESS
;
339 /******************************************************************************
340 * lookup_hkey [Internal]
342 * Just as the name says. Creates the root keys on demand, so we can call the
343 * Reg* functions at any time.
346 * Success: Pointer to key structure
349 #define ADD_ROOT_KEY(xx) \
350 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
351 memset(xx,'\0',sizeof(KEYSTRUCT));\
352 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
354 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
357 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
358 * some programs. Do not remove those cases. -MM
362 case HKEY_CLASSES_ROOT
:
364 if (!key_classes_root
)
368 /* calls lookup_hkey recursively, TWICE */
372 &cl_r_hkey
) != ERROR_SUCCESS
)
374 ERR_(reg
)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
378 key_classes_root
= lookup_hkey(cl_r_hkey
);
380 return key_classes_root
;
383 case HKEY_CURRENT_USER
:
384 if (!key_current_user
) {
385 ADD_ROOT_KEY(key_current_user
);
387 return key_current_user
;
389 case HKEY_LOCAL_MACHINE
:
390 if (!key_local_machine
) {
391 ADD_ROOT_KEY(key_local_machine
);
394 return key_local_machine
;
398 ADD_ROOT_KEY(key_users
);
402 case HKEY_PERFORMANCE_DATA
:
403 if (!key_performance_data
) {
404 ADD_ROOT_KEY(key_performance_data
);
406 return key_performance_data
;
410 ADD_ROOT_KEY(key_dyn_data
);
414 case HKEY_CURRENT_CONFIG
:
415 if (!key_current_config
) {
416 ADD_ROOT_KEY(key_current_config
);
418 return key_current_config
;
421 return get_handle(hkey
);
427 /* so we don't accidently access them ... */
428 #define key_current_config NULL NULL
429 #define key_current_user NULL NULL
430 #define key_users NULL NULL
431 #define key_local_machine NULL NULL
432 #define key_classes_root NULL NULL
433 #define key_dyn_data NULL NULL
434 #define key_performance_data NULL NULL
436 /******************************************************************************
437 * split_keypath [Internal]
438 * splits the unicode string 'wp' into an array of strings.
439 * the array is allocated by this function.
440 * Free the array using FREE_KEY_PATH
443 * wp [I] String to split up
444 * wpv [O] Array of pointers to strings
445 * wpc [O] Number of components
447 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
452 TRACE_(reg
)("(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
454 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
456 /* We know we have at least one substring */
459 /* Replace each backslash with NULL, and increment the count */
460 for (i
=0;ws
[i
];i
++) {
469 /* Allocate the space for the array of pointers, leaving room for the
471 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
474 /* Assign each pointer to the appropriate character in the string */
479 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
484 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
489 /******************************************************************************
490 * REGISTRY_Init [Internal]
491 * Registry initialisation, allocates some default keys.
493 static void REGISTRY_Init(void) {
497 TRACE_(reg
)("(void)\n");
499 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
502 /* This was an Open, but since it is called before the real registries
503 are loaded, it was changed to a Create - MTB 980507*/
504 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
505 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
508 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
512 * string RegisteredOwner
513 * string RegisteredOrganization
516 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
521 if (-1!=gethostname(buf
,200)) {
522 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
523 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
529 /************************ SAVE Registry Function ****************************/
531 #define REGISTRY_SAVE_VERSION 0x00000001
533 /* Registry saveformat:
534 * If you change it, increase above number by 1, which will flush
535 * old registry database files.
538 * "WINE REGISTRY Version %d"
542 * valuename=lastmodified,type,data
546 * keyname,valuename,stringdata:
547 * the usual ascii characters from 0x00-0xff (well, not 0x00)
548 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
549 * ( "=\\\t" escaped in \uXXXX form.)
553 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
555 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
556 * SaveOnlyUpdatedKeys=yes
559 /******************************************************************************
560 * _save_check_tainted [Internal]
562 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
568 if (lpkey
->flags
& REG_OPTION_TAINTED
)
573 if (_save_check_tainted(lpkey
->nextsub
)) {
574 lpkey
->flags
|= REG_OPTION_TAINTED
;
582 /******************************************************************************
583 * _save_USTRING [Internal]
585 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
599 if (escapeeq
&& *s
=='=')
602 fputc(*s
,F
); /* if \\ then put it twice. */
604 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
611 /******************************************************************************
612 * _savesubkey [Internal]
615 * REG_MULTI_SZ is handled as binary (like in win95) (js)
617 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
624 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
625 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
627 for (tabs
=level
;tabs
--;)
629 _save_USTRING(F
,lpxkey
->keyname
,1);
631 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
632 LPKEYVALUE val
=lpxkey
->values
+i
;
634 for (tabs
=level
+1;tabs
--;)
636 _save_USTRING(F
,val
->name
,0);
638 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
639 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
640 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
642 for (j
=0;j
<val
->len
;j
++)
643 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
646 /* descend recursively */
647 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
656 /******************************************************************************
657 * _savesubreg [Internal]
659 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
661 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
662 _save_check_tainted(lpkey
->nextsub
);
663 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
667 /******************************************************************************
668 * _savereg [Internal]
670 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
676 WARN_(reg
)("Couldn't open %s for writing: %s\n",
681 if (!_savesubreg(F
,lpkey
,all
)) {
684 WARN_(reg
)("Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
692 /******************************************************************************
693 * SHELL_SaveRegistry [Internal]
695 void SHELL_SaveRegistry( void )
697 char *fn
, *home
, *tmp
;
704 TRACE_(reg
)("(void)\n");
707 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
716 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
721 &len
)) || (type
!=REG_SZ
))
728 if (lstrcmpiA(buf
,"yes")) all
=1;
730 if (!(home
= getenv( "HOME" )))
732 WARN_(reg
)("Failed to get homedirectory of UID %d.\n",getuid());
736 * Save HKEY_CURRENT_USER
737 * Try first saving according to the defined location in .winerc
739 fn
= xmalloc( MAX_PATHNAME_LEN
);
740 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "", fn
, MAX_PATHNAME_LEN
- 1))
742 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
747 if (usedCfgUser
!= 1)
749 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
750 strlen(SAVE_CURRENT_USER
) + 2 );
752 strcat(fn
,WINE_PREFIX
);
754 /* create the directory. don't care about errorcodes. */
755 mkdir(fn
,0755); /* drwxr-xr-x */
756 strcat(fn
,"/"SAVE_CURRENT_USER
);
758 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
762 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
763 if (-1==rename(tmp
,fn
)) {
764 perror("rename tmp registry");
773 * Save HKEY_LOCAL_MACHINE
774 * Try first saving according to the defined location in .winerc
776 fn
= xmalloc ( MAX_PATHNAME_LEN
);
777 if (PROFILE_GetWineIniString ( "Registry", "LocalMachineFileName", "", fn
,
778 MAX_PATHNAME_LEN
- 1))
780 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
787 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_MACHINE
)+2);
789 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
791 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
795 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
796 if (-1==rename(tmp
,fn
)) {
797 perror("rename tmp registry");
808 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
811 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
813 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
814 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
815 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
816 if (-1==rename(tmp
,fn
)) {
817 perror("rename tmp registry");
826 /************************ LOAD Registry Function ****************************/
830 /******************************************************************************
831 * _find_or_add_key [Internal]
833 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
835 LPKEYSTRUCT lpxkey
,*lplpkey
;
837 if ((!keyname
) || (keyname
[0]==0)) {
841 lplpkey
= &(lpkey
->nextsub
);
844 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
845 !lstrcmpiW(lpxkey
->keyname
,keyname
)
848 lplpkey
= &(lpxkey
->next
);
852 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
854 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
855 lpxkey
->keyname
= keyname
;
861 /******************************************************************************
862 * _find_or_add_value [Internal]
864 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
865 LPBYTE data
, DWORD len
, DWORD lastmodified
)
870 if (name
&& !*name
) {/* empty string equals default (NULL) value */
875 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
881 if ( val
->name
!=NULL
&&
882 val
->name
[0]==name
[0] &&
883 !lstrcmpiW(val
->name
,name
)
888 if (i
==lpkey
->nrofvalues
) {
889 lpkey
->values
= xrealloc(
891 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
894 memset(val
,'\0',sizeof(KEYVALUE
));
900 if (val
->lastmodified
<lastmodified
) {
901 val
->lastmodified
=lastmodified
;
904 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && !data
){
906 data
=xmalloc(sizeof(WCHAR
));
907 memset(data
,0,sizeof(WCHAR
));
920 /******************************************************************************
921 * _wine_read_line [Internal]
923 * reads a line including dynamically enlarging the readbuffer and throwing
926 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
936 s
=fgets(curread
,mylen
,F
);
939 if (NULL
==(s
=strchr(curread
,'\n'))) {
940 /* buffer wasn't large enough */
941 curoff
= strlen(*buf
);
942 *buf
= xrealloc(*buf
,*len
*2);
943 curread
= *buf
+ curoff
;
944 mylen
= *len
; /* we filled up the buffer and
945 * got new '*len' bytes to fill
953 /* throw away comments */
954 if (**buf
=='#' || **buf
==';') {
959 if (s
) /* got end of line */
966 /******************************************************************************
967 * _wine_read_USTRING [Internal]
969 * converts a char* into a UNICODE string (up to a special char)
970 * and returns the position exactly after that string
972 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
977 /* read up to "=" or "\0" or "\n" */
980 /* empty string is the win3.1 default value(NULL)*/
984 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
986 while (*s
&& (*s
!='\n') && (*s
!='=')) {
988 *ws
++=*((unsigned char*)s
++);
992 /* Dangling \ ... may only happen if a registry
993 * write was short. FIXME: What do to?
1003 WARN_(reg
)("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1011 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1012 if (!sscanf(xbuf
,"%x",&wc
))
1013 WARN_(reg
)("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1015 *ws
++ =(unsigned short)wc
;
1022 *str
= strdupW(*str
);
1030 /******************************************************************************
1031 * _wine_loadsubkey [Internal]
1034 * It seems like this is returning a boolean. Should it?
1040 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1041 int *buflen
, DWORD optflag
)
1048 TRACE_(reg
)("(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1051 lpkey
->flags
|= optflag
;
1053 /* Good. We already got a line here ... so parse it */
1063 WARN_(reg
)("Got a subhierarchy without resp. key?\n");
1066 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1070 /* let the caller handle this line */
1071 if (i
<level
|| **buf
=='\0')
1074 /* it can be: a value or a keyname. Parse the name first */
1075 s
=_wine_read_USTRING(s
,&name
);
1077 /* switch() default: hack to avoid gotos */
1081 lpxkey
=_find_or_add_key(lpkey
,name
);
1084 int len
,lastmodified
,type
;
1087 WARN_(reg
)("Unexpected character: %c\n",*s
);
1091 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1092 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
1096 s
=strchr(s
,',');s
++;
1097 s
=strchr(s
,',');s
++;
1098 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1099 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1101 len
= lstrlenW((LPWSTR
)data
)*2+2;
1106 data
= (LPBYTE
)xmalloc(len
+1);
1107 for (i
=0;i
<len
;i
++) {
1109 if (*s
>='0' && *s
<='9')
1110 data
[i
]=(*s
-'0')<<4;
1111 if (*s
>='a' && *s
<='f')
1112 data
[i
]=(*s
-'a'+'\xa')<<4;
1113 if (*s
>='A' && *s
<='F')
1114 data
[i
]=(*s
-'A'+'\xa')<<4;
1116 if (*s
>='0' && *s
<='9')
1118 if (*s
>='a' && *s
<='f')
1119 data
[i
]|=*s
-'a'+'\xa';
1120 if (*s
>='A' && *s
<='F')
1121 data
[i
]|=*s
-'A'+'\xa';
1125 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1128 /* read the next line */
1129 if (!_wine_read_line(F
,buf
,buflen
))
1136 /******************************************************************************
1137 * _wine_loadsubreg [Internal]
1139 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1145 buf
=xmalloc(10);buflen
=10;
1146 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1150 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1154 if (ver
!=REGISTRY_SAVE_VERSION
) {
1155 TRACE_(reg
)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1159 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1163 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1172 /******************************************************************************
1173 * _wine_loadreg [Internal]
1175 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1179 TRACE_(reg
)("(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1183 WARN_(reg
)("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1186 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1194 /******************************************************************************
1195 * _flush_registry [Internal]
1197 * This function allow to flush section of the internal registry. It is mainly
1198 * implements to fix a problem with the global HKU and the local HKU.
1199 * Those two files are read to build the HKU\.Default branch to finaly copy
1200 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1201 * all the global HKU are saved onto the user's personal version of HKU hive.
1205 /* Forward declaration of recusive agent */
1206 static void _flush_reg(LPKEYSTRUCT from
);
1208 static void _flush_registry( LPKEYSTRUCT from
)
1210 /* make sure we have something... */
1214 /* Launch the recusive agent on sub branches */
1215 _flush_reg( from
->nextsub
);
1216 _flush_reg( from
->next
);
1218 /* Initialize pointers */
1219 from
->nextsub
= NULL
;
1222 static void _flush_reg( LPKEYSTRUCT from
)
1226 /* make sure we have something... */
1231 * do the same for the child keys
1233 if (from
->nextsub
!= NULL
)
1234 _flush_reg(from
->nextsub
);
1237 * do the same for the sibling keys
1239 if (from
->next
!= NULL
)
1240 _flush_reg(from
->next
);
1243 * iterate through this key's values and delete them
1245 for (j
=0;j
<from
->nrofvalues
;j
++)
1247 free( (from
->values
+j
)->name
);
1248 free( (from
->values
+j
)->data
);
1252 * free the structure
1259 /******************************************************************************
1260 * _copy_registry [Internal]
1262 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1270 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1272 for (j
=0;j
<from
->nrofvalues
;j
++) {
1276 valfrom
= from
->values
+j
;
1278 if (name
) name
=strdupW(name
);
1279 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1280 memcpy(data
,valfrom
->data
,valfrom
->len
);
1288 valfrom
->lastmodified
1291 _copy_registry(from
,lpxkey
);
1297 /* WINDOWS 95 REGISTRY LOADER */
1299 * Structure of a win95 registry database.
1301 * 0 : "CREG" - magic
1303 * 8 : DWORD offset_of_RGDB_part
1304 * 0C..0F: ? (someone fill in please)
1305 * 10: WORD number of RGDB blocks
1307 * 14: WORD always 0000?
1308 * 16: WORD always 0001?
1309 * 18..1F: ? (someone fill in please)
1313 * 0 : "RGKN" - magic
1314 * 4 : DWORD offset to first RGDB section
1315 * 8 : DWORD offset to the root record
1316 * C..0x1B: ? (fill in)
1317 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1319 * Disk Key Entry Structure:
1320 * 00: DWORD - Free entry indicator(?)
1321 * 04: DWORD - Hash = sum of bytes of keyname
1322 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1323 * 0C: DWORD - disk address of PreviousLevel Key.
1324 * 10: DWORD - disk address of Next Sublevel Key.
1325 * 14: DWORD - disk address of Next Key (on same level).
1326 * DKEP>18: WORD - Nr, Low Significant part.
1327 * 1A: WORD - Nr, High Significant part.
1329 * The disk address always points to the nr part of the previous key entry
1330 * of the referenced key. Don't ask me why, or even if I got this correct
1331 * from staring at 1kg of hexdumps. (DKEP)
1333 * The High significant part of the structure seems to equal the number
1334 * of the RGDB section. The low significant part is a unique ID within
1337 * There are two minor corrections to the position of that structure.
1338 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1339 * the DKE reread from there.
1340 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1341 * CPS - I have not experienced the above phenomenon in my registry files
1344 * 00: "RGDB" - magic
1345 * 04: DWORD offset to next RGDB section
1347 * 0C: WORD always 000d?
1348 * 0E: WORD RGDB block number
1349 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1351 * 20.....: disk keys
1354 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1355 * 08: WORD nrLS - low significant part of NR
1356 * 0A: WORD nrHS - high significant part of NR
1357 * 0C: DWORD bytesused - bytes used in this structure.
1358 * 10: WORD name_len - length of name in bytes. without \0
1359 * 12: WORD nr_of_values - number of values.
1360 * 14: char name[name_len] - name string. No \0.
1361 * 14+name_len: disk values
1362 * nextkeyoffset: ... next disk key
1365 * 00: DWORD type - value type (hmm, could be WORD too)
1366 * 04: DWORD - unknown, usually 0
1367 * 08: WORD namelen - length of Name. 0 means name=NULL
1368 * 0C: WORD datalen - length of Data.
1369 * 10: char name[namelen] - name, no \0
1370 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1371 * 10+namelen+datalen: next values or disk key
1373 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1374 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1375 * structure) and reading another RGDB_section.
1376 * repeat until end of file.
1378 * An interesting relationship exists in RGDB_section. The value at offset
1379 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1380 * idea at the moment what this means. (Kevin Cozens)
1382 * FIXME: this description needs some serious help, yes.
1385 struct _w95keyvalue
{
1387 unsigned short datalen
;
1389 unsigned char *data
;
1397 struct _w95keyvalue
*values
;
1398 struct _w95key
*prevlvl
;
1399 struct _w95key
*nextsub
;
1400 struct _w95key
*next
;
1414 /******************************************************************************
1415 * _w95_processKey [Internal]
1417 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1418 int nrLS
, int nrMS
, struct _w95_info
*info
)
1421 /* Disk Key Header structure (RGDB part) */
1423 unsigned long nextkeyoff
;
1424 unsigned short nrLS
;
1425 unsigned short nrMS
;
1426 unsigned long bytesused
;
1427 unsigned short keynamelen
;
1428 unsigned short values
;
1431 /* disk key values or nothing */
1433 /* Disk Key Value structure */
1437 unsigned short valnamelen
;
1438 unsigned short valdatalen
;
1439 /* valname, valdata */
1445 char *rgdbdata
= info
->rgdbbuffer
;
1446 int nbytes
= info
->rgdbsize
;
1447 char *curdata
= rgdbdata
;
1448 char *end
= rgdbdata
+ nbytes
;
1450 char *next
= rgdbdata
;
1456 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1458 memcpy(&off_next_rgdb
,curdata
+4,4);
1459 next
= curdata
+ off_next_rgdb
;
1460 nrgdb
= (int) *((short *)curdata
+ 7);
1462 } while (nrgdb
!= nrMS
&& (next
< end
));
1464 /* curdata now points to the start of the right RGDB section */
1467 #define XREAD(whereto,len) \
1468 if ((curdata + len) <= end) {\
1469 memcpy(whereto,curdata,len);\
1474 while (curdata
< next
) {
1475 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1477 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1478 if (xdkh
->nrLS
== nrLS
) {
1479 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1480 curdata
+= sizeof(dkh
);
1483 curdata
+= xdkh
->nextkeyoff
;
1486 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1488 if (nrgdb
!= dkh
.nrMS
)
1491 assert((dkh
.keynamelen
<2) || curdata
[0]);
1492 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1493 curdata
+= dkh
.keynamelen
;
1495 for (i
=0;i
< dkh
.values
; i
++) {
1501 XREAD(&dkv
,sizeof(dkv
));
1503 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1504 curdata
+= dkv
.valnamelen
;
1506 if ((1 << dkv
.type
) & UNICONVMASK
) {
1507 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1508 len
= 2*(dkv
.valdatalen
+ 1);
1510 /* I don't think we want to NULL terminate all data */
1511 data
= xmalloc(dkv
.valdatalen
);
1512 memcpy (data
, curdata
, dkv
.valdatalen
);
1513 len
= dkv
.valdatalen
;
1516 curdata
+= dkv
.valdatalen
;
1530 /******************************************************************************
1531 * _w95_walkrgkn [Internal]
1533 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1534 struct _w95_info
*info
)
1537 /* Disk Key Entry structure (RGKN part) */
1541 unsigned long x3
;/*usually 0xFFFFFFFF */
1542 unsigned long prevlvl
;
1543 unsigned long nextsub
;
1545 unsigned short nrLS
;
1546 unsigned short nrMS
;
1547 } *dke
= (struct dke
*)off
;
1551 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1554 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1555 /* XXX <-- This is a hack*/
1560 if (dke
->nextsub
!= -1 &&
1561 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1562 && (dke
->nextsub
> 0x20)) {
1564 _w95_walkrgkn(lpxkey
,
1565 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1569 if (dke
->next
!= -1 &&
1570 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1571 (dke
->next
> 0x20)) {
1572 _w95_walkrgkn(prevkey
,
1573 info
->rgknbuffer
+ dke
->next
- 0x20,
1581 /******************************************************************************
1582 * _w95_loadreg [Internal]
1584 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1588 unsigned long where
,version
,rgdbsection
,end
;
1589 struct _w95_info info
;
1591 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1593 TRACE_(reg
)("Loading Win95 registry database '%s'\n",fn
);
1594 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1595 if (hfd
==HFILE_ERROR
)
1598 if (4!=_lread(hfd
,magic
,4))
1600 if (strcmp(magic
,"CREG")) {
1601 WARN_(reg
)("%s is not a w95 registry.\n",fn
);
1604 if (4!=_lread(hfd
,&version
,4))
1606 if (4!=_lread(hfd
,&rgdbsection
,4))
1608 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1610 if (4!=_lread(hfd
,magic
,4))
1612 if (strcmp(magic
,"RGKN")) {
1613 WARN_(reg
)("second IFF header not RGKN, but %s\n", magic
);
1617 /* STEP 1: Keylink structures */
1618 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1623 info
.rgknsize
= end
- where
;
1624 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1625 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1628 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1631 end
= hfdinfo
.nFileSizeLow
;
1632 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1634 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1637 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1638 info
.rgdbsize
= end
- rgdbsection
;
1640 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1644 _w95_walkrgkn(lpkey
, NULL
, &info
);
1646 free (info
.rgdbbuffer
);
1647 free (info
.rgknbuffer
);
1651 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1654 reghack - windows 3.11 registry data format demo program.
1656 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1657 a combined hash table and tree description, and finally a text table.
1659 The header is obvious from the struct header. The taboff1 and taboff2
1660 fields are always 0x20, and their usage is unknown.
1662 The 8-byte entry table has various entry types.
1664 tabent[0] is a root index. The second word has the index of the root of
1666 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1667 the index of the key/value that has that hash. Data with the same
1668 hash value are on a circular list. The other three words in the
1669 hash entry are always zero.
1670 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1671 entry: dirent and keyent/valent. They are identified by context.
1672 tabent[freeidx] is the first free entry. The first word in a free entry
1673 is the index of the next free entry. The last has 0 as a link.
1674 The other three words in the free list are probably irrelevant.
1676 Entries in text table are preceeded by a word at offset-2. This word
1677 has the value (2*index)+1, where index is the referring keyent/valent
1678 entry in the table. I have no suggestion for the 2* and the +1.
1679 Following the word, there are N bytes of data, as per the keyent/valent
1680 entry length. The offset of the keyent/valent entry is from the start
1681 of the text table to the first data byte.
1683 This information is not available from Microsoft. The data format is
1684 deduced from the reg.dat file by me. Mistakes may
1685 have been made. I claim no rights and give no guarantees for this program.
1687 Tor Sjøwall, tor@sn.no
1690 /* reg.dat header format */
1691 struct _w31_header
{
1692 char cookie
[8]; /* 'SHCC3.10' */
1693 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1694 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1695 unsigned long tabcnt
; /* number of entries in index table */
1696 unsigned long textoff
; /* offset of text part */
1697 unsigned long textsize
; /* byte size of text part */
1698 unsigned short hashsize
; /* hash size */
1699 unsigned short freeidx
; /* free index */
1702 /* generic format of table entries */
1703 struct _w31_tabent
{
1704 unsigned short w0
, w1
, w2
, w3
;
1707 /* directory tabent: */
1708 struct _w31_dirent
{
1709 unsigned short sibling_idx
; /* table index of sibling dirent */
1710 unsigned short child_idx
; /* table index of child dirent */
1711 unsigned short key_idx
; /* table index of key keyent */
1712 unsigned short value_idx
; /* table index of value valent */
1716 struct _w31_keyent
{
1717 unsigned short hash_idx
; /* hash chain index for string */
1718 unsigned short refcnt
; /* reference count */
1719 unsigned short length
; /* length of string */
1720 unsigned short string_off
; /* offset of string in text table */
1724 struct _w31_valent
{
1725 unsigned short hash_idx
; /* hash chain index for string */
1726 unsigned short refcnt
; /* reference count */
1727 unsigned short length
; /* length of string */
1728 unsigned short string_off
; /* offset of string in text table */
1731 /* recursive helper function to display a directory tree */
1733 __w31_dumptree( unsigned short idx
,
1735 struct _w31_tabent
*tab
,
1736 struct _w31_header
*head
,
1738 time_t lastmodified
,
1741 struct _w31_dirent
*dir
;
1742 struct _w31_keyent
*key
;
1743 struct _w31_valent
*val
;
1744 LPKEYSTRUCT xlpkey
= NULL
;
1746 static char tail
[400];
1749 dir
=(struct _w31_dirent
*)&tab
[idx
];
1752 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1754 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1755 tail
[key
->length
]='\0';
1756 /* all toplevel entries AND the entries in the
1757 * toplevel subdirectory belong to \SOFTWARE\Classes
1759 if (!level
&& !lstrcmpA(tail
,".classes")) {
1760 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1761 idx
=dir
->sibling_idx
;
1764 name
=strdupA2W(tail
);
1766 xlpkey
=_find_or_add_key(lpkey
,name
);
1768 /* only add if leaf node or valued node */
1769 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1770 if (dir
->value_idx
) {
1771 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1772 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1773 tail
[val
->length
]='\0';
1774 value
=strdupA2W(tail
);
1775 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1779 TRACE_(reg
)("strange: no directory key name, idx=%04x\n", idx
);
1781 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1782 idx
=dir
->sibling_idx
;
1787 /******************************************************************************
1788 * _w31_loadreg [Internal]
1790 void _w31_loadreg(void) {
1792 struct _w31_header head
;
1793 struct _w31_tabent
*tab
;
1797 BY_HANDLE_FILE_INFORMATION hfinfo
;
1798 time_t lastmodified
;
1801 TRACE_(reg
)("(void)\n");
1803 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1804 if (hf
==HFILE_ERROR
)
1807 /* read & dump header */
1808 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1809 ERR_(reg
)("reg.dat is too short.\n");
1813 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1814 ERR_(reg
)("reg.dat has bad signature.\n");
1819 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1820 /* read and dump index table */
1822 if (len
!=_lread(hf
,tab
,len
)) {
1823 ERR_(reg
)("couldn't read %d bytes.\n",len
);
1830 txt
= xmalloc(head
.textsize
);
1831 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1832 ERR_(reg
)("couldn't seek to textblock.\n");
1838 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1839 ERR_(reg
)("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1846 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1847 ERR_(reg
)("GetFileInformationByHandle failed?.\n");
1853 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1854 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1855 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1863 /**********************************************************************************
1864 * SHELL_LoadRegistry [Internal]
1866 void SHELL_LoadRegistry( void )
1869 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1872 TRACE_(reg
)("(void)\n");
1874 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1875 HKU
= lookup_hkey(HKEY_USERS
);
1876 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1878 /* Load windows 3.1 entries */
1880 /* Load windows 95 entries */
1881 _w95_loadreg("C:\\system.1st", HKLM
);
1882 _w95_loadreg("system.dat", HKLM
);
1883 _w95_loadreg("user.dat", HKU
);
1886 * Load the global HKU hive directly from /usr/local/etc
1888 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1891 * Load the global machine defaults directly form /usr/local/etc
1893 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1896 * Load the user saved registries
1898 if ((home
= getenv( "HOME" )))
1901 * Load user's personal versions of global HKU/.Default keys
1905 strlen(WINE_PREFIX
)+
1906 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1909 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1910 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1914 * Load HKCU, attempt to get the registry location from the config
1915 * file first, if exist, load and keep going.
1917 fn
= xmalloc( MAX_PATHNAME_LEN
);
1918 if ( PROFILE_GetWineIniString(
1923 MAX_PATHNAME_LEN
- 1))
1925 _wine_loadreg(HKCU
,fn
,0);
1931 strlen(WINE_PREFIX
)+
1932 strlen(SAVE_CURRENT_USER
)+2);
1935 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1936 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
1940 * Load HKLM, attempt to get the registry location from the config
1941 * file first, if exist, load and keep going.
1943 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1944 if ( PROFILE_GetWineIniString(
1946 "LocalMachineFileName",
1949 MAX_PATHNAME_LEN
- 1))
1951 _wine_loadreg(HKLM
, fn
, 0);
1957 strlen(WINE_PREFIX
)+
1958 strlen(SAVE_LOCAL_MACHINE
)+2);
1961 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1962 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
1967 WARN_(reg
)("Failed to get homedirectory of UID %d.\n",getuid());
1971 * Obtain the handle of the HKU\.Default key.
1972 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1974 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1975 lpkey
= lookup_hkey(hkey
);
1977 WARN_(reg
)("Could not create global user default key\n");
1979 _copy_registry(lpkey
, HKCU
);
1984 * Since HKU is built from the global HKU and the local user HKU file we must
1985 * flush the HKU tree we have built at this point otherwise the part brought
1986 * in from the global HKU is saved into the local HKU. To avoid this
1987 * useless dupplication of HKU keys we reread the local HKU key.
1990 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1991 _flush_registry(HKU
);
1993 /* Reload user's local HKU hive */
1996 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
)
1997 + strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
2000 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2002 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2008 * Make sure the update mode is there
2010 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2012 DWORD junk
,type
,len
;
2016 if (( RegQueryValueExA(
2022 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2024 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2032 /********************* API FUNCTIONS ***************************************/
2036 * All functions are stubs to RegOpenKeyEx32W where all the
2040 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2041 * RegOpenKey32W -> RegOpenKeyEx32W
2045 /******************************************************************************
2046 * RegOpenKeyEx32W [ADVAPI32.150]
2047 * Opens the specified key
2049 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2052 * hkey [I] Handle of open key
2053 * lpszSubKey [I] Name of subkey to open
2054 * dwReserved [I] Reserved - must be zero
2055 * samDesired [I] Security access mask
2056 * retkey [O] Address of handle of open key
2059 * Success: ERROR_SUCCESS
2060 * Failure: Error code
2062 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2063 REGSAM samDesired
, LPHKEY retkey
)
2065 LPKEYSTRUCT lpNextKey
,lpxkey
;
2069 TRACE_(reg
)("(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2072 lpNextKey
= lookup_hkey( hkey
);
2074 return ERROR_INVALID_HANDLE
;
2076 if (!lpszSubKey
|| !*lpszSubKey
) {
2077 /* Either NULL or pointer to empty string, so return a new handle
2078 to the original hkey */
2080 add_handle(currenthandle
,lpNextKey
,samDesired
);
2081 *retkey
=currenthandle
;
2082 return ERROR_SUCCESS
;
2085 if (lpszSubKey
[0] == '\\') {
2086 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2087 return ERROR_BAD_PATHNAME
;
2090 split_keypath(lpszSubKey
,&wps
,&wpc
);
2092 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2096 lpxkey
=lpNextKey
->nextsub
;
2098 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2101 lpxkey
=lpxkey
->next
;
2105 TRACE_(reg
)("Could not find subkey %s\n",debugstr_w(wps
[i
]));
2107 return ERROR_FILE_NOT_FOUND
;
2114 add_handle(currenthandle
,lpxkey
,samDesired
);
2115 *retkey
= currenthandle
;
2116 TRACE_(reg
)(" Returning %x\n", currenthandle
);
2118 return ERROR_SUCCESS
;
2122 /******************************************************************************
2123 * RegOpenKeyEx32A [ADVAPI32.149]
2125 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2126 REGSAM samDesired
, LPHKEY retkey
)
2128 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2131 TRACE_(reg
)("(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2133 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2139 /******************************************************************************
2140 * RegOpenKey32W [ADVAPI32.151]
2143 * hkey [I] Handle of open key
2144 * lpszSubKey [I] Address of name of subkey to open
2145 * retkey [O] Address of handle of open key
2148 * Success: ERROR_SUCCESS
2149 * Failure: Error code
2151 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2153 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2154 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2158 /******************************************************************************
2159 * RegOpenKey32A [ADVAPI32.148]
2161 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2164 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2165 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2166 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2172 /******************************************************************************
2173 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2175 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2177 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2178 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2185 * All those functions convert their respective
2186 * arguments and call RegCreateKeyExW at the end.
2188 * We stay away from the Ex functions as long as possible because there are
2189 * differences in the return values
2192 * RegCreateKeyEx32A \
2193 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2197 /******************************************************************************
2198 * RegCreateKeyEx32W [ADVAPI32.131]
2201 * hkey [I] Handle of an open key
2202 * lpszSubKey [I] Address of subkey name
2203 * dwReserved [I] Reserved - must be 0
2204 * lpszClass [I] Address of class string
2205 * fdwOptions [I] Special options flag
2206 * samDesired [I] Desired security access
2207 * lpSecAttribs [I] Address of key security structure
2208 * retkey [O] Address of buffer for opened handle
2209 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2211 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2212 DWORD dwReserved
, LPWSTR lpszClass
,
2213 DWORD fdwOptions
, REGSAM samDesired
,
2214 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2215 LPHKEY retkey
, LPDWORD lpDispos
)
2217 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2221 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2222 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2223 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2225 lpNextKey
= lookup_hkey(hkey
);
2227 return ERROR_INVALID_HANDLE
;
2229 /* Check for valid options */
2230 switch(fdwOptions
) {
2231 case REG_OPTION_NON_VOLATILE
:
2232 case REG_OPTION_VOLATILE
:
2233 case REG_OPTION_BACKUP_RESTORE
:
2236 return ERROR_INVALID_PARAMETER
;
2239 /* Sam has to be a combination of the following */
2241 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2242 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2243 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2244 return ERROR_INVALID_PARAMETER
;
2246 if (!lpszSubKey
|| !*lpszSubKey
) {
2248 add_handle(currenthandle
,lpNextKey
,samDesired
);
2249 *retkey
=currenthandle
;
2250 TRACE_(reg
)("Returning %x\n", currenthandle
);
2251 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2252 return ERROR_SUCCESS
;
2255 if (lpszSubKey
[0] == '\\') {
2256 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2257 return ERROR_BAD_PATHNAME
;
2260 split_keypath(lpszSubKey
,&wps
,&wpc
);
2262 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2265 lpxkey
=lpNextKey
->nextsub
;
2267 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2269 lpxkey
=lpxkey
->next
;
2278 add_handle(currenthandle
,lpxkey
,samDesired
);
2279 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2280 *retkey
= currenthandle
;
2281 TRACE_(reg
)("Returning %x\n", currenthandle
);
2283 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2285 return ERROR_SUCCESS
;
2288 /* Good. Now the hard part */
2290 lplpPrevKey
= &(lpNextKey
->nextsub
);
2291 lpxkey
= *lplpPrevKey
;
2293 lplpPrevKey
= &(lpxkey
->next
);
2294 lpxkey
= *lplpPrevKey
;
2296 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2297 if (!*lplpPrevKey
) {
2299 TRACE_(reg
)("Returning OUTOFMEMORY\n");
2300 return ERROR_OUTOFMEMORY
;
2302 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2303 TRACE_(reg
)("Adding %s\n", debugstr_w(wps
[i
]));
2304 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2305 (*lplpPrevKey
)->next
= NULL
;
2306 (*lplpPrevKey
)->nextsub
= NULL
;
2307 (*lplpPrevKey
)->values
= NULL
;
2308 (*lplpPrevKey
)->nrofvalues
= 0;
2309 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2311 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2313 (*lplpPrevKey
)->class = NULL
;
2314 lpNextKey
= *lplpPrevKey
;
2318 add_handle(currenthandle
,lpNextKey
,samDesired
);
2320 /*FIXME: flag handling correct? */
2321 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2323 lpNextKey
->class = strdupW(lpszClass
);
2325 lpNextKey
->class = NULL
;
2326 *retkey
= currenthandle
;
2327 TRACE_(reg
)("Returning %x\n", currenthandle
);
2329 *lpDispos
= REG_CREATED_NEW_KEY
;
2331 return ERROR_SUCCESS
;
2335 /******************************************************************************
2336 * RegCreateKeyEx32A [ADVAPI32.130]
2338 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2339 LPSTR lpszClass
, DWORD fdwOptions
,
2341 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2342 LPHKEY retkey
, LPDWORD lpDispos
)
2344 LPWSTR lpszSubKeyW
, lpszClassW
;
2347 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2348 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2351 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2352 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2354 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2355 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2358 if(lpszSubKeyW
) free(lpszSubKeyW
);
2359 if(lpszClassW
) free(lpszClassW
);
2365 /******************************************************************************
2366 * RegCreateKey32W [ADVAPI32.132]
2368 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2371 LPKEYSTRUCT lpNextKey
;
2373 TRACE_(reg
)("(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2375 /* This check is here because the return value is different than the
2376 one from the Ex functions */
2377 lpNextKey
= lookup_hkey(hkey
);
2379 return ERROR_BADKEY
;
2381 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2382 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2387 /******************************************************************************
2388 * RegCreateKey32A [ADVAPI32.129]
2390 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2395 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2396 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2397 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2398 if(lpszSubKeyW
) free(lpszSubKeyW
);
2403 /******************************************************************************
2404 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2406 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2408 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2409 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2414 * Query Value Functions
2415 * Win32 differs between keynames and valuenames.
2416 * multiple values may belong to one key, the special value
2417 * with name NULL is the default value used by the win31
2421 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2422 * RegQueryValue32W -> RegQueryValueEx32W
2426 /******************************************************************************
2427 * RegQueryValueEx32W [ADVAPI32.158]
2428 * Retrieves type and data for a specified name associated with an open key
2431 * hkey [I] Handle of key to query
2432 * lpValueName [I] Name of value to query
2433 * lpdwReserved [I] Reserved - must be NULL
2434 * lpdwType [O] Address of buffer for value type. If NULL, the type
2436 * lpbData [O] Address of data buffer. If NULL, the actual data is
2438 * lpcbData [I/O] Address of data buffer size
2441 * ERROR_SUCCESS: Success
2442 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2443 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2445 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2446 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2447 LPBYTE lpbData
, LPDWORD lpcbData
)
2453 TRACE_(reg
)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2454 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2456 lpkey
= lookup_hkey(hkey
);
2459 return ERROR_INVALID_HANDLE
;
2461 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2462 return ERROR_INVALID_PARAMETER
;
2464 /* An empty name string is equivalent to NULL */
2465 if (lpValueName
&& !*lpValueName
)
2468 if (lpValueName
==NULL
)
2469 { /* Use key's unnamed or default value, if any */
2470 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2471 if (lpkey
->values
[i
].name
==NULL
)
2475 { /* Search for the key name */
2476 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2477 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2481 if (i
==lpkey
->nrofvalues
)
2482 { TRACE_(reg
)(" Key not found\n");
2483 if (lpValueName
==NULL
)
2484 { /* Empty keyname not found */
2486 { *(WCHAR
*)lpbData
= 0;
2491 TRACE_(reg
)(" Returning an empty string\n");
2492 return ERROR_SUCCESS
;
2494 return ERROR_FILE_NOT_FOUND
;
2497 ret
= ERROR_SUCCESS
;
2499 if (lpdwType
) /* type required ?*/
2500 *lpdwType
= lpkey
->values
[i
].type
;
2502 if (lpbData
) /* data required ?*/
2503 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2504 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2506 ret
= ERROR_MORE_DATA
;
2509 if (lpcbData
) /* size required ?*/
2510 { *lpcbData
= lpkey
->values
[i
].len
;
2513 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2515 TRACE_(reg
)(" (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2521 /******************************************************************************
2522 * RegQueryValue32W [ADVAPI32.159]
2524 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2530 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2531 lpcbData
?*lpcbData
:0);
2533 /* Only open subkey, if we really do descend */
2534 if (lpszSubKey
&& *lpszSubKey
) {
2535 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2536 if (ret
!= ERROR_SUCCESS
) {
2537 WARN_(reg
)("Could not open %s\n", debugstr_w(lpszSubKey
));
2544 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2552 /******************************************************************************
2553 * RegQueryValueEx32A [ADVAPI32.157]
2556 * the documantation is wrong: if the buffer is to small it remains untouched
2558 * FIXME: check returnvalue (len) for an empty key
2560 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2561 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2562 LPBYTE lpbData
, LPDWORD lpcbData
)
2564 LPWSTR lpszValueNameW
;
2565 LPBYTE mybuf
= NULL
;
2566 DWORD ret
, mytype
, mylen
= 0;
2568 TRACE_(reg
)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2569 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2571 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2572 { return ERROR_INVALID_PARAMETER
;
2575 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2577 /* get just the type first */
2578 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2580 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2581 { if(lpszValueNameW
) free(lpszValueNameW
);
2585 if (lpcbData
) /* at least length requested? */
2586 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2587 { if (lpbData
) /* value requested? */
2588 { mylen
= 2*( *lpcbData
);
2589 mybuf
= (LPBYTE
)xmalloc( mylen
);
2592 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2594 if (ret
== ERROR_SUCCESS
)
2596 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2600 *lpcbData
= mylen
/2; /* size is in byte! */
2602 else /* no strings, call it straight */
2603 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2607 if (lpdwType
) /* type when requested */
2608 { *lpdwType
= mytype
;
2611 TRACE_(reg
)(" (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2613 if(mybuf
) free(mybuf
);
2614 if(lpszValueNameW
) free(lpszValueNameW
);
2619 /******************************************************************************
2620 * RegQueryValueEx16 [KERNEL.225]
2622 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2623 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2624 LPBYTE lpbData
, LPDWORD lpcbData
)
2626 TRACE_(reg
)("(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2627 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2628 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2629 lpbData
, lpcbData
);
2633 /******************************************************************************
2634 * RegQueryValue32A [ADVAPI32.156]
2636 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2642 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2643 lpcbData
?*lpcbData
:0);
2645 if (lpszSubKey
&& *lpszSubKey
) {
2646 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2647 if( ret
!= ERROR_SUCCESS
)
2653 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2656 RegCloseKey( xhkey
);
2661 /******************************************************************************
2662 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2665 * Is this HACK still applicable?
2668 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2669 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2672 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2675 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2676 lpcbData
?*lpcbData
:0);
2679 *lpcbData
&= 0xFFFF;
2680 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2685 * Setting values of Registry keys
2688 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2689 * RegSetValue32W -> RegSetValueEx32W
2693 /******************************************************************************
2694 * RegSetValueEx32W [ADVAPI32.170]
2695 * Sets the data and type of a value under a register key
2698 * hkey [I] Handle of key to set value for
2699 * lpszValueName [I] Name of value to set
2700 * dwReserved [I] Reserved - must be zero
2701 * dwType [I] Flag for value type
2702 * lpbData [I] Address of value data
2703 * cbData [I] Size of value data
2706 * Success: ERROR_SUCCESS
2707 * Failure: Error code
2710 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2712 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2713 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2719 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2720 dwReserved
, dwType
, lpbData
, cbData
);
2722 lpkey
= lookup_hkey( hkey
);
2725 return ERROR_INVALID_HANDLE
;
2727 lpkey
->flags
|= REG_OPTION_TAINTED
;
2729 if (lpszValueName
==NULL
) {
2730 /* Sets type and name for key's unnamed or default value */
2731 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2732 if (lpkey
->values
[i
].name
==NULL
)
2735 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2736 if ( lpkey
->values
[i
].name
&&
2737 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2741 if (i
==lpkey
->nrofvalues
) {
2742 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2744 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2746 lpkey
->nrofvalues
++;
2747 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2749 if (lpkey
->values
[i
].name
==NULL
) {
2751 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2753 lpkey
->values
[i
].name
= NULL
;
2756 if (dwType
== REG_SZ
)
2757 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2759 lpkey
->values
[i
].len
= cbData
;
2760 lpkey
->values
[i
].type
= dwType
;
2761 if (lpkey
->values
[i
].data
!=NULL
)
2762 free(lpkey
->values
[i
].data
);
2763 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2764 lpkey
->values
[i
].lastmodified
= time(NULL
);
2765 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2766 return ERROR_SUCCESS
;
2770 /******************************************************************************
2771 * RegSetValueEx32A [ADVAPI32.169]
2774 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2776 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2777 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2781 LPWSTR lpszValueNameW
;
2785 return (ERROR_INVALID_PARAMETER
);
2787 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2788 dwReserved
,dwType
,lpbData
,cbData
);
2790 if ((1<<dwType
) & UNICONVMASK
)
2791 { if (dwType
== REG_SZ
)
2792 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2794 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2795 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2802 lpszValueNameW
= strdupA2W(lpszValueName
);
2804 lpszValueNameW
= NULL
;
2806 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2809 free(lpszValueNameW
);
2818 /******************************************************************************
2819 * RegSetValueEx16 [KERNEL.226]
2821 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2822 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2824 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2825 dwReserved
,dwType
,lpbData
,cbData
);
2826 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2831 /******************************************************************************
2832 * RegSetValue32W [ADVAPI32.171]
2834 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2835 LPCWSTR lpszData
, DWORD cbData
)
2840 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",
2841 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2843 if (lpszSubKey
&& *lpszSubKey
) {
2844 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2845 if (ret
!=ERROR_SUCCESS
)
2849 if (dwType
!=REG_SZ
) {
2850 TRACE_(reg
)("dwType=%ld - Changing to REG_SZ\n",dwType
);
2853 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2854 TRACE_(reg
)("Len=%ld != strlen(%s)+1=%d!\n",
2855 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2857 cbData
=2*lstrlenW(lpszData
)+2;
2859 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2866 /******************************************************************************
2867 * RegSetValue32A [ADVAPI32.168]
2870 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2871 LPCSTR lpszData
, DWORD cbData
)
2876 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2877 if (lpszSubKey
&& *lpszSubKey
) {
2878 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2879 if (ret
!=ERROR_SUCCESS
)
2884 if (dwType
!=REG_SZ
) {
2885 TRACE_(reg
)("dwType=%ld!\n",dwType
);
2888 if (cbData
!=strlen(lpszData
)+1)
2889 cbData
=strlen(lpszData
)+1;
2890 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2897 /******************************************************************************
2898 * RegSetValue16 [KERNEL.221] [SHELL.5]
2900 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2901 LPCSTR lpszData
, DWORD cbData
)
2903 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2904 debugstr_a(lpszData
),cbData
);
2905 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2913 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2914 * RegEnumKey32W -> RegEnumKeyEx32W
2918 /******************************************************************************
2919 * RegEnumKeyEx32W [ADVAPI32.139]
2922 * hkey [I] Handle to key to enumerate
2923 * iSubKey [I] Index of subkey to enumerate
2924 * lpszName [O] Buffer for subkey name
2925 * lpcchName [O] Size of subkey buffer
2926 * lpdwReserved [I] Reserved
2927 * lpszClass [O] Buffer for class string
2928 * lpcchClass [O] Size of class buffer
2929 * ft [O] Time key last written to
2931 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2932 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2933 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2936 LPKEYSTRUCT lpkey
,lpxkey
;
2938 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2939 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2941 lpkey
= lookup_hkey( hkey
);
2943 return ERROR_INVALID_HANDLE
;
2945 if (!lpkey
->nextsub
)
2946 return ERROR_NO_MORE_ITEMS
;
2947 lpxkey
=lpkey
->nextsub
;
2949 /* Traverse the subkeys */
2950 while (iSubkey
&& lpxkey
) {
2952 lpxkey
=lpxkey
->next
;
2955 if (iSubkey
|| !lpxkey
)
2956 return ERROR_NO_MORE_ITEMS
;
2957 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
2958 return ERROR_MORE_DATA
;
2959 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
2962 *lpcchName
= lstrlenW(lpszName
);
2965 /* FIXME: what should we write into it? */
2969 return ERROR_SUCCESS
;
2973 /******************************************************************************
2974 * RegEnumKey32W [ADVAPI32.140]
2976 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2981 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2982 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2986 /******************************************************************************
2987 * RegEnumKeyEx32A [ADVAPI32.138]
2989 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2990 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2991 LPSTR lpszClass
, LPDWORD lpcchClass
,
2994 DWORD ret
,lpcchNameW
,lpcchClassW
;
2995 LPWSTR lpszNameW
,lpszClassW
;
2998 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2999 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3002 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3003 lpcchNameW
= *lpcchName
;
3009 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3010 lpcchClassW
= *lpcchClass
;
3025 if (ret
==ERROR_SUCCESS
) {
3026 lstrcpyWtoA(lpszName
,lpszNameW
);
3027 *lpcchName
=strlen(lpszName
);
3029 lstrcpyWtoA(lpszClass
,lpszClassW
);
3030 *lpcchClass
=strlen(lpszClass
);
3041 /******************************************************************************
3042 * RegEnumKey32A [ADVAPI32.137]
3044 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3049 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3050 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3055 /******************************************************************************
3056 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3058 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3061 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3062 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3067 * Enumerate Registry Values
3070 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3074 /******************************************************************************
3075 * RegEnumValue32W [ADVAPI32.142]
3078 * hkey [I] Handle to key to query
3079 * iValue [I] Index of value to query
3080 * lpszValue [O] Value string
3081 * lpcchValue [I/O] Size of value buffer (in wchars)
3082 * lpdReserved [I] Reserved
3083 * lpdwType [O] Type code
3084 * lpbData [O] Value data
3085 * lpcbData [I/O] Size of data buffer (in bytes)
3087 * Note: wide character functions that take and/or return "character counts"
3088 * use TCHAR (that is unsigned short or char) not byte counts.
3090 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3091 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3092 LPDWORD lpdwType
, LPBYTE lpbData
,
3098 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3099 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3101 lpkey
= lookup_hkey( hkey
);
3103 if (!lpcbData
&& lpbData
)
3104 return ERROR_INVALID_PARAMETER
;
3107 return ERROR_INVALID_HANDLE
;
3109 if (lpkey
->nrofvalues
<= iValue
)
3110 return ERROR_NO_MORE_ITEMS
;
3112 val
= &(lpkey
->values
[iValue
]);
3115 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3116 *lpcchValue
= lstrlenW(val
->name
)+1;
3117 return ERROR_MORE_DATA
;
3119 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3120 *lpcchValue
=lstrlenW(val
->name
);
3126 /* Can be NULL if the type code is not required */
3128 *lpdwType
= val
->type
;
3131 if (val
->len
>*lpcbData
)
3132 return ERROR_MORE_DATA
;
3133 memcpy(lpbData
,val
->data
,val
->len
);
3134 *lpcbData
= val
->len
;
3137 debug_print_value ( val
->data
, val
);
3138 return ERROR_SUCCESS
;
3142 /******************************************************************************
3143 * RegEnumValue32A [ADVAPI32.141]
3145 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3146 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3147 LPDWORD lpdwType
, LPBYTE lpbData
,
3152 DWORD ret
,lpcbDataW
;
3155 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3156 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3158 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3160 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3161 lpcbDataW
= *lpcbData
;
3165 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3166 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3171 if (ret
==ERROR_SUCCESS
) {
3172 lstrcpyWtoA(lpszValue
,lpszValueW
);
3174 if ((1<<dwType
) & UNICONVMASK
) {
3175 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3177 if (lpcbDataW
> *lpcbData
)
3178 ret
= ERROR_MORE_DATA
;
3180 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3182 *lpcbData
= lpcbDataW
;
3185 if (lpbDataW
) free(lpbDataW
);
3186 if (lpszValueW
) free(lpszValueW
);
3191 /******************************************************************************
3192 * RegEnumValue16 [KERNEL.223]
3194 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3195 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3196 LPDWORD lpdwType
, LPBYTE lpbData
,
3199 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3200 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3201 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3202 lpdwType
, lpbData
, lpcbData
);
3206 /******************************************************************************
3207 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3208 * Releases the handle of the specified key
3211 * hkey [I] Handle of key to close
3214 * Success: ERROR_SUCCESS
3215 * Failure: Error code
3217 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3219 TRACE_(reg
)("(%x)\n",hkey
);
3221 /* The standard handles are allowed to succeed, even though they are not
3223 if (is_standard_hkey(hkey
))
3224 return ERROR_SUCCESS
;
3226 return remove_handle(hkey
);
3231 * Delete registry key
3234 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3238 /******************************************************************************
3239 * RegDeleteKey32W [ADVAPI32.134]
3242 * hkey [I] Handle to open key
3243 * lpszSubKey [I] Name of subkey to delete
3246 * Success: ERROR_SUCCESS
3247 * Failure: Error code
3249 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3251 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3255 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3257 lpNextKey
= lookup_hkey(hkey
);
3259 return ERROR_INVALID_HANDLE
;
3261 /* Subkey param cannot be NULL */
3262 if (!lpszSubKey
|| !*lpszSubKey
)
3263 return ERROR_BADKEY
;
3265 /* We need to know the previous key in the hier. */
3266 split_keypath(lpszSubKey
,&wps
,&wpc
);
3270 lpxkey
=lpNextKey
->nextsub
;
3272 TRACE_(reg
)(" Scanning [%s]\n",
3273 debugstr_w(lpxkey
->keyname
));
3274 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3276 lpxkey
=lpxkey
->next
;
3280 TRACE_(reg
)(" Not found.\n");
3281 /* not found is success */
3282 return ERROR_SUCCESS
;
3287 lpxkey
= lpNextKey
->nextsub
;
3288 lplpPrevKey
= &(lpNextKey
->nextsub
);
3290 TRACE_(reg
)(" Scanning [%s]\n",
3291 debugstr_w(lpxkey
->keyname
));
3292 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3294 lplpPrevKey
= &(lpxkey
->next
);
3295 lpxkey
= lpxkey
->next
;
3300 WARN_(reg
)(" Not found.\n");
3301 return ERROR_FILE_NOT_FOUND
;
3304 if (lpxkey
->nextsub
) {
3306 WARN_(reg
)(" Not empty.\n");
3307 return ERROR_CANTWRITE
;
3309 *lplpPrevKey
= lpxkey
->next
;
3310 free(lpxkey
->keyname
);
3312 free(lpxkey
->class);
3314 free(lpxkey
->values
);
3317 TRACE_(reg
)(" Done.\n");
3318 return ERROR_SUCCESS
;
3322 /******************************************************************************
3323 * RegDeleteKey32A [ADVAPI32.133]
3325 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3330 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3331 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3332 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3333 if(lpszSubKeyW
) free(lpszSubKeyW
);
3338 /******************************************************************************
3339 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3341 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3343 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3344 return RegDeleteKeyA( hkey
, lpszSubKey
);
3349 * Delete registry value
3352 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3356 /******************************************************************************
3357 * RegDeleteValue32W [ADVAPI32.136]
3365 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3371 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3373 lpkey
= lookup_hkey( hkey
);
3375 return ERROR_INVALID_HANDLE
;
3378 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3379 if ( lpkey
->values
[i
].name
&&
3380 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3384 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3385 if (lpkey
->values
[i
].name
==NULL
)
3389 if (i
== lpkey
->nrofvalues
)
3390 return ERROR_FILE_NOT_FOUND
;
3392 val
= lpkey
->values
+i
;
3393 if (val
->name
) free(val
->name
);
3394 if (val
->data
) free(val
->data
);
3398 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3400 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3402 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3404 lpkey
->nrofvalues
--;
3405 return ERROR_SUCCESS
;
3409 /******************************************************************************
3410 * RegDeleteValue32A [ADVAPI32.135]
3412 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3417 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3418 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3419 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3420 if(lpszValueW
) free(lpszValueW
);
3425 /******************************************************************************
3426 * RegDeleteValue16 [KERNEL.222]
3428 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3430 TRACE_(reg
)("(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3431 return RegDeleteValueA( hkey
, lpszValue
);
3435 /******************************************************************************
3436 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3437 * Writes key to registry
3440 * hkey [I] Handle of key to write
3443 * Success: ERROR_SUCCESS
3444 * Failure: Error code
3446 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3451 TRACE_(reg
)("(%x)\n", hkey
);
3453 lpkey
= lookup_hkey( hkey
);
3455 return ERROR_BADKEY
;
3457 ERR_(reg
)("What is the correct filename?\n");
3459 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3462 return ERROR_SUCCESS
;
3464 return ERROR_UNKNOWN
; /* FIXME */
3468 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3471 /******************************************************************************
3472 * RegQueryInfoKey32W [ADVAPI32.153]
3475 * hkey [I] Handle to key to query
3476 * lpszClass [O] Buffer for class string
3477 * lpcchClass [O] Size of class string buffer
3478 * lpdwReserved [I] Reserved
3479 * lpcSubKeys [I] Buffer for number of subkeys
3480 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3481 * lpcchMaxClass [O] Buffer for longest class string length
3482 * lpcValues [O] Buffer for number of value entries
3483 * lpcchMaxValueName [O] Buffer for longest value name length
3484 * lpccbMaxValueData [O] Buffer for longest value data length
3485 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3487 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3488 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3489 * lpcchClass is NULL
3490 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3491 * (it's hard to test validity, so test !NULL instead)
3493 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3494 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3495 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3496 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3497 LPDWORD lpcchMaxValueName
,
3498 LPDWORD lpccbMaxValueData
,
3499 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3501 LPKEYSTRUCT lpkey
,lpxkey
;
3502 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3505 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3506 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3507 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3508 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3510 lpkey
= lookup_hkey(hkey
);
3512 return ERROR_INVALID_HANDLE
;
3514 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3515 return ERROR_INVALID_PARAMETER
;
3517 /* either lpcchClass is valid or this is win95 and lpcchClass
3520 DWORD classLen
= lstrlenW(lpkey
->class);
3522 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3523 *lpcchClass
=classLen
+1;
3524 return ERROR_MORE_DATA
;
3527 *lpcchClass
=classLen
;
3528 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3536 *lpcchClass
= lstrlenW(lpkey
->class);
3538 lpxkey
=lpkey
->nextsub
;
3539 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3542 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3543 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3544 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3545 maxclass
=lstrlenW(lpxkey
->class);
3546 lpxkey
=lpxkey
->next
;
3548 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3549 LPKEYVALUE val
=lpkey
->values
+i
;
3551 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3552 maxvname
=lstrlenW(val
->name
);
3553 if (val
->len
>maxvdata
)
3556 if (!maxclass
) maxclass
= 1;
3557 if (!maxvname
) maxvname
= 1;
3559 *lpcValues
= lpkey
->nrofvalues
;
3561 *lpcSubKeys
= nrofkeys
;
3563 *lpcchMaxSubkey
= maxsubkey
;
3565 *lpcchMaxClass
= maxclass
;
3566 if (lpcchMaxValueName
)
3567 *lpcchMaxValueName
= maxvname
;
3568 if (lpccbMaxValueData
)
3569 *lpccbMaxValueData
= maxvdata
;
3570 return ERROR_SUCCESS
;
3574 /******************************************************************************
3575 * RegQueryInfoKey32A [ADVAPI32.152]
3577 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3578 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3579 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3580 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3581 LPDWORD lpccbMaxValueData
,
3582 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3584 LPWSTR lpszClassW
= NULL
;
3587 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3588 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3589 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3590 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3594 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3595 } else if (VERSION_GetVersion() == WIN95
) {
3596 /* win95 allows lpcchClass to be null */
3597 /* we don't know how big lpszClass is, would
3598 MAX_PATHNAME_LEN be the correct default? */
3599 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3604 ret
=RegQueryInfoKeyW(
3615 lpcbSecurityDescriptor
,
3618 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3619 lstrcpyWtoA(lpszClass
,lpszClassW
);
3626 /******************************************************************************
3627 * RegConnectRegistry32W [ADVAPI32.128]
3630 * lpMachineName [I] Address of name of remote computer
3631 * hHey [I] Predefined registry handle
3632 * phkResult [I] Address of buffer for remote registry handle
3634 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3637 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3639 if (!lpMachineName
|| !*lpMachineName
) {
3640 /* Use the local machine name */
3641 return RegOpenKey16( hKey
, "", phkResult
);
3644 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
3645 return ERROR_BAD_NETPATH
;
3649 /******************************************************************************
3650 * RegConnectRegistry32A [ADVAPI32.127]
3652 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3655 LPWSTR machineW
= strdupA2W(machine
);
3656 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3662 /******************************************************************************
3663 * RegGetKeySecurity [ADVAPI32.144]
3664 * Retrieves a copy of security descriptor protecting the registry key
3667 * hkey [I] Open handle of key to set
3668 * SecurityInformation [I] Descriptor contents
3669 * pSecurityDescriptor [O] Address of descriptor for key
3670 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3673 * Success: ERROR_SUCCESS
3674 * Failure: Error code
3676 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3677 SECURITY_INFORMATION SecurityInformation
,
3678 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3679 LPDWORD lpcbSecurityDescriptor
)
3683 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3684 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3686 lpkey
= lookup_hkey( hkey
);
3688 return ERROR_INVALID_HANDLE
;
3690 /* FIXME: Check for valid SecurityInformation values */
3692 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3693 return ERROR_INSUFFICIENT_BUFFER
;
3695 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3696 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3698 return ERROR_SUCCESS
;
3702 /******************************************************************************
3703 * RegLoadKey32W [ADVAPI32.???]
3706 * hkey [I] Handle of open key
3707 * lpszSubKey [I] Address of name of subkey
3708 * lpszFile [I] Address of filename for registry information
3710 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3713 TRACE_(reg
)("(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3715 /* Do this check before the hkey check */
3716 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3717 return ERROR_INVALID_PARAMETER
;
3719 lpkey
= lookup_hkey( hkey
);
3721 return ERROR_INVALID_HANDLE
;
3723 FIXME_(reg
)("(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3724 debugstr_w(lpszFile
));
3726 return ERROR_SUCCESS
;
3730 /******************************************************************************
3731 * RegLoadKey32A [ADVAPI32.???]
3733 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3736 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3737 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3738 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3739 if(lpszFileW
) free(lpszFileW
);
3740 if(lpszSubKeyW
) free(lpszSubKeyW
);
3745 /******************************************************************************
3746 * RegNotifyChangeKeyValue [ADVAPI32.???]
3749 * hkey [I] Handle of key to watch
3750 * fWatchSubTree [I] Flag for subkey notification
3751 * fdwNotifyFilter [I] Changes to be reported
3752 * hEvent [I] Handle of signaled event
3753 * fAsync [I] Flag for asynchronous reporting
3755 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3756 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3760 TRACE_(reg
)("(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3763 lpkey
= lookup_hkey( hkey
);
3765 return ERROR_INVALID_HANDLE
;
3767 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3770 return ERROR_SUCCESS
;
3774 /******************************************************************************
3775 * RegUnLoadKey32W [ADVAPI32.173]
3778 * hkey [I] Handle of open key
3779 * lpSubKey [I] Address of name of subkey to unload
3781 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3783 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3784 return ERROR_SUCCESS
;
3788 /******************************************************************************
3789 * RegUnLoadKey32A [ADVAPI32.172]
3791 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3794 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3795 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3796 if(lpSubKeyW
) free(lpSubKeyW
);
3801 /******************************************************************************
3802 * RegSetKeySecurity [ADVAPI32.167]
3805 * hkey [I] Open handle of key to set
3806 * SecurityInfo [I] Descriptor contents
3807 * pSecurityDesc [I] Address of descriptor for key
3809 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3810 PSECURITY_DESCRIPTOR pSecurityDesc
)
3814 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3816 /* It seems to perform this check before the hkey check */
3817 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3818 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3819 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3820 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3823 return ERROR_INVALID_PARAMETER
;
3826 return ERROR_INVALID_PARAMETER
;
3828 lpkey
= lookup_hkey( hkey
);
3830 return ERROR_INVALID_HANDLE
;
3832 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3834 return ERROR_SUCCESS
;
3838 /******************************************************************************
3839 * RegSaveKey32W [ADVAPI32.166]
3842 * hkey [I] Handle of key where save begins
3843 * lpFile [I] Address of filename to save to
3844 * sa [I] Address of security structure
3846 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3847 LPSECURITY_ATTRIBUTES sa
)
3851 TRACE_(reg
)("(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3853 /* It appears to do this check before the hkey check */
3854 if (!lpFile
|| !*lpFile
)
3855 return ERROR_INVALID_PARAMETER
;
3857 lpkey
= lookup_hkey( hkey
);
3859 return ERROR_INVALID_HANDLE
;
3861 FIXME_(reg
)("(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3863 return ERROR_SUCCESS
;
3867 /******************************************************************************
3868 * RegSaveKey32A [ADVAPI32.165]
3870 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3871 LPSECURITY_ATTRIBUTES sa
)
3874 LPWSTR lpFileW
= strdupA2W(lpFile
);
3875 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3881 /******************************************************************************
3882 * RegRestoreKey32W [ADVAPI32.164]
3885 * hkey [I] Handle of key where restore begins
3886 * lpFile [I] Address of filename containing saved tree
3887 * dwFlags [I] Optional flags
3889 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3893 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3895 /* It seems to do this check before the hkey check */
3896 if (!lpFile
|| !*lpFile
)
3897 return ERROR_INVALID_PARAMETER
;
3899 lpkey
= lookup_hkey( hkey
);
3901 return ERROR_INVALID_HANDLE
;
3903 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3905 /* Check for file existence */
3907 return ERROR_SUCCESS
;
3911 /******************************************************************************
3912 * RegRestoreKey32A [ADVAPI32.163]
3914 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3917 LPWSTR lpFileW
= strdupA2W(lpFile
);
3918 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3919 if(lpFileW
) free(lpFileW
);
3924 /******************************************************************************
3925 * RegReplaceKey32W [ADVAPI32.162]
3928 * hkey [I] Handle of open key
3929 * lpSubKey [I] Address of name of subkey
3930 * lpNewFile [I] Address of filename for file with new data
3931 * lpOldFile [I] Address of filename for backup file
3933 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3938 TRACE_(reg
)("(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3939 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3941 lpkey
= lookup_hkey( hkey
);
3943 return ERROR_INVALID_HANDLE
;
3945 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3946 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3948 return ERROR_SUCCESS
;
3952 /******************************************************************************
3953 * RegReplaceKey32A [ADVAPI32.161]
3955 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3959 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3960 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3961 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3962 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);