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>
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
45 #include "winversion.h"
47 static void REGISTRY_Init(void);
48 /* FIXME: following defines should be configured global ... */
50 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
51 #define WINE_PREFIX "/.wine"
52 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
53 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
55 /* relative in ~user/.wine/ : */
56 #define SAVE_CURRENT_USER "user.reg"
57 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
58 #define SAVE_LOCAL_MACHINE "system.reg"
60 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
61 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
63 /* one value of a key */
64 typedef struct tagKEYVALUE
66 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
67 DWORD type
; /* type of value */
68 DWORD len
; /* length of data in BYTEs */
69 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
70 LPBYTE data
; /* content, may be strings, binaries, etc. */
71 } KEYVALUE
,*LPKEYVALUE
;
74 typedef struct tagKEYSTRUCT
76 LPWSTR keyname
; /* name of THIS key (UNICODE) */
77 DWORD flags
; /* flags. */
80 DWORD nrofvalues
; /* nr of values in THIS key */
81 LPKEYVALUE values
; /* values in THIS key */
82 /* key management pointers */
83 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
84 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
85 } KEYSTRUCT
, *LPKEYSTRUCT
;
88 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
89 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
90 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
91 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
93 /* dynamic, not saved */
94 static KEYSTRUCT
*key_performance_data
=NULL
;
95 static KEYSTRUCT
*key_current_config
=NULL
;
96 static KEYSTRUCT
*key_dyn_data
=NULL
;
98 /* what valuetypes do we need to convert? */
99 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
102 static struct openhandle
{
107 static int nrofopenhandles
=0;
108 /* Starts after 1 because 0,1 are reserved for Win16 */
109 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
110 HKEYs for remote registry access */
111 static int currenthandle
=2;
116 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
117 * If so, can we remove them?
119 * No, the memory handling functions are called very often in here,
120 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
121 * loading 100 times slower. -MM
123 static LPWSTR
strdupA2W(LPCSTR src
)
126 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
127 lstrcpyAtoW(dest
,src
);
133 static LPWSTR
strdupW(LPCWSTR a
) {
138 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
139 b
=(LPWSTR
)xmalloc(len
);
146 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
149 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
151 lstrcpynAtoW(dest
,src
,nchars
+1);
156 * we need to convert A to W with '\0' in strings (MULTI_SZ)
159 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
162 TRACE(reg
,"\"%s\" %i\n",src
, n
);
164 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
168 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
171 TRACE(string
,"L\"%s\" %i\n",debugstr_w(src
), n
);
173 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
178 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
180 if (TRACE_ON(reg
) && lpbData
)
184 case HEX_REG_EXPAND_SZ
:
187 TRACE(reg
," Value %s, Data(sz)=%s\n",
188 debugstr_w(key
->name
),
189 debugstr_w((LPCWSTR
)lpbData
));
194 TRACE(reg
," Value %s, Data(dword)=0x%08lx\n",
195 debugstr_w(key
->name
),
199 case HEX_REG_MULTI_SZ
:
203 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
206 TRACE(reg
, " Value %s, MULTI_SZ(%i=%s)\n",
207 debugstr_w(key
->name
),
211 ptr
+= lstrlenW(ptr
)+1;
219 case HEX_REG_RESOURCE_LIST
:
220 case HEX_REG_FULL_RESOURCE_DESCRIPTOR
:
223 case REG_RESOURCE_LIST
:
224 case REG_FULL_RESOURCE_DESCRIPTOR
:
227 char szTemp
[100]; /* 3*32 + 3 + 1 */
229 for ( i
= 0; i
< key
->len
; i
++)
231 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
234 sprintf (&(szTemp
[i
*3+3]),"...");
238 TRACE(reg
," Value %s, Data(raw)=(%s)\n",
239 debugstr_w(key
->name
),
245 FIXME(reg
, " Value %s, Unknown data type %ld\n",
246 debugstr_w(key
->name
),
253 /******************************************************************************
254 * is_standard_hkey [Internal]
255 * Determines if a hkey is a standard key
257 static BOOL
is_standard_hkey( HKEY hkey
)
262 case HKEY_CLASSES_ROOT
:
263 case HKEY_CURRENT_CONFIG
:
264 case HKEY_CURRENT_USER
:
265 case HKEY_LOCAL_MACHINE
:
267 case HKEY_PERFORMANCE_DATA
:
275 /******************************************************************************
276 * add_handle [Internal]
278 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
282 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
283 /* Check for duplicates */
284 for (i
=0;i
<nrofopenhandles
;i
++) {
285 if (openhandles
[i
].lpkey
==lpkey
) {
286 /* This is not really an error - the user is allowed to create
287 two (or more) handles to the same key */
288 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
290 if (openhandles
[i
].hkey
==hkey
) {
291 WARN(reg
, "Adding handle %x twice\n",hkey
);
294 openhandles
=xrealloc( openhandles
,
295 sizeof(struct openhandle
)*(nrofopenhandles
+1));
297 openhandles
[i
].lpkey
= lpkey
;
298 openhandles
[i
].hkey
= hkey
;
299 openhandles
[i
].accessmask
= accessmask
;
304 /******************************************************************************
305 * get_handle [Internal]
308 * Success: Pointer to key
311 static LPKEYSTRUCT
get_handle( HKEY hkey
)
315 for (i
=0; i
<nrofopenhandles
; i
++)
316 if (openhandles
[i
].hkey
== hkey
)
317 return openhandles
[i
].lpkey
;
318 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
323 /******************************************************************************
324 * remove_handle [Internal]
327 * hkey [I] Handle of key to remove
330 * Success: ERROR_SUCCESS
331 * Failure: ERROR_INVALID_HANDLE
333 static DWORD
remove_handle( HKEY hkey
)
337 for (i
=0;i
<nrofopenhandles
;i
++)
338 if (openhandles
[i
].hkey
==hkey
)
341 if (i
== nrofopenhandles
) {
342 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
343 return ERROR_INVALID_HANDLE
;
346 memcpy( openhandles
+i
,
348 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
350 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
352 return ERROR_SUCCESS
;
355 /******************************************************************************
356 * lookup_hkey [Internal]
358 * Just as the name says. Creates the root keys on demand, so we can call the
359 * Reg* functions at any time.
362 * Success: Pointer to key structure
365 #define ADD_ROOT_KEY(xx) \
366 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
367 memset(xx,'\0',sizeof(KEYSTRUCT));\
368 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
370 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
373 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
374 * some programs. Do not remove those cases. -MM
378 case HKEY_CLASSES_ROOT
:
380 if (!key_classes_root
)
384 /* calls lookup_hkey recursively, TWICE */
388 &cl_r_hkey
) != ERROR_SUCCESS
)
392 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
396 key_classes_root
= lookup_hkey(cl_r_hkey
);
398 return key_classes_root
;
401 case HKEY_CURRENT_USER
:
402 if (!key_current_user
) {
403 ADD_ROOT_KEY(key_current_user
);
405 return key_current_user
;
407 case HKEY_LOCAL_MACHINE
:
408 if (!key_local_machine
) {
409 ADD_ROOT_KEY(key_local_machine
);
412 return key_local_machine
;
416 ADD_ROOT_KEY(key_users
);
420 case HKEY_PERFORMANCE_DATA
:
421 if (!key_performance_data
) {
422 ADD_ROOT_KEY(key_performance_data
);
424 return key_performance_data
;
428 ADD_ROOT_KEY(key_dyn_data
);
432 case HKEY_CURRENT_CONFIG
:
433 if (!key_current_config
) {
434 ADD_ROOT_KEY(key_current_config
);
436 return key_current_config
;
439 return get_handle(hkey
);
445 /* so we don't accidently access them ... */
446 #define key_current_config NULL NULL
447 #define key_current_user NULL NULL
448 #define key_users NULL NULL
449 #define key_local_machine NULL NULL
450 #define key_classes_root NULL NULL
451 #define key_dyn_data NULL NULL
452 #define key_performance_data NULL NULL
454 /******************************************************************************
455 * split_keypath [Internal]
456 * splits the unicode string 'wp' into an array of strings.
457 * the array is allocated by this function.
458 * Free the array using FREE_KEY_PATH
461 * wp [I] String to split up
462 * wpv [O] Array of pointers to strings
463 * wpc [O] Number of components
465 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
470 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
472 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
474 /* We know we have at least one substring */
477 /* Replace each backslash with NULL, and increment the count */
478 for (i
=0;ws
[i
];i
++) {
487 /* Allocate the space for the array of pointers, leaving room for the
489 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
492 /* Assign each pointer to the appropriate character in the string */
497 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
502 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
507 /******************************************************************************
508 * REGISTRY_Init [Internal]
509 * Registry initialisation, allocates some default keys.
511 static void REGISTRY_Init(void) {
515 TRACE(reg
,"(void)\n");
517 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
520 /* This was an Open, but since it is called before the real registries
521 are loaded, it was changed to a Create - MTB 980507*/
522 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
523 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
526 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
530 * string RegisteredOwner
531 * string RegisteredOrganization
534 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
539 if (-1!=gethostname(buf
,200)) {
540 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
541 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
547 /************************ SAVE Registry Function ****************************/
549 #define REGISTRY_SAVE_VERSION 0x00000001
551 /* Registry saveformat:
552 * If you change it, increase above number by 1, which will flush
553 * old registry database files.
556 * "WINE REGISTRY Version %d"
560 * valuename=lastmodified,type,data
564 * keyname,valuename,stringdata:
565 * the usual ascii characters from 0x00-0xff (well, not 0x00)
566 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
567 * ( "=\\\t" escaped in \uXXXX form.)
571 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
573 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
574 * SaveOnlyUpdatedKeys=yes
577 /******************************************************************************
578 * _save_check_tainted [Internal]
580 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
586 if (lpkey
->flags
& REG_OPTION_TAINTED
)
591 if (_save_check_tainted(lpkey
->nextsub
)) {
592 lpkey
->flags
|= REG_OPTION_TAINTED
;
600 /******************************************************************************
601 * _save_USTRING [Internal]
603 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
617 if (escapeeq
&& *s
=='=')
620 fputc(*s
,F
); /* if \\ then put it twice. */
622 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
629 /******************************************************************************
630 * _savesubkey [Internal]
633 * REG_MULTI_SZ is handled as binary (like in win95) (js)
635 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
642 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
643 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
645 for (tabs
=level
;tabs
--;)
647 _save_USTRING(F
,lpxkey
->keyname
,1);
649 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
650 LPKEYVALUE val
=lpxkey
->values
+i
;
652 for (tabs
=level
+1;tabs
--;)
654 _save_USTRING(F
,val
->name
,0);
656 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
657 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
658 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
660 for (j
=0;j
<val
->len
;j
++)
661 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
664 /* descend recursively */
665 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
674 /******************************************************************************
675 * _savesubreg [Internal]
677 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
679 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
680 _save_check_tainted(lpkey
->nextsub
);
681 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
685 /******************************************************************************
686 * _savereg [Internal]
688 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
694 WARN(reg
,"Couldn't open %s for writing: %s\n",
699 if (!_savesubreg(F
,lpkey
,all
)) {
702 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
710 /******************************************************************************
711 * SHELL_SaveRegistry [Internal]
713 void SHELL_SaveRegistry( void )
723 TRACE(reg
,"(void)\n");
726 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
735 if ( (ERROR_SUCCESS
!=RegQueryValueExA(
741 &len
)) || (type
!=REG_SZ
))
748 if (lstrcmpiA(buf
,"yes"))
751 pwd
=getpwuid(getuid());
752 if ( (pwd
!=NULL
) && (pwd
->pw_dir
!=NULL
))
756 * Save HKEY_CURRENT_USER
757 * Try first saving according to the defined location in .winerc
759 fn
= xmalloc( MAX_PATHNAME_LEN
);
760 if (PROFILE_GetWineIniString (
765 MAX_PATHNAME_LEN
- 1))
767 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
772 if (usedCfgUser
!= 1)
775 strlen(pwd
->pw_dir
) +
776 strlen(WINE_PREFIX
) +
777 strlen(SAVE_CURRENT_USER
) + 2 );
779 strcpy(fn
,pwd
->pw_dir
);
780 strcat(fn
,WINE_PREFIX
);
782 /* create the directory. don't care about errorcodes. */
783 mkdir(fn
,0755); /* drwxr-xr-x */
784 strcat(fn
,"/"SAVE_CURRENT_USER
);
786 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
790 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
791 if (-1==rename(tmp
,fn
)) {
792 perror("rename tmp registry");
801 * Save HKEY_LOCAL_MACHINE
802 * Try first saving according to the defined location in .winerc
804 fn
= xmalloc ( MAX_PATHNAME_LEN
);
805 if (PROFILE_GetWineIniString (
807 "LocalMachineFileName",
810 MAX_PATHNAME_LEN
- 1))
812 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
822 strlen(SAVE_LOCAL_MACHINE
)+2);
824 strcpy(fn
,pwd
->pw_dir
);
825 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
827 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
831 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
832 if (-1==rename(tmp
,fn
)) {
833 perror("rename tmp registry");
847 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
849 strcpy(fn
,pwd
->pw_dir
);
850 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
852 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
853 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
854 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
855 if (-1==rename(tmp
,fn
)) {
856 perror("rename tmp registry");
865 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
870 /************************ LOAD Registry Function ****************************/
874 /******************************************************************************
875 * _find_or_add_key [Internal]
877 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
879 LPKEYSTRUCT lpxkey
,*lplpkey
;
881 if ((!keyname
) || (keyname
[0]==0)) {
885 lplpkey
= &(lpkey
->nextsub
);
888 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
889 !lstrcmpiW(lpxkey
->keyname
,keyname
)
892 lplpkey
= &(lpxkey
->next
);
896 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
898 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
899 lpxkey
->keyname
= keyname
;
905 /******************************************************************************
906 * _find_or_add_value [Internal]
908 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
909 LPBYTE data
, DWORD len
, DWORD lastmodified
)
914 if (name
&& !*name
) {/* empty string equals default (NULL) value */
919 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
925 if ( val
->name
!=NULL
&&
926 val
->name
[0]==name
[0] &&
927 !lstrcmpiW(val
->name
,name
)
932 if (i
==lpkey
->nrofvalues
) {
933 lpkey
->values
= xrealloc(
935 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
938 memset(val
,'\0',sizeof(KEYVALUE
));
944 if (val
->lastmodified
<lastmodified
) {
945 val
->lastmodified
=lastmodified
;
956 /******************************************************************************
957 * _wine_read_line [Internal]
959 * reads a line including dynamically enlarging the readbuffer and throwing
962 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
972 s
=fgets(curread
,mylen
,F
);
975 if (NULL
==(s
=strchr(curread
,'\n'))) {
976 /* buffer wasn't large enough */
977 curoff
= strlen(*buf
);
978 *buf
= xrealloc(*buf
,*len
*2);
979 curread
= *buf
+ curoff
;
980 mylen
= *len
; /* we filled up the buffer and
981 * got new '*len' bytes to fill
989 /* throw away comments */
990 if (**buf
=='#' || **buf
==';') {
995 if (s
) /* got end of line */
1002 /******************************************************************************
1003 * _wine_read_USTRING [Internal]
1005 * converts a char* into a UNICODE string (up to a special char)
1006 * and returns the position exactly after that string
1008 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
1013 /* read up to "=" or "\0" or "\n" */
1016 /* empty string is the win3.1 default value(NULL)*/
1020 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
1022 while (*s
&& (*s
!='\n') && (*s
!='=')) {
1024 *ws
++=*((unsigned char*)s
++);
1028 /* Dangling \ ... may only happen if a registry
1029 * write was short. FIXME: What do to?
1039 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1047 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1048 if (!sscanf(xbuf
,"%x",&wc
))
1049 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1051 *ws
++ =(unsigned short)wc
;
1058 *str
= strdupW(*str
);
1066 /******************************************************************************
1067 * _wine_loadsubkey [Internal]
1070 * It seems like this is returning a boolean. Should it?
1076 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1077 int *buflen
, DWORD optflag
)
1084 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1087 lpkey
->flags
|= optflag
;
1089 /* Good. We already got a line here ... so parse it */
1099 WARN(reg
,"Got a subhierarchy without resp. key?\n");
1102 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1106 /* let the caller handle this line */
1107 if (i
<level
|| **buf
=='\0')
1110 /* it can be: a value or a keyname. Parse the name first */
1111 s
=_wine_read_USTRING(s
,&name
);
1113 /* switch() default: hack to avoid gotos */
1117 lpxkey
=_find_or_add_key(lpkey
,name
);
1120 int len
,lastmodified
,type
;
1123 WARN(reg
,"Unexpected character: %c\n",*s
);
1127 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1128 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
1132 s
=strchr(s
,',');s
++;
1133 s
=strchr(s
,',');s
++;
1134 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1135 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1137 len
= lstrlenW((LPWSTR
)data
)*2+2;
1142 data
= (LPBYTE
)xmalloc(len
+1);
1143 for (i
=0;i
<len
;i
++) {
1145 if (*s
>='0' && *s
<='9')
1146 data
[i
]=(*s
-'0')<<4;
1147 if (*s
>='a' && *s
<='f')
1148 data
[i
]=(*s
-'a'+'\xa')<<4;
1149 if (*s
>='A' && *s
<='F')
1150 data
[i
]=(*s
-'A'+'\xa')<<4;
1152 if (*s
>='0' && *s
<='9')
1154 if (*s
>='a' && *s
<='f')
1155 data
[i
]|=*s
-'a'+'\xa';
1156 if (*s
>='A' && *s
<='F')
1157 data
[i
]|=*s
-'A'+'\xa';
1161 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1164 /* read the next line */
1165 if (!_wine_read_line(F
,buf
,buflen
))
1172 /******************************************************************************
1173 * _wine_loadsubreg [Internal]
1175 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1181 buf
=xmalloc(10);buflen
=10;
1182 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1186 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1190 if (ver
!=REGISTRY_SAVE_VERSION
) {
1191 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1195 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1199 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1208 /******************************************************************************
1209 * _wine_loadreg [Internal]
1211 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1215 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1219 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1222 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1230 /******************************************************************************
1231 * _flush_registry [Internal]
1233 * This function allow to flush section of the internal registry. It is mainly
1234 * implements to fix a problem with the global HKU and the local HKU.
1235 * Those two files are read to build the HKU\.Default branch to finaly copy
1236 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1237 * all the global HKU are saved onto the user's personal version of HKU hive.
1241 /* Forward declaration of recusive agent */
1242 static void _flush_reg(LPKEYSTRUCT from
);
1244 static void _flush_registry( LPKEYSTRUCT from
)
1246 /* make sure we have something... */
1250 /* Launch the recusive agent on sub branches */
1251 _flush_reg( from
->nextsub
);
1252 _flush_reg( from
->next
);
1254 /* Initialize pointers */
1255 from
->nextsub
= NULL
;
1258 static void _flush_reg( LPKEYSTRUCT from
)
1262 /* make sure we have something... */
1267 * do the same for the child keys
1269 if (from
->nextsub
!= NULL
)
1270 _flush_reg(from
->nextsub
);
1273 * do the same for the sibling keys
1275 if (from
->next
!= NULL
)
1276 _flush_reg(from
->next
);
1279 * iterate through this key's values and delete them
1281 for (j
=0;j
<from
->nrofvalues
;j
++)
1283 free( (from
->values
+j
)->name
);
1284 free( (from
->values
+j
)->data
);
1288 * free the structure
1295 /******************************************************************************
1296 * _copy_registry [Internal]
1298 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1306 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1308 for (j
=0;j
<from
->nrofvalues
;j
++) {
1312 valfrom
= from
->values
+j
;
1314 if (name
) name
=strdupW(name
);
1315 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1316 memcpy(data
,valfrom
->data
,valfrom
->len
);
1324 valfrom
->lastmodified
1327 _copy_registry(from
,lpxkey
);
1333 /* WINDOWS 95 REGISTRY LOADER */
1335 * Structure of a win95 registry database.
1337 * 0 : "CREG" - magic
1339 * 8 : DWORD offset_of_RGDB_part
1340 * 0C..0F: ? (someone fill in please)
1341 * 10: WORD number of RGDB blocks
1343 * 14: WORD always 0000?
1344 * 16: WORD always 0001?
1345 * 18..1F: ? (someone fill in please)
1349 * 0 : "RGKN" - magic
1350 * 4 : DWORD offset to first RGDB section
1351 * 8 : DWORD offset to the root record
1352 * C..0x1B: ? (fill in)
1353 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1355 * Disk Key Entry Structure:
1356 * 00: DWORD - Free entry indicator(?)
1357 * 04: DWORD - Hash = sum of bytes of keyname
1358 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1359 * 0C: DWORD - disk address of PreviousLevel Key.
1360 * 10: DWORD - disk address of Next Sublevel Key.
1361 * 14: DWORD - disk address of Next Key (on same level).
1362 * DKEP>18: WORD - Nr, Low Significant part.
1363 * 1A: WORD - Nr, High Significant part.
1365 * The disk address always points to the nr part of the previous key entry
1366 * of the referenced key. Don't ask me why, or even if I got this correct
1367 * from staring at 1kg of hexdumps. (DKEP)
1369 * The High significant part of the structure seems to equal the number
1370 * of the RGDB section. The low significant part is a unique ID within
1373 * There are two minor corrections to the position of that structure.
1374 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1375 * the DKE reread from there.
1376 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1377 * CPS - I have not experienced the above phenomenon in my registry files
1380 * 00: "RGDB" - magic
1381 * 04: DWORD offset to next RGDB section
1383 * 0C: WORD always 000d?
1384 * 0E: WORD RGDB block number
1385 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1387 * 20.....: disk keys
1390 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1391 * 08: WORD nrLS - low significant part of NR
1392 * 0A: WORD nrHS - high significant part of NR
1393 * 0C: DWORD bytesused - bytes used in this structure.
1394 * 10: WORD name_len - length of name in bytes. without \0
1395 * 12: WORD nr_of_values - number of values.
1396 * 14: char name[name_len] - name string. No \0.
1397 * 14+name_len: disk values
1398 * nextkeyoffset: ... next disk key
1401 * 00: DWORD type - value type (hmm, could be WORD too)
1402 * 04: DWORD - unknown, usually 0
1403 * 08: WORD namelen - length of Name. 0 means name=NULL
1404 * 0C: WORD datalen - length of Data.
1405 * 10: char name[namelen] - name, no \0
1406 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1407 * 10+namelen+datalen: next values or disk key
1409 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1410 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1411 * structure) and reading another RGDB_section.
1412 * repeat until end of file.
1414 * An interesting relationship exists in RGDB_section. The value at offset
1415 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1416 * idea at the moment what this means. (Kevin Cozens)
1418 * FIXME: this description needs some serious help, yes.
1421 struct _w95keyvalue
{
1423 unsigned short datalen
;
1425 unsigned char *data
;
1433 struct _w95keyvalue
*values
;
1434 struct _w95key
*prevlvl
;
1435 struct _w95key
*nextsub
;
1436 struct _w95key
*next
;
1450 /******************************************************************************
1451 * _w95_processKey [Internal]
1453 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1454 int nrLS
, int nrMS
, struct _w95_info
*info
)
1457 /* Disk Key Header structure (RGDB part) */
1459 unsigned long nextkeyoff
;
1460 unsigned short nrLS
;
1461 unsigned short nrMS
;
1462 unsigned long bytesused
;
1463 unsigned short keynamelen
;
1464 unsigned short values
;
1467 /* disk key values or nothing */
1469 /* Disk Key Value structure */
1473 unsigned short valnamelen
;
1474 unsigned short valdatalen
;
1475 /* valname, valdata */
1481 char *rgdbdata
= info
->rgdbbuffer
;
1482 int nbytes
= info
->rgdbsize
;
1483 char *curdata
= rgdbdata
;
1484 char *end
= rgdbdata
+ nbytes
;
1486 char *next
= rgdbdata
;
1492 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1494 memcpy(&off_next_rgdb
,curdata
+4,4);
1495 next
= curdata
+ off_next_rgdb
;
1496 nrgdb
= (int) *((short *)curdata
+ 7);
1498 } while (nrgdb
!= nrMS
&& (next
< end
));
1500 /* curdata now points to the start of the right RGDB section */
1503 #define XREAD(whereto,len) \
1504 if ((curdata + len) <= end) {\
1505 memcpy(whereto,curdata,len);\
1510 while (curdata
< next
) {
1511 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1513 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1514 if (xdkh
->nrLS
== nrLS
) {
1515 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1516 curdata
+= sizeof(dkh
);
1519 curdata
+= xdkh
->nextkeyoff
;
1522 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1524 if (nrgdb
!= dkh
.nrMS
)
1527 assert((dkh
.keynamelen
<2) || curdata
[0]);
1528 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1529 curdata
+= dkh
.keynamelen
;
1531 for (i
=0;i
< dkh
.values
; i
++) {
1537 XREAD(&dkv
,sizeof(dkv
));
1539 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1540 curdata
+= dkv
.valnamelen
;
1542 if ((1 << dkv
.type
) & UNICONVMASK
) {
1543 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1544 len
= 2*(dkv
.valdatalen
+ 1);
1546 /* I don't think we want to NULL terminate all data */
1547 data
= xmalloc(dkv
.valdatalen
);
1548 memcpy (data
, curdata
, dkv
.valdatalen
);
1549 len
= dkv
.valdatalen
;
1552 curdata
+= dkv
.valdatalen
;
1566 /******************************************************************************
1567 * _w95_walkrgkn [Internal]
1569 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1570 struct _w95_info
*info
)
1573 /* Disk Key Entry structure (RGKN part) */
1577 unsigned long x3
;/*usually 0xFFFFFFFF */
1578 unsigned long prevlvl
;
1579 unsigned long nextsub
;
1581 unsigned short nrLS
;
1582 unsigned short nrMS
;
1583 } *dke
= (struct dke
*)off
;
1587 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1590 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1591 /* XXX <-- This is a hack*/
1596 if (dke
->nextsub
!= -1 &&
1597 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1598 && (dke
->nextsub
> 0x20)) {
1600 _w95_walkrgkn(lpxkey
,
1601 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1605 if (dke
->next
!= -1 &&
1606 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1607 (dke
->next
> 0x20)) {
1608 _w95_walkrgkn(prevkey
,
1609 info
->rgknbuffer
+ dke
->next
- 0x20,
1617 /******************************************************************************
1618 * _w95_loadreg [Internal]
1620 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1624 unsigned long where
,version
,rgdbsection
,end
;
1625 struct _w95_info info
;
1627 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1629 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1630 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1631 if (hfd
==HFILE_ERROR
)
1634 if (4!=_lread(hfd
,magic
,4))
1636 if (strcmp(magic
,"CREG")) {
1637 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1640 if (4!=_lread(hfd
,&version
,4))
1642 if (4!=_lread(hfd
,&rgdbsection
,4))
1644 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1646 if (4!=_lread(hfd
,magic
,4))
1648 if (strcmp(magic
,"RGKN")) {
1649 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1653 /* STEP 1: Keylink structures */
1654 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1659 info
.rgknsize
= end
- where
;
1660 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1661 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1664 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1667 end
= hfdinfo
.nFileSizeLow
;
1668 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1670 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1673 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1674 info
.rgdbsize
= end
- rgdbsection
;
1676 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1680 _w95_walkrgkn(lpkey
, NULL
, &info
);
1682 free (info
.rgdbbuffer
);
1683 free (info
.rgknbuffer
);
1687 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1690 reghack - windows 3.11 registry data format demo program.
1692 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1693 a combined hash table and tree description, and finally a text table.
1695 The header is obvious from the struct header. The taboff1 and taboff2
1696 fields are always 0x20, and their usage is unknown.
1698 The 8-byte entry table has various entry types.
1700 tabent[0] is a root index. The second word has the index of the root of
1702 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1703 the index of the key/value that has that hash. Data with the same
1704 hash value are on a circular list. The other three words in the
1705 hash entry are always zero.
1706 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1707 entry: dirent and keyent/valent. They are identified by context.
1708 tabent[freeidx] is the first free entry. The first word in a free entry
1709 is the index of the next free entry. The last has 0 as a link.
1710 The other three words in the free list are probably irrelevant.
1712 Entries in text table are preceeded by a word at offset-2. This word
1713 has the value (2*index)+1, where index is the referring keyent/valent
1714 entry in the table. I have no suggestion for the 2* and the +1.
1715 Following the word, there are N bytes of data, as per the keyent/valent
1716 entry length. The offset of the keyent/valent entry is from the start
1717 of the text table to the first data byte.
1719 This information is not available from Microsoft. The data format is
1720 deduced from the reg.dat file by me. Mistakes may
1721 have been made. I claim no rights and give no guarantees for this program.
1723 Tor Sjøwall, tor@sn.no
1726 /* reg.dat header format */
1727 struct _w31_header
{
1728 char cookie
[8]; /* 'SHCC3.10' */
1729 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1730 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1731 unsigned long tabcnt
; /* number of entries in index table */
1732 unsigned long textoff
; /* offset of text part */
1733 unsigned long textsize
; /* byte size of text part */
1734 unsigned short hashsize
; /* hash size */
1735 unsigned short freeidx
; /* free index */
1738 /* generic format of table entries */
1739 struct _w31_tabent
{
1740 unsigned short w0
, w1
, w2
, w3
;
1743 /* directory tabent: */
1744 struct _w31_dirent
{
1745 unsigned short sibling_idx
; /* table index of sibling dirent */
1746 unsigned short child_idx
; /* table index of child dirent */
1747 unsigned short key_idx
; /* table index of key keyent */
1748 unsigned short value_idx
; /* table index of value valent */
1752 struct _w31_keyent
{
1753 unsigned short hash_idx
; /* hash chain index for string */
1754 unsigned short refcnt
; /* reference count */
1755 unsigned short length
; /* length of string */
1756 unsigned short string_off
; /* offset of string in text table */
1760 struct _w31_valent
{
1761 unsigned short hash_idx
; /* hash chain index for string */
1762 unsigned short refcnt
; /* reference count */
1763 unsigned short length
; /* length of string */
1764 unsigned short string_off
; /* offset of string in text table */
1767 /* recursive helper function to display a directory tree */
1769 __w31_dumptree( unsigned short idx
,
1771 struct _w31_tabent
*tab
,
1772 struct _w31_header
*head
,
1774 time_t lastmodified
,
1777 struct _w31_dirent
*dir
;
1778 struct _w31_keyent
*key
;
1779 struct _w31_valent
*val
;
1780 LPKEYSTRUCT xlpkey
= NULL
;
1782 static char tail
[400];
1785 dir
=(struct _w31_dirent
*)&tab
[idx
];
1788 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1790 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1791 tail
[key
->length
]='\0';
1792 /* all toplevel entries AND the entries in the
1793 * toplevel subdirectory belong to \SOFTWARE\Classes
1795 if (!level
&& !lstrcmpA(tail
,".classes")) {
1796 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1797 idx
=dir
->sibling_idx
;
1800 name
=strdupA2W(tail
);
1802 xlpkey
=_find_or_add_key(lpkey
,name
);
1804 /* only add if leaf node or valued node */
1805 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1806 if (dir
->value_idx
) {
1807 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1808 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1809 tail
[val
->length
]='\0';
1810 value
=strdupA2W(tail
);
1811 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1815 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1817 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1818 idx
=dir
->sibling_idx
;
1823 /******************************************************************************
1824 * _w31_loadreg [Internal]
1826 void _w31_loadreg(void) {
1828 struct _w31_header head
;
1829 struct _w31_tabent
*tab
;
1833 BY_HANDLE_FILE_INFORMATION hfinfo
;
1834 time_t lastmodified
;
1837 TRACE(reg
,"(void)\n");
1839 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1840 if (hf
==HFILE_ERROR
)
1843 /* read & dump header */
1844 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1845 ERR(reg
, "reg.dat is too short.\n");
1849 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1850 ERR(reg
, "reg.dat has bad signature.\n");
1855 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1856 /* read and dump index table */
1858 if (len
!=_lread(hf
,tab
,len
)) {
1859 ERR(reg
,"couldn't read %d bytes.\n",len
);
1866 txt
= xmalloc(head
.textsize
);
1867 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1868 ERR(reg
,"couldn't seek to textblock.\n");
1874 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1875 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1882 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1883 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1889 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1890 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1891 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1899 /**********************************************************************************
1900 * SHELL_LoadRegistry [Internal]
1902 void SHELL_LoadRegistry( void )
1906 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1909 TRACE(reg
,"(void)\n");
1911 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1912 HKU
= lookup_hkey(HKEY_USERS
);
1913 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1915 /* Load windows 3.1 entries */
1917 /* Load windows 95 entries */
1918 _w95_loadreg("C:\\system.1st", HKLM
);
1919 _w95_loadreg("system.dat", HKLM
);
1920 _w95_loadreg("user.dat", HKU
);
1923 * Load the global HKU hive directly from /usr/local/etc
1925 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1928 * Load the global machine defaults directly form /usr/local/etc
1930 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1932 /* Get current user info */
1933 pwd
=getpwuid(getuid());
1936 * Load the user saved registries
1938 if ( (pwd
!= NULL
) &&
1939 (pwd
->pw_dir
!= NULL
) )
1942 * Load user's personal versions of global HKU/.Default keys
1945 strlen(pwd
->pw_dir
)+
1946 strlen(WINE_PREFIX
)+
1947 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1949 strcpy(fn
, pwd
->pw_dir
);
1950 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1951 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1955 * Load HKCU, attempt to get the registry location from the config
1956 * file first, if exist, load and keep going.
1958 fn
= xmalloc( MAX_PATHNAME_LEN
);
1959 if ( PROFILE_GetWineIniString(
1964 MAX_PATHNAME_LEN
- 1))
1966 _wine_loadreg(HKCU
,fn
,0);
1971 strlen(pwd
->pw_dir
)+
1972 strlen(WINE_PREFIX
)+
1973 strlen(SAVE_CURRENT_USER
)+2);
1975 strcpy(fn
, pwd
->pw_dir
);
1976 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1977 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
1981 * Load HKLM, attempt to get the registry location from the config
1982 * file first, if exist, load and keep going.
1984 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1985 if ( PROFILE_GetWineIniString(
1987 "LocalMachineFileName",
1990 MAX_PATHNAME_LEN
- 1))
1992 _wine_loadreg(HKLM
, fn
, 0);
1997 strlen(pwd
->pw_dir
)+
1998 strlen(WINE_PREFIX
)+
1999 strlen(SAVE_LOCAL_MACHINE
)+2);
2001 strcpy(fn
,pwd
->pw_dir
);
2002 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
2003 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
2008 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
2012 * Obtain the handle of the HKU\.Default key.
2013 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2015 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
2016 lpkey
= lookup_hkey(hkey
);
2018 WARN(reg
,"Could not create global user default key\n");
2020 _copy_registry(lpkey
, HKCU
);
2025 * Since HKU is built from the global HKU and the local user HKU file we must
2026 * flush the HKU tree we have built at this point otherwise the part brought
2027 * in from the global HKU is saved into the local HKU. To avoid this
2028 * useless dupplication of HKU keys we reread the local HKU key.
2031 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2032 _flush_registry(HKU
);
2034 /* Reload user's local HKU hive */
2036 strlen(pwd
->pw_dir
)+
2037 strlen(WINE_PREFIX
)+
2038 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
2040 strcpy(fn
,pwd
->pw_dir
);
2041 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2043 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2048 * Make sure the update mode is there
2050 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2052 DWORD junk
,type
,len
;
2056 if (( RegQueryValueExA(
2062 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2064 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2072 /********************* API FUNCTIONS ***************************************/
2076 * All functions are stubs to RegOpenKeyEx32W where all the
2080 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2081 * RegOpenKey32W -> RegOpenKeyEx32W
2085 /******************************************************************************
2086 * RegOpenKeyEx32W [ADVAPI32.150]
2087 * Opens the specified key
2089 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2092 * hkey [I] Handle of open key
2093 * lpszSubKey [I] Name of subkey to open
2094 * dwReserved [I] Reserved - must be zero
2095 * samDesired [I] Security access mask
2096 * retkey [O] Address of handle of open key
2099 * Success: ERROR_SUCCESS
2100 * Failure: Error code
2102 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2103 REGSAM samDesired
, LPHKEY retkey
)
2105 LPKEYSTRUCT lpNextKey
,lpxkey
;
2109 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2112 lpNextKey
= lookup_hkey( hkey
);
2114 return ERROR_INVALID_HANDLE
;
2116 if (!lpszSubKey
|| !*lpszSubKey
) {
2117 /* Either NULL or pointer to empty string, so return a new handle
2118 to the original hkey */
2120 add_handle(currenthandle
,lpNextKey
,samDesired
);
2121 *retkey
=currenthandle
;
2122 return ERROR_SUCCESS
;
2125 if (lpszSubKey
[0] == '\\') {
2126 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2127 return ERROR_BAD_PATHNAME
;
2130 split_keypath(lpszSubKey
,&wps
,&wpc
);
2132 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2136 lpxkey
=lpNextKey
->nextsub
;
2138 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2141 lpxkey
=lpxkey
->next
;
2145 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
2147 return ERROR_FILE_NOT_FOUND
;
2154 add_handle(currenthandle
,lpxkey
,samDesired
);
2155 *retkey
= currenthandle
;
2156 TRACE(reg
," Returning %x\n", currenthandle
);
2158 return ERROR_SUCCESS
;
2162 /******************************************************************************
2163 * RegOpenKeyEx32A [ADVAPI32.149]
2165 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2166 REGSAM samDesired
, LPHKEY retkey
)
2168 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2171 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2173 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2179 /******************************************************************************
2180 * RegOpenKey32W [ADVAPI32.151]
2183 * hkey [I] Handle of open key
2184 * lpszSubKey [I] Address of name of subkey to open
2185 * retkey [O] Address of handle of open key
2188 * Success: ERROR_SUCCESS
2189 * Failure: Error code
2191 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2193 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2194 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2198 /******************************************************************************
2199 * RegOpenKey32A [ADVAPI32.148]
2201 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2204 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2205 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2206 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2212 /******************************************************************************
2213 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2215 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2217 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2218 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2225 * All those functions convert their respective
2226 * arguments and call RegCreateKeyExW at the end.
2228 * We stay away from the Ex functions as long as possible because there are
2229 * differences in the return values
2232 * RegCreateKeyEx32A \
2233 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2237 /******************************************************************************
2238 * RegCreateKeyEx32W [ADVAPI32.131]
2241 * hkey [I] Handle of an open key
2242 * lpszSubKey [I] Address of subkey name
2243 * dwReserved [I] Reserved - must be 0
2244 * lpszClass [I] Address of class string
2245 * fdwOptions [I] Special options flag
2246 * samDesired [I] Desired security access
2247 * lpSecAttribs [I] Address of key security structure
2248 * retkey [O] Address of buffer for opened handle
2249 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2251 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2252 DWORD dwReserved
, LPWSTR lpszClass
,
2253 DWORD fdwOptions
, REGSAM samDesired
,
2254 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2255 LPHKEY retkey
, LPDWORD lpDispos
)
2257 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2261 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2262 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2263 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2265 lpNextKey
= lookup_hkey(hkey
);
2267 return ERROR_INVALID_HANDLE
;
2269 /* Check for valid options */
2270 switch(fdwOptions
) {
2271 case REG_OPTION_NON_VOLATILE
:
2272 case REG_OPTION_VOLATILE
:
2273 case REG_OPTION_BACKUP_RESTORE
:
2276 return ERROR_INVALID_PARAMETER
;
2279 /* Sam has to be a combination of the following */
2281 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2282 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2283 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2284 return ERROR_INVALID_PARAMETER
;
2286 if (!lpszSubKey
|| !*lpszSubKey
) {
2288 add_handle(currenthandle
,lpNextKey
,samDesired
);
2289 *retkey
=currenthandle
;
2290 TRACE(reg
, "Returning %x\n", currenthandle
);
2291 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2292 return ERROR_SUCCESS
;
2295 if (lpszSubKey
[0] == '\\') {
2296 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2297 return ERROR_BAD_PATHNAME
;
2300 split_keypath(lpszSubKey
,&wps
,&wpc
);
2302 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2305 lpxkey
=lpNextKey
->nextsub
;
2307 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2309 lpxkey
=lpxkey
->next
;
2318 add_handle(currenthandle
,lpxkey
,samDesired
);
2319 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2320 *retkey
= currenthandle
;
2321 TRACE(reg
, "Returning %x\n", currenthandle
);
2323 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2325 return ERROR_SUCCESS
;
2328 /* Good. Now the hard part */
2330 lplpPrevKey
= &(lpNextKey
->nextsub
);
2331 lpxkey
= *lplpPrevKey
;
2333 lplpPrevKey
= &(lpxkey
->next
);
2334 lpxkey
= *lplpPrevKey
;
2336 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2337 if (!*lplpPrevKey
) {
2339 TRACE(reg
, "Returning OUTOFMEMORY\n");
2340 return ERROR_OUTOFMEMORY
;
2342 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2343 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
2344 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2345 (*lplpPrevKey
)->next
= NULL
;
2346 (*lplpPrevKey
)->nextsub
= NULL
;
2347 (*lplpPrevKey
)->values
= NULL
;
2348 (*lplpPrevKey
)->nrofvalues
= 0;
2349 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2351 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2353 (*lplpPrevKey
)->class = NULL
;
2354 lpNextKey
= *lplpPrevKey
;
2358 add_handle(currenthandle
,lpNextKey
,samDesired
);
2360 /*FIXME: flag handling correct? */
2361 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2363 lpNextKey
->class = strdupW(lpszClass
);
2365 lpNextKey
->class = NULL
;
2366 *retkey
= currenthandle
;
2367 TRACE(reg
, "Returning %x\n", currenthandle
);
2369 *lpDispos
= REG_CREATED_NEW_KEY
;
2371 return ERROR_SUCCESS
;
2375 /******************************************************************************
2376 * RegCreateKeyEx32A [ADVAPI32.130]
2378 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2379 LPSTR lpszClass
, DWORD fdwOptions
,
2381 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2382 LPHKEY retkey
, LPDWORD lpDispos
)
2384 LPWSTR lpszSubKeyW
, lpszClassW
;
2387 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2388 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2391 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2392 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2394 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2395 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2398 if(lpszSubKeyW
) free(lpszSubKeyW
);
2399 if(lpszClassW
) free(lpszClassW
);
2405 /******************************************************************************
2406 * RegCreateKey32W [ADVAPI32.132]
2408 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2411 LPKEYSTRUCT lpNextKey
;
2413 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2415 /* This check is here because the return value is different than the
2416 one from the Ex functions */
2417 lpNextKey
= lookup_hkey(hkey
);
2419 return ERROR_BADKEY
;
2421 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2422 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2427 /******************************************************************************
2428 * RegCreateKey32A [ADVAPI32.129]
2430 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2435 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2436 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2437 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2438 if(lpszSubKeyW
) free(lpszSubKeyW
);
2443 /******************************************************************************
2444 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2446 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2448 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2449 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2454 * Query Value Functions
2455 * Win32 differs between keynames and valuenames.
2456 * multiple values may belong to one key, the special value
2457 * with name NULL is the default value used by the win31
2461 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2462 * RegQueryValue32W -> RegQueryValueEx32W
2466 /******************************************************************************
2467 * RegQueryValueEx32W [ADVAPI32.158]
2468 * Retrieves type and data for a specified name associated with an open key
2471 * hkey [I] Handle of key to query
2472 * lpValueName [I] Name of value to query
2473 * lpdwReserved [I] Reserved - must be NULL
2474 * lpdwType [O] Address of buffer for value type. If NULL, the type
2476 * lpbData [O] Address of data buffer. If NULL, the actual data is
2478 * lpcbData [I/O] Address of data buffer size
2481 * ERROR_SUCCESS: Success
2482 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2483 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2485 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2486 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2487 LPBYTE lpbData
, LPDWORD lpcbData
)
2493 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2494 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2496 lpkey
= lookup_hkey(hkey
);
2499 return ERROR_INVALID_HANDLE
;
2501 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2502 return ERROR_INVALID_PARAMETER
;
2504 /* An empty name string is equivalent to NULL */
2505 if (lpValueName
&& !*lpValueName
)
2508 if (lpValueName
==NULL
)
2509 { /* Use key's unnamed or default value, if any */
2510 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2511 if (lpkey
->values
[i
].name
==NULL
)
2515 { /* Search for the key name */
2516 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2517 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2521 if (i
==lpkey
->nrofvalues
)
2522 { TRACE(reg
," Key not found\n");
2523 if (lpValueName
==NULL
)
2524 { /* Empty keyname not found */
2526 { *(WCHAR
*)lpbData
= 0;
2531 TRACE(reg
, " Returning an empty string\n");
2532 return ERROR_SUCCESS
;
2534 return ERROR_FILE_NOT_FOUND
;
2537 ret
= ERROR_SUCCESS
;
2539 if (lpdwType
) /* type required ?*/
2540 *lpdwType
= lpkey
->values
[i
].type
;
2542 if (lpbData
) /* data required ?*/
2543 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2544 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2546 ret
= ERROR_MORE_DATA
;
2549 if (lpcbData
) /* size required ?*/
2550 { *lpcbData
= lpkey
->values
[i
].len
;
2553 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2555 TRACE(reg
," (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2561 /******************************************************************************
2562 * RegQueryValue32W [ADVAPI32.159]
2564 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2570 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2571 lpcbData
?*lpcbData
:0);
2573 /* Only open subkey, if we really do descend */
2574 if (lpszSubKey
&& *lpszSubKey
) {
2575 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2576 if (ret
!= ERROR_SUCCESS
) {
2577 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2584 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2592 /******************************************************************************
2593 * RegQueryValueEx32A [ADVAPI32.157]
2596 * the documantation is wrong: if the buffer is to small it remains untouched
2598 * FIXME: check returnvalue (len) for an empty key
2600 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2601 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2602 LPBYTE lpbData
, LPDWORD lpcbData
)
2604 LPWSTR lpszValueNameW
;
2605 LPBYTE mybuf
= NULL
;
2606 DWORD ret
, mytype
, mylen
= 0;
2608 TRACE(reg
,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2609 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2611 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2612 { return ERROR_INVALID_PARAMETER
;
2615 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2617 /* get just the type first */
2618 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2620 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2621 { if(lpszValueNameW
) free(lpszValueNameW
);
2625 if (lpcbData
) /* at least length requested? */
2626 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2627 { if (lpbData
) /* value requested? */
2628 { mylen
= 2*( *lpcbData
);
2629 mybuf
= (LPBYTE
)xmalloc( mylen
);
2632 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2634 if (ret
== ERROR_SUCCESS
)
2636 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2640 *lpcbData
= mylen
/2; /* size is in byte! */
2642 else /* no strings, call it straight */
2643 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2647 if (lpdwType
) /* type when requested */
2648 { *lpdwType
= mytype
;
2651 TRACE(reg
," (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2653 if(mybuf
) free(mybuf
);
2654 if(lpszValueNameW
) free(lpszValueNameW
);
2659 /******************************************************************************
2660 * RegQueryValueEx16 [KERNEL.225]
2662 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2663 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2664 LPBYTE lpbData
, LPDWORD lpcbData
)
2666 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2667 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2668 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2669 lpbData
, lpcbData
);
2673 /******************************************************************************
2674 * RegQueryValue32A [ADVAPI32.156]
2676 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2682 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2683 lpcbData
?*lpcbData
:0);
2685 if (lpszSubKey
&& *lpszSubKey
) {
2686 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2687 if( ret
!= ERROR_SUCCESS
)
2693 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2696 RegCloseKey( xhkey
);
2701 /******************************************************************************
2702 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2705 * Is this HACK still applicable?
2708 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2709 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2712 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2715 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2716 lpcbData
?*lpcbData
:0);
2719 *lpcbData
&= 0xFFFF;
2720 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2725 * Setting values of Registry keys
2728 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2729 * RegSetValue32W -> RegSetValueEx32W
2733 /******************************************************************************
2734 * RegSetValueEx32W [ADVAPI32.170]
2735 * Sets the data and type of a value under a register key
2738 * hkey [I] Handle of key to set value for
2739 * lpszValueName [I] Name of value to set
2740 * dwReserved [I] Reserved - must be zero
2741 * dwType [I] Flag for value type
2742 * lpbData [I] Address of value data
2743 * cbData [I] Size of value data
2746 * Success: ERROR_SUCCESS
2747 * Failure: Error code
2750 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2752 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2753 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2759 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2760 dwReserved
, dwType
, lpbData
, cbData
);
2762 lpkey
= lookup_hkey( hkey
);
2765 return ERROR_INVALID_HANDLE
;
2767 lpkey
->flags
|= REG_OPTION_TAINTED
;
2769 if (lpszValueName
==NULL
) {
2770 /* Sets type and name for key's unnamed or default value */
2771 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2772 if (lpkey
->values
[i
].name
==NULL
)
2775 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2776 if ( lpkey
->values
[i
].name
&&
2777 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2781 if (i
==lpkey
->nrofvalues
) {
2782 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2784 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2786 lpkey
->nrofvalues
++;
2787 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2789 if (lpkey
->values
[i
].name
==NULL
) {
2791 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2793 lpkey
->values
[i
].name
= NULL
;
2796 if (dwType
== REG_SZ
)
2797 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2799 lpkey
->values
[i
].len
= cbData
;
2800 lpkey
->values
[i
].type
= dwType
;
2801 if (lpkey
->values
[i
].data
!=NULL
)
2802 free(lpkey
->values
[i
].data
);
2803 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2804 lpkey
->values
[i
].lastmodified
= time(NULL
);
2805 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2806 return ERROR_SUCCESS
;
2810 /******************************************************************************
2811 * RegSetValueEx32A [ADVAPI32.169]
2814 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2816 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2817 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2821 LPWSTR lpszValueNameW
;
2825 return (ERROR_INVALID_PARAMETER
);
2827 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2828 dwReserved
,dwType
,lpbData
,cbData
);
2830 if ((1<<dwType
) & UNICONVMASK
)
2831 { if (dwType
== REG_SZ
)
2832 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2834 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2835 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2842 lpszValueNameW
= strdupA2W(lpszValueName
);
2844 lpszValueNameW
= NULL
;
2846 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2849 free(lpszValueNameW
);
2858 /******************************************************************************
2859 * RegSetValueEx16 [KERNEL.226]
2861 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2862 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2864 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2865 dwReserved
,dwType
,lpbData
,cbData
);
2866 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2871 /******************************************************************************
2872 * RegSetValue32W [ADVAPI32.171]
2874 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2875 LPCWSTR lpszData
, DWORD cbData
)
2880 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2881 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2883 if (lpszSubKey
&& *lpszSubKey
) {
2884 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2885 if (ret
!=ERROR_SUCCESS
)
2889 if (dwType
!=REG_SZ
) {
2890 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2893 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2894 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2895 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2897 cbData
=2*lstrlenW(lpszData
)+2;
2899 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2906 /******************************************************************************
2907 * RegSetValue32A [ADVAPI32.168]
2910 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2911 LPCSTR lpszData
, DWORD cbData
)
2916 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2917 if (lpszSubKey
&& *lpszSubKey
) {
2918 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2919 if (ret
!=ERROR_SUCCESS
)
2924 if (dwType
!=REG_SZ
) {
2925 TRACE(reg
,"dwType=%ld!\n",dwType
);
2928 if (cbData
!=strlen(lpszData
)+1)
2929 cbData
=strlen(lpszData
)+1;
2930 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2937 /******************************************************************************
2938 * RegSetValue16 [KERNEL.221] [SHELL.5]
2940 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2941 LPCSTR lpszData
, DWORD cbData
)
2943 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2944 debugstr_a(lpszData
),cbData
);
2945 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2953 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2954 * RegEnumKey32W -> RegEnumKeyEx32W
2958 /******************************************************************************
2959 * RegEnumKeyEx32W [ADVAPI32.139]
2962 * hkey [I] Handle to key to enumerate
2963 * iSubKey [I] Index of subkey to enumerate
2964 * lpszName [O] Buffer for subkey name
2965 * lpcchName [O] Size of subkey buffer
2966 * lpdwReserved [I] Reserved
2967 * lpszClass [O] Buffer for class string
2968 * lpcchClass [O] Size of class buffer
2969 * ft [O] Time key last written to
2971 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2972 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2973 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2976 LPKEYSTRUCT lpkey
,lpxkey
;
2978 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2979 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2981 lpkey
= lookup_hkey( hkey
);
2983 return ERROR_INVALID_HANDLE
;
2985 if (!lpkey
->nextsub
)
2986 return ERROR_NO_MORE_ITEMS
;
2987 lpxkey
=lpkey
->nextsub
;
2989 /* Traverse the subkeys */
2990 while (iSubkey
&& lpxkey
) {
2992 lpxkey
=lpxkey
->next
;
2995 if (iSubkey
|| !lpxkey
)
2996 return ERROR_NO_MORE_ITEMS
;
2997 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
2998 return ERROR_MORE_DATA
;
2999 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
3002 *lpcchName
= lstrlenW(lpszName
);
3005 /* FIXME: what should we write into it? */
3009 return ERROR_SUCCESS
;
3013 /******************************************************************************
3014 * RegEnumKey32W [ADVAPI32.140]
3016 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3021 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3022 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
3026 /******************************************************************************
3027 * RegEnumKeyEx32A [ADVAPI32.138]
3029 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3030 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3031 LPSTR lpszClass
, LPDWORD lpcchClass
,
3034 DWORD ret
,lpcchNameW
,lpcchClassW
;
3035 LPWSTR lpszNameW
,lpszClassW
;
3038 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3039 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3042 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3043 lpcchNameW
= *lpcchName
;
3049 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3050 lpcchClassW
= *lpcchClass
;
3065 if (ret
==ERROR_SUCCESS
) {
3066 lstrcpyWtoA(lpszName
,lpszNameW
);
3067 *lpcchName
=strlen(lpszName
);
3069 lstrcpyWtoA(lpszClass
,lpszClassW
);
3070 *lpcchClass
=strlen(lpszClass
);
3081 /******************************************************************************
3082 * RegEnumKey32A [ADVAPI32.137]
3084 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3089 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3090 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3095 /******************************************************************************
3096 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3098 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3101 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3102 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3107 * Enumerate Registry Values
3110 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3114 /******************************************************************************
3115 * RegEnumValue32W [ADVAPI32.142]
3118 * hkey [I] Handle to key to query
3119 * iValue [I] Index of value to query
3120 * lpszValue [O] Value string
3121 * lpcchValue [I/O] Size of value buffer (in wchars)
3122 * lpdReserved [I] Reserved
3123 * lpdwType [O] Type code
3124 * lpbData [O] Value data
3125 * lpcbData [I/O] Size of data buffer (in bytes)
3127 * Note: wide character functions that take and/or return "character counts"
3128 * use TCHAR (that is unsigned short or char) not byte counts.
3130 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3131 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3132 LPDWORD lpdwType
, LPBYTE lpbData
,
3138 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3139 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3141 lpkey
= lookup_hkey( hkey
);
3143 if (!lpcbData
&& lpbData
)
3144 return ERROR_INVALID_PARAMETER
;
3147 return ERROR_INVALID_HANDLE
;
3149 if (lpkey
->nrofvalues
<= iValue
)
3150 return ERROR_NO_MORE_ITEMS
;
3152 val
= &(lpkey
->values
[iValue
]);
3155 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3156 *lpcchValue
= lstrlenW(val
->name
)+1;
3157 return ERROR_MORE_DATA
;
3159 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3160 *lpcchValue
=lstrlenW(val
->name
);
3166 /* Can be NULL if the type code is not required */
3168 *lpdwType
= val
->type
;
3171 if (val
->len
>*lpcbData
)
3172 return ERROR_MORE_DATA
;
3173 memcpy(lpbData
,val
->data
,val
->len
);
3174 *lpcbData
= val
->len
;
3177 debug_print_value ( val
->data
, val
);
3178 return ERROR_SUCCESS
;
3182 /******************************************************************************
3183 * RegEnumValue32A [ADVAPI32.141]
3185 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3186 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3187 LPDWORD lpdwType
, LPBYTE lpbData
,
3192 DWORD ret
,lpcbDataW
;
3195 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3196 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3198 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3200 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3201 lpcbDataW
= *lpcbData
;
3205 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3206 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3211 if (ret
==ERROR_SUCCESS
) {
3212 lstrcpyWtoA(lpszValue
,lpszValueW
);
3214 if ((1<<dwType
) & UNICONVMASK
) {
3215 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3217 if (lpcbDataW
> *lpcbData
)
3218 ret
= ERROR_MORE_DATA
;
3220 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3222 *lpcbData
= lpcbDataW
;
3225 if (lpbDataW
) free(lpbDataW
);
3226 if (lpszValueW
) free(lpszValueW
);
3231 /******************************************************************************
3232 * RegEnumValue16 [KERNEL.223]
3234 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3235 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3236 LPDWORD lpdwType
, LPBYTE lpbData
,
3239 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3240 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3241 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3242 lpdwType
, lpbData
, lpcbData
);
3246 /******************************************************************************
3247 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3248 * Releases the handle of the specified key
3251 * hkey [I] Handle of key to close
3254 * Success: ERROR_SUCCESS
3255 * Failure: Error code
3257 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3259 TRACE(reg
,"(%x)\n",hkey
);
3261 /* The standard handles are allowed to succeed, even though they are not
3263 if (is_standard_hkey(hkey
))
3264 return ERROR_SUCCESS
;
3266 return remove_handle(hkey
);
3271 * Delete registry key
3274 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3278 /******************************************************************************
3279 * RegDeleteKey32W [ADVAPI32.134]
3282 * hkey [I] Handle to open key
3283 * lpszSubKey [I] Name of subkey to delete
3286 * Success: ERROR_SUCCESS
3287 * Failure: Error code
3289 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3291 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3295 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3297 lpNextKey
= lookup_hkey(hkey
);
3299 return ERROR_INVALID_HANDLE
;
3301 /* Subkey param cannot be NULL */
3302 if (!lpszSubKey
|| !*lpszSubKey
)
3303 return ERROR_BADKEY
;
3305 /* We need to know the previous key in the hier. */
3306 split_keypath(lpszSubKey
,&wps
,&wpc
);
3310 lpxkey
=lpNextKey
->nextsub
;
3312 TRACE(reg
, " Scanning [%s]\n",
3313 debugstr_w(lpxkey
->keyname
));
3314 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3316 lpxkey
=lpxkey
->next
;
3320 TRACE(reg
, " Not found.\n");
3321 /* not found is success */
3322 return ERROR_SUCCESS
;
3327 lpxkey
= lpNextKey
->nextsub
;
3328 lplpPrevKey
= &(lpNextKey
->nextsub
);
3330 TRACE(reg
, " Scanning [%s]\n",
3331 debugstr_w(lpxkey
->keyname
));
3332 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3334 lplpPrevKey
= &(lpxkey
->next
);
3335 lpxkey
= lpxkey
->next
;
3340 WARN(reg
, " Not found.\n");
3341 return ERROR_FILE_NOT_FOUND
;
3344 if (lpxkey
->nextsub
) {
3346 WARN(reg
, " Not empty.\n");
3347 return ERROR_CANTWRITE
;
3349 *lplpPrevKey
= lpxkey
->next
;
3350 free(lpxkey
->keyname
);
3352 free(lpxkey
->class);
3354 free(lpxkey
->values
);
3357 TRACE(reg
, " Done.\n");
3358 return ERROR_SUCCESS
;
3362 /******************************************************************************
3363 * RegDeleteKey32A [ADVAPI32.133]
3365 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3370 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3371 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3372 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3373 if(lpszSubKeyW
) free(lpszSubKeyW
);
3378 /******************************************************************************
3379 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3381 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3383 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3384 return RegDeleteKeyA( hkey
, lpszSubKey
);
3389 * Delete registry value
3392 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3396 /******************************************************************************
3397 * RegDeleteValue32W [ADVAPI32.136]
3405 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3411 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3413 lpkey
= lookup_hkey( hkey
);
3415 return ERROR_INVALID_HANDLE
;
3418 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3419 if ( lpkey
->values
[i
].name
&&
3420 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3424 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3425 if (lpkey
->values
[i
].name
==NULL
)
3429 if (i
== lpkey
->nrofvalues
)
3430 return ERROR_FILE_NOT_FOUND
;
3432 val
= lpkey
->values
+i
;
3433 if (val
->name
) free(val
->name
);
3434 if (val
->data
) free(val
->data
);
3438 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3440 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3442 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3444 lpkey
->nrofvalues
--;
3445 return ERROR_SUCCESS
;
3449 /******************************************************************************
3450 * RegDeleteValue32A [ADVAPI32.135]
3452 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3457 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3458 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3459 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3460 if(lpszValueW
) free(lpszValueW
);
3465 /******************************************************************************
3466 * RegDeleteValue16 [KERNEL.222]
3468 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3470 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3471 return RegDeleteValueA( hkey
, lpszValue
);
3475 /******************************************************************************
3476 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3477 * Writes key to registry
3480 * hkey [I] Handle of key to write
3483 * Success: ERROR_SUCCESS
3484 * Failure: Error code
3486 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3491 TRACE(reg
, "(%x)\n", hkey
);
3493 lpkey
= lookup_hkey( hkey
);
3495 return ERROR_BADKEY
;
3497 ERR(reg
, "What is the correct filename?\n");
3499 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3502 return ERROR_SUCCESS
;
3504 return ERROR_UNKNOWN
; /* FIXME */
3508 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3511 /******************************************************************************
3512 * RegQueryInfoKey32W [ADVAPI32.153]
3515 * hkey [I] Handle to key to query
3516 * lpszClass [O] Buffer for class string
3517 * lpcchClass [O] Size of class string buffer
3518 * lpdwReserved [I] Reserved
3519 * lpcSubKeys [I] Buffer for number of subkeys
3520 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3521 * lpcchMaxClass [O] Buffer for longest class string length
3522 * lpcValues [O] Buffer for number of value entries
3523 * lpcchMaxValueName [O] Buffer for longest value name length
3524 * lpccbMaxValueData [O] Buffer for longest value data length
3525 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3527 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3528 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3529 * lpcchClass is NULL
3530 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3531 * (it's hard to test validity, so test !NULL instead)
3533 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3534 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3535 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3536 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3537 LPDWORD lpcchMaxValueName
,
3538 LPDWORD lpccbMaxValueData
,
3539 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3541 LPKEYSTRUCT lpkey
,lpxkey
;
3542 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3545 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3546 lpkey
= lookup_hkey(hkey
);
3548 return ERROR_INVALID_HANDLE
;
3550 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3551 return ERROR_INVALID_PARAMETER
;
3553 /* either lpcchClass is valid or this is win95 and lpcchClass
3556 DWORD classLen
= lstrlenW(lpkey
->class);
3558 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3559 *lpcchClass
=classLen
+1;
3560 return ERROR_MORE_DATA
;
3563 *lpcchClass
=classLen
;
3564 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3572 *lpcchClass
= lstrlenW(lpkey
->class);
3574 lpxkey
=lpkey
->nextsub
;
3575 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3578 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3579 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3580 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3581 maxclass
=lstrlenW(lpxkey
->class);
3582 lpxkey
=lpxkey
->next
;
3584 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3585 LPKEYVALUE val
=lpkey
->values
+i
;
3587 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3588 maxvname
=lstrlenW(val
->name
);
3589 if (val
->len
>maxvdata
)
3592 if (!maxclass
) maxclass
= 1;
3593 if (!maxvname
) maxvname
= 1;
3595 *lpcValues
= lpkey
->nrofvalues
;
3597 *lpcSubKeys
= nrofkeys
;
3599 *lpcchMaxSubkey
= maxsubkey
;
3601 *lpcchMaxClass
= maxclass
;
3602 if (lpcchMaxValueName
)
3603 *lpcchMaxValueName
= maxvname
;
3604 if (lpccbMaxValueData
)
3605 *lpccbMaxValueData
= maxvdata
;
3606 return ERROR_SUCCESS
;
3610 /******************************************************************************
3611 * RegQueryInfoKey32A [ADVAPI32.152]
3613 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3614 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3615 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3616 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3617 LPDWORD lpccbMaxValueData
,
3618 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3620 LPWSTR lpszClassW
= NULL
;
3623 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3626 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3627 } else if (VERSION_GetVersion() == WIN95
) {
3628 /* win95 allows lpcchClass to be null */
3629 /* we don't know how big lpszClass is, would
3630 MAX_PATHNAME_LEN be the correct default? */
3631 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3636 ret
=RegQueryInfoKeyW(
3647 lpcbSecurityDescriptor
,
3650 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3651 lstrcpyWtoA(lpszClass
,lpszClassW
);
3658 /******************************************************************************
3659 * RegConnectRegistry32W [ADVAPI32.128]
3662 * lpMachineName [I] Address of name of remote computer
3663 * hHey [I] Predefined registry handle
3664 * phkResult [I] Address of buffer for remote registry handle
3666 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3669 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3671 if (!lpMachineName
|| !*lpMachineName
) {
3672 /* Use the local machine name */
3673 return RegOpenKey16( hKey
, "", phkResult
);
3676 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3677 return ERROR_BAD_NETPATH
;
3681 /******************************************************************************
3682 * RegConnectRegistry32A [ADVAPI32.127]
3684 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3687 LPWSTR machineW
= strdupA2W(machine
);
3688 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3694 /******************************************************************************
3695 * RegGetKeySecurity [ADVAPI32.144]
3696 * Retrieves a copy of security descriptor protecting the registry key
3699 * hkey [I] Open handle of key to set
3700 * SecurityInformation [I] Descriptor contents
3701 * pSecurityDescriptor [O] Address of descriptor for key
3702 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3705 * Success: ERROR_SUCCESS
3706 * Failure: Error code
3708 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3709 SECURITY_INFORMATION SecurityInformation
,
3710 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3711 LPDWORD lpcbSecurityDescriptor
)
3715 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3716 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3718 lpkey
= lookup_hkey( hkey
);
3720 return ERROR_INVALID_HANDLE
;
3722 /* FIXME: Check for valid SecurityInformation values */
3724 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3725 return ERROR_INSUFFICIENT_BUFFER
;
3727 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3728 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3730 return ERROR_SUCCESS
;
3734 /******************************************************************************
3735 * RegLoadKey32W [ADVAPI32.???]
3738 * hkey [I] Handle of open key
3739 * lpszSubKey [I] Address of name of subkey
3740 * lpszFile [I] Address of filename for registry information
3742 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3745 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3747 /* Do this check before the hkey check */
3748 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3749 return ERROR_INVALID_PARAMETER
;
3751 lpkey
= lookup_hkey( hkey
);
3753 return ERROR_INVALID_HANDLE
;
3755 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3756 debugstr_w(lpszFile
));
3758 return ERROR_SUCCESS
;
3762 /******************************************************************************
3763 * RegLoadKey32A [ADVAPI32.???]
3765 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3768 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3769 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3770 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3771 if(lpszFileW
) free(lpszFileW
);
3772 if(lpszSubKeyW
) free(lpszSubKeyW
);
3777 /******************************************************************************
3778 * RegNotifyChangeKeyValue [ADVAPI32.???]
3781 * hkey [I] Handle of key to watch
3782 * fWatchSubTree [I] Flag for subkey notification
3783 * fdwNotifyFilter [I] Changes to be reported
3784 * hEvent [I] Handle of signaled event
3785 * fAsync [I] Flag for asynchronous reporting
3787 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3788 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3792 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3795 lpkey
= lookup_hkey( hkey
);
3797 return ERROR_INVALID_HANDLE
;
3799 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3802 return ERROR_SUCCESS
;
3806 /******************************************************************************
3807 * RegUnLoadKey32W [ADVAPI32.173]
3810 * hkey [I] Handle of open key
3811 * lpSubKey [I] Address of name of subkey to unload
3813 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3815 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3816 return ERROR_SUCCESS
;
3820 /******************************************************************************
3821 * RegUnLoadKey32A [ADVAPI32.172]
3823 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3826 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3827 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3828 if(lpSubKeyW
) free(lpSubKeyW
);
3833 /******************************************************************************
3834 * RegSetKeySecurity [ADVAPI32.167]
3837 * hkey [I] Open handle of key to set
3838 * SecurityInfo [I] Descriptor contents
3839 * pSecurityDesc [I] Address of descriptor for key
3841 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3842 PSECURITY_DESCRIPTOR pSecurityDesc
)
3846 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3848 /* It seems to perform this check before the hkey check */
3849 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3850 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3851 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3852 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3855 return ERROR_INVALID_PARAMETER
;
3858 return ERROR_INVALID_PARAMETER
;
3860 lpkey
= lookup_hkey( hkey
);
3862 return ERROR_INVALID_HANDLE
;
3864 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3866 return ERROR_SUCCESS
;
3870 /******************************************************************************
3871 * RegSaveKey32W [ADVAPI32.166]
3874 * hkey [I] Handle of key where save begins
3875 * lpFile [I] Address of filename to save to
3876 * sa [I] Address of security structure
3878 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3879 LPSECURITY_ATTRIBUTES sa
)
3883 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3885 /* It appears to do this check before the hkey check */
3886 if (!lpFile
|| !*lpFile
)
3887 return ERROR_INVALID_PARAMETER
;
3889 lpkey
= lookup_hkey( hkey
);
3891 return ERROR_INVALID_HANDLE
;
3893 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3895 return ERROR_SUCCESS
;
3899 /******************************************************************************
3900 * RegSaveKey32A [ADVAPI32.165]
3902 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3903 LPSECURITY_ATTRIBUTES sa
)
3906 LPWSTR lpFileW
= strdupA2W(lpFile
);
3907 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3913 /******************************************************************************
3914 * RegRestoreKey32W [ADVAPI32.164]
3917 * hkey [I] Handle of key where restore begins
3918 * lpFile [I] Address of filename containing saved tree
3919 * dwFlags [I] Optional flags
3921 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3925 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3927 /* It seems to do this check before the hkey check */
3928 if (!lpFile
|| !*lpFile
)
3929 return ERROR_INVALID_PARAMETER
;
3931 lpkey
= lookup_hkey( hkey
);
3933 return ERROR_INVALID_HANDLE
;
3935 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3937 /* Check for file existence */
3939 return ERROR_SUCCESS
;
3943 /******************************************************************************
3944 * RegRestoreKey32A [ADVAPI32.163]
3946 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3949 LPWSTR lpFileW
= strdupA2W(lpFile
);
3950 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3951 if(lpFileW
) free(lpFileW
);
3956 /******************************************************************************
3957 * RegReplaceKey32W [ADVAPI32.162]
3960 * hkey [I] Handle of open key
3961 * lpSubKey [I] Address of name of subkey
3962 * lpNewFile [I] Address of filename for file with new data
3963 * lpOldFile [I] Address of filename for backup file
3965 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3970 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3971 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3973 lpkey
= lookup_hkey( hkey
);
3975 return ERROR_INVALID_HANDLE
;
3977 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3978 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3980 return ERROR_SUCCESS
;
3984 /******************************************************************************
3985 * RegReplaceKey32A [ADVAPI32.161]
3987 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3991 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3992 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3993 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3994 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);