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 #ifdef HAVE_SYS_ERRNO_H
28 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
37 #include "wine/winbase16.h"
38 #include "wine/winestring.h"
42 #include "debugtools.h"
46 #include "winversion.h"
48 DECLARE_DEBUG_CHANNEL(reg
)
49 DECLARE_DEBUG_CHANNEL(string
)
51 static void REGISTRY_Init(void);
52 /* FIXME: following defines should be configured global ... */
54 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
55 #define WINE_PREFIX "/.wine"
56 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
57 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
59 /* relative in ~user/.wine/ : */
60 #define SAVE_CURRENT_USER "user.reg"
61 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
62 #define SAVE_LOCAL_MACHINE "system.reg"
64 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
65 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
67 /* one value of a key */
68 typedef struct tagKEYVALUE
70 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
71 DWORD type
; /* type of value */
72 DWORD len
; /* length of data in BYTEs */
73 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
74 LPBYTE data
; /* content, may be strings, binaries, etc. */
75 } KEYVALUE
,*LPKEYVALUE
;
78 typedef struct tagKEYSTRUCT
80 LPWSTR keyname
; /* name of THIS key (UNICODE) */
81 DWORD flags
; /* flags. */
84 DWORD nrofvalues
; /* nr of values in THIS key */
85 LPKEYVALUE values
; /* values in THIS key */
86 /* key management pointers */
87 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
88 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
89 } KEYSTRUCT
, *LPKEYSTRUCT
;
92 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
93 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
94 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
95 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
97 /* dynamic, not saved */
98 static KEYSTRUCT
*key_performance_data
=NULL
;
99 static KEYSTRUCT
*key_current_config
=NULL
;
100 static KEYSTRUCT
*key_dyn_data
=NULL
;
102 /* what valuetypes do we need to convert? */
103 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
106 static struct openhandle
{
111 static int nrofopenhandles
=0;
112 /* Starts after 1 because 0,1 are reserved for Win16 */
113 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
114 HKEYs for remote registry access */
115 static int currenthandle
=2;
120 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
121 * If so, can we remove them?
123 * No, the memory handling functions are called very often in here,
124 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
125 * loading 100 times slower. -MM
127 static LPWSTR
strdupA2W(LPCSTR src
)
130 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
131 lstrcpyAtoW(dest
,src
);
137 static LPWSTR
strdupW(LPCWSTR a
) {
142 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
143 b
=(LPWSTR
)xmalloc(len
);
150 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
153 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
155 lstrcpynAtoW(dest
,src
,nchars
+1);
160 * we need to convert A to W with '\0' in strings (MULTI_SZ)
163 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
166 TRACE_(reg
)("\"%s\" %i\n",src
, n
);
168 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
172 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
175 TRACE_(string
)("L\"%s\" %i\n",debugstr_w(src
), n
);
177 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
182 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
184 if (TRACE_ON(reg
) && lpbData
)
190 TRACE_(reg
)(" Value %s, Data(sz)=%s\n",
191 debugstr_w(key
->name
),
192 debugstr_w((LPCWSTR
)lpbData
));
196 TRACE_(reg
)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key
->name
),
204 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
207 TRACE_(reg
)(" Value %s, MULTI_SZ(%i=%s)\n",
208 debugstr_w(key
->name
),
212 ptr
+= lstrlenW(ptr
)+1;
219 char szTemp
[100]; /* 3*32 + 3 + 1 */
221 for ( i
= 0; i
< key
->len
; i
++)
223 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
226 sprintf (&(szTemp
[i
*3+3]),"...");
230 TRACE_(reg
)(" Value %s, Data(raw)=(%s)\n",
231 debugstr_w(key
->name
),
239 /******************************************************************************
240 * is_standard_hkey [Internal]
241 * Determines if a hkey is a standard key
243 static BOOL
is_standard_hkey( HKEY hkey
)
248 case HKEY_CLASSES_ROOT
:
249 case HKEY_CURRENT_CONFIG
:
250 case HKEY_CURRENT_USER
:
251 case HKEY_LOCAL_MACHINE
:
253 case HKEY_PERFORMANCE_DATA
:
261 /******************************************************************************
262 * add_handle [Internal]
264 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
268 TRACE_(reg
)("(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
269 /* Check for duplicates */
270 for (i
=0;i
<nrofopenhandles
;i
++) {
271 if (openhandles
[i
].lpkey
==lpkey
) {
272 /* This is not really an error - the user is allowed to create
273 two (or more) handles to the same key */
274 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
276 if (openhandles
[i
].hkey
==hkey
) {
277 WARN_(reg
)("Adding handle %x twice\n",hkey
);
280 openhandles
=xrealloc( openhandles
,
281 sizeof(struct openhandle
)*(nrofopenhandles
+1));
283 openhandles
[i
].lpkey
= lpkey
;
284 openhandles
[i
].hkey
= hkey
;
285 openhandles
[i
].accessmask
= accessmask
;
290 /******************************************************************************
291 * get_handle [Internal]
294 * Success: Pointer to key
297 static LPKEYSTRUCT
get_handle( HKEY hkey
)
301 for (i
=0; i
<nrofopenhandles
; i
++)
302 if (openhandles
[i
].hkey
== hkey
)
303 return openhandles
[i
].lpkey
;
304 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
309 /******************************************************************************
310 * remove_handle [Internal]
313 * hkey [I] Handle of key to remove
316 * Success: ERROR_SUCCESS
317 * Failure: ERROR_INVALID_HANDLE
319 static DWORD
remove_handle( HKEY hkey
)
323 for (i
=0;i
<nrofopenhandles
;i
++)
324 if (openhandles
[i
].hkey
==hkey
)
327 if (i
== nrofopenhandles
) {
328 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
329 return ERROR_INVALID_HANDLE
;
332 memcpy( openhandles
+i
,
334 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
336 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
338 return ERROR_SUCCESS
;
341 /******************************************************************************
342 * lookup_hkey [Internal]
344 * Just as the name says. Creates the root keys on demand, so we can call the
345 * Reg* functions at any time.
348 * Success: Pointer to key structure
351 #define ADD_ROOT_KEY(xx) \
352 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
353 memset(xx,'\0',sizeof(KEYSTRUCT));\
354 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
356 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
359 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
360 * some programs. Do not remove those cases. -MM
364 case HKEY_CLASSES_ROOT
:
366 if (!key_classes_root
)
370 /* calls lookup_hkey recursively, TWICE */
374 &cl_r_hkey
) != ERROR_SUCCESS
)
376 ERR_(reg
)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
380 key_classes_root
= lookup_hkey(cl_r_hkey
);
382 return key_classes_root
;
385 case HKEY_CURRENT_USER
:
386 if (!key_current_user
) {
387 ADD_ROOT_KEY(key_current_user
);
389 return key_current_user
;
391 case HKEY_LOCAL_MACHINE
:
392 if (!key_local_machine
) {
393 ADD_ROOT_KEY(key_local_machine
);
396 return key_local_machine
;
400 ADD_ROOT_KEY(key_users
);
404 case HKEY_PERFORMANCE_DATA
:
405 if (!key_performance_data
) {
406 ADD_ROOT_KEY(key_performance_data
);
408 return key_performance_data
;
412 ADD_ROOT_KEY(key_dyn_data
);
416 case HKEY_CURRENT_CONFIG
:
417 if (!key_current_config
) {
418 ADD_ROOT_KEY(key_current_config
);
420 return key_current_config
;
423 return get_handle(hkey
);
429 /* so we don't accidently access them ... */
430 #define key_current_config NULL NULL
431 #define key_current_user NULL NULL
432 #define key_users NULL NULL
433 #define key_local_machine NULL NULL
434 #define key_classes_root NULL NULL
435 #define key_dyn_data NULL NULL
436 #define key_performance_data NULL NULL
438 /******************************************************************************
439 * split_keypath [Internal]
440 * splits the unicode string 'wp' into an array of strings.
441 * the array is allocated by this function.
442 * Free the array using FREE_KEY_PATH
445 * wp [I] String to split up
446 * wpv [O] Array of pointers to strings
447 * wpc [O] Number of components
449 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
454 TRACE_(reg
)("(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
456 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
458 /* We know we have at least one substring */
461 /* Replace each backslash with NULL, and increment the count */
462 for (i
=0;ws
[i
];i
++) {
471 /* Allocate the space for the array of pointers, leaving room for the
473 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
476 /* Assign each pointer to the appropriate character in the string */
481 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
486 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
491 /******************************************************************************
492 * REGISTRY_Init [Internal]
493 * Registry initialisation, allocates some default keys.
495 static void REGISTRY_Init(void) {
499 TRACE_(reg
)("(void)\n");
501 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
504 /* This was an Open, but since it is called before the real registries
505 are loaded, it was changed to a Create - MTB 980507*/
506 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
507 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
510 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
514 * string RegisteredOwner
515 * string RegisteredOrganization
518 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
523 if (-1!=gethostname(buf
,200)) {
524 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
525 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
531 /************************ SAVE Registry Function ****************************/
533 #define REGISTRY_SAVE_VERSION 0x00000001
535 /* Registry saveformat:
536 * If you change it, increase above number by 1, which will flush
537 * old registry database files.
540 * "WINE REGISTRY Version %d"
544 * valuename=lastmodified,type,data
548 * keyname,valuename,stringdata:
549 * the usual ascii characters from 0x00-0xff (well, not 0x00)
550 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
551 * ( "=\\\t" escaped in \uXXXX form.)
555 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
557 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
558 * SaveOnlyUpdatedKeys=yes
561 /******************************************************************************
562 * _save_check_tainted [Internal]
564 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
570 if (lpkey
->flags
& REG_OPTION_TAINTED
)
575 if (_save_check_tainted(lpkey
->nextsub
)) {
576 lpkey
->flags
|= REG_OPTION_TAINTED
;
584 /******************************************************************************
585 * _save_USTRING [Internal]
587 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
601 if (escapeeq
&& *s
=='=')
604 fputc(*s
,F
); /* if \\ then put it twice. */
606 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
613 /******************************************************************************
614 * _savesubkey [Internal]
617 * REG_MULTI_SZ is handled as binary (like in win95) (js)
619 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
626 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
627 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
629 for (tabs
=level
;tabs
--;)
631 _save_USTRING(F
,lpxkey
->keyname
,1);
633 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
634 LPKEYVALUE val
=lpxkey
->values
+i
;
636 for (tabs
=level
+1;tabs
--;)
638 _save_USTRING(F
,val
->name
,0);
640 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
641 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
642 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
644 for (j
=0;j
<val
->len
;j
++)
645 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
648 /* descend recursively */
649 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
658 /******************************************************************************
659 * _savesubreg [Internal]
661 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
663 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
664 _save_check_tainted(lpkey
->nextsub
);
665 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
669 /******************************************************************************
670 * _savereg [Internal]
672 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
678 WARN_(reg
)("Couldn't open %s for writing: %s\n",
683 if (!_savesubreg(F
,lpkey
,all
)) {
686 WARN_(reg
)("Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
694 /******************************************************************************
695 * SHELL_SaveRegistry [Internal]
697 void SHELL_SaveRegistry( void )
699 char *fn
, *home
, *tmp
;
706 TRACE_(reg
)("(void)\n");
709 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
718 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
723 &len
)) || (type
!=REG_SZ
))
730 if (lstrcmpiA(buf
,"yes")) all
=1;
732 if (!(home
= getenv( "HOME" )))
734 WARN_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
738 * Save HKEY_CURRENT_USER
739 * Try first saving according to the defined location in .winerc
741 fn
= xmalloc( MAX_PATHNAME_LEN
);
742 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "", fn
, MAX_PATHNAME_LEN
- 1))
744 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
749 if (usedCfgUser
!= 1)
751 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
752 strlen(SAVE_CURRENT_USER
) + 2 );
754 strcat(fn
,WINE_PREFIX
);
756 /* create the directory. don't care about errorcodes. */
757 mkdir(fn
,0755); /* drwxr-xr-x */
758 strcat(fn
,"/"SAVE_CURRENT_USER
);
760 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
764 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
765 if (-1==rename(tmp
,fn
)) {
766 perror("rename tmp registry");
775 * Save HKEY_LOCAL_MACHINE
776 * Try first saving according to the defined location in .winerc
778 fn
= xmalloc ( MAX_PATHNAME_LEN
);
779 if (PROFILE_GetWineIniString ( "Registry", "LocalMachineFileName", "", fn
,
780 MAX_PATHNAME_LEN
- 1))
782 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
789 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_MACHINE
)+2);
791 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
793 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
797 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
798 if (-1==rename(tmp
,fn
)) {
799 perror("rename tmp registry");
810 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
813 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
815 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
816 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
817 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
818 if (-1==rename(tmp
,fn
)) {
819 perror("rename tmp registry");
828 /************************ LOAD Registry Function ****************************/
832 /******************************************************************************
833 * _find_or_add_key [Internal]
835 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
837 LPKEYSTRUCT lpxkey
,*lplpkey
;
839 if ((!keyname
) || (keyname
[0]==0)) {
843 lplpkey
= &(lpkey
->nextsub
);
846 if ( tolower(lpxkey
->keyname
[0])==tolower(keyname
[0]) &&
847 !lstrcmpiW(lpxkey
->keyname
,keyname
)
850 lplpkey
= &(lpxkey
->next
);
854 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
856 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
857 lpxkey
->keyname
= keyname
;
863 /******************************************************************************
864 * _find_or_add_value [Internal]
866 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
867 LPBYTE data
, DWORD len
, DWORD lastmodified
)
872 if (name
&& !*name
) {/* empty string equals default (NULL) value */
877 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
883 if ( val
->name
!=NULL
&&
884 tolower(val
->name
[0])==tolower(name
[0]) &&
885 !lstrcmpiW(val
->name
,name
)
890 if (i
==lpkey
->nrofvalues
) {
891 lpkey
->values
= xrealloc(
893 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
896 memset(val
,'\0',sizeof(KEYVALUE
));
902 if (val
->lastmodified
<lastmodified
) {
903 val
->lastmodified
=lastmodified
;
906 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && !data
){
908 data
=xmalloc(sizeof(WCHAR
));
909 memset(data
,0,sizeof(WCHAR
));
922 /******************************************************************************
923 * _wine_read_line [Internal]
925 * reads a line including dynamically enlarging the readbuffer and throwing
928 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
938 s
=fgets(curread
,mylen
,F
);
941 if (NULL
==(s
=strchr(curread
,'\n'))) {
942 /* buffer wasn't large enough */
943 curoff
= strlen(*buf
);
944 *buf
= xrealloc(*buf
,*len
*2);
945 curread
= *buf
+ curoff
;
946 mylen
= *len
; /* we filled up the buffer and
947 * got new '*len' bytes to fill
955 /* throw away comments */
956 if (**buf
=='#' || **buf
==';') {
961 if (s
) /* got end of line */
968 /******************************************************************************
969 * _wine_read_USTRING [Internal]
971 * converts a char* into a UNICODE string (up to a special char)
972 * and returns the position exactly after that string
974 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
979 /* read up to "=" or "\0" or "\n" */
982 /* empty string is the win3.1 default value(NULL)*/
986 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
988 while (*s
&& (*s
!='\n') && (*s
!='=')) {
990 *ws
++=*((unsigned char*)s
++);
994 /* Dangling \ ... may only happen if a registry
995 * write was short. FIXME: What do to?
1005 WARN_(reg
)("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1013 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1014 if (!sscanf(xbuf
,"%x",&wc
))
1015 WARN_(reg
)("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1017 *ws
++ =(unsigned short)wc
;
1024 *str
= strdupW(*str
);
1032 /******************************************************************************
1033 * _wine_loadsubkey [Internal]
1036 * It seems like this is returning a boolean. Should it?
1042 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1043 int *buflen
, DWORD optflag
)
1050 TRACE_(reg
)("(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1053 lpkey
->flags
|= optflag
;
1055 /* Good. We already got a line here ... so parse it */
1065 WARN_(reg
)("Got a subhierarchy without resp. key?\n");
1068 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1072 /* let the caller handle this line */
1073 if (i
<level
|| **buf
=='\0')
1076 /* it can be: a value or a keyname. Parse the name first */
1077 s
=_wine_read_USTRING(s
,&name
);
1079 /* switch() default: hack to avoid gotos */
1083 lpxkey
=_find_or_add_key(lpkey
,name
);
1086 int len
,lastmodified
,type
;
1089 WARN_(reg
)("Unexpected character: %c\n",*s
);
1093 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1094 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
1098 s
=strchr(s
,',');s
++;
1099 s
=strchr(s
,',');s
++;
1100 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1101 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1103 len
= lstrlenW((LPWSTR
)data
)*2+2;
1108 data
= (LPBYTE
)xmalloc(len
+1);
1109 for (i
=0;i
<len
;i
++) {
1111 if (*s
>='0' && *s
<='9')
1112 data
[i
]=(*s
-'0')<<4;
1113 if (*s
>='a' && *s
<='f')
1114 data
[i
]=(*s
-'a'+'\xa')<<4;
1115 if (*s
>='A' && *s
<='F')
1116 data
[i
]=(*s
-'A'+'\xa')<<4;
1118 if (*s
>='0' && *s
<='9')
1120 if (*s
>='a' && *s
<='f')
1121 data
[i
]|=*s
-'a'+'\xa';
1122 if (*s
>='A' && *s
<='F')
1123 data
[i
]|=*s
-'A'+'\xa';
1127 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1130 /* read the next line */
1131 if (!_wine_read_line(F
,buf
,buflen
))
1138 /******************************************************************************
1139 * _wine_loadsubreg [Internal]
1141 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1147 buf
=xmalloc(10);buflen
=10;
1148 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1152 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1156 if (ver
!=REGISTRY_SAVE_VERSION
) {
1157 TRACE_(reg
)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1161 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1165 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1174 /******************************************************************************
1175 * _wine_loadreg [Internal]
1177 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1181 TRACE_(reg
)("(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1185 WARN_(reg
)("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1188 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1196 /******************************************************************************
1197 * _flush_registry [Internal]
1199 * This function allow to flush section of the internal registry. It is mainly
1200 * implements to fix a problem with the global HKU and the local HKU.
1201 * Those two files are read to build the HKU\.Default branch to finaly copy
1202 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1203 * all the global HKU are saved onto the user's personal version of HKU hive.
1207 /* Forward declaration of recusive agent */
1208 static void _flush_reg(LPKEYSTRUCT from
);
1210 static void _flush_registry( LPKEYSTRUCT from
)
1212 /* make sure we have something... */
1216 /* Launch the recusive agent on sub branches */
1217 _flush_reg( from
->nextsub
);
1218 _flush_reg( from
->next
);
1220 /* Initialize pointers */
1221 from
->nextsub
= NULL
;
1224 static void _flush_reg( LPKEYSTRUCT from
)
1228 /* make sure we have something... */
1233 * do the same for the child keys
1235 if (from
->nextsub
!= NULL
)
1236 _flush_reg(from
->nextsub
);
1239 * do the same for the sibling keys
1241 if (from
->next
!= NULL
)
1242 _flush_reg(from
->next
);
1245 * iterate through this key's values and delete them
1247 for (j
=0;j
<from
->nrofvalues
;j
++)
1249 free( (from
->values
+j
)->name
);
1250 free( (from
->values
+j
)->data
);
1254 * free the structure
1261 /******************************************************************************
1262 * _copy_registry [Internal]
1264 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1272 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1274 for (j
=0;j
<from
->nrofvalues
;j
++) {
1278 valfrom
= from
->values
+j
;
1280 if (name
) name
=strdupW(name
);
1281 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1282 memcpy(data
,valfrom
->data
,valfrom
->len
);
1290 valfrom
->lastmodified
1293 _copy_registry(from
,lpxkey
);
1299 /* WINDOWS 95 REGISTRY LOADER */
1301 * Structure of a win95 registry database.
1303 * 0 : "CREG" - magic
1305 * 8 : DWORD offset_of_RGDB_part
1306 * 0C..0F: ? (someone fill in please)
1307 * 10: WORD number of RGDB blocks
1309 * 14: WORD always 0000?
1310 * 16: WORD always 0001?
1311 * 18..1F: ? (someone fill in please)
1315 * 0 : "RGKN" - magic
1316 * 4 : DWORD offset to first RGDB section
1317 * 8 : DWORD offset to the root record
1318 * C..0x1B: ? (fill in)
1319 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1321 * Disk Key Entry Structure:
1322 * 00: DWORD - Free entry indicator(?)
1323 * 04: DWORD - Hash = sum of bytes of keyname
1324 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1325 * 0C: DWORD - disk address of PreviousLevel Key.
1326 * 10: DWORD - disk address of Next Sublevel Key.
1327 * 14: DWORD - disk address of Next Key (on same level).
1328 * DKEP>18: WORD - Nr, Low Significant part.
1329 * 1A: WORD - Nr, High Significant part.
1331 * The disk address always points to the nr part of the previous key entry
1332 * of the referenced key. Don't ask me why, or even if I got this correct
1333 * from staring at 1kg of hexdumps. (DKEP)
1335 * The High significant part of the structure seems to equal the number
1336 * of the RGDB section. The low significant part is a unique ID within
1339 * There are two minor corrections to the position of that structure.
1340 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1341 * the DKE reread from there.
1342 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1343 * CPS - I have not experienced the above phenomenon in my registry files
1346 * 00: "RGDB" - magic
1347 * 04: DWORD offset to next RGDB section
1349 * 0C: WORD always 000d?
1350 * 0E: WORD RGDB block number
1351 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1353 * 20.....: disk keys
1356 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1357 * 08: WORD nrLS - low significant part of NR
1358 * 0A: WORD nrHS - high significant part of NR
1359 * 0C: DWORD bytesused - bytes used in this structure.
1360 * 10: WORD name_len - length of name in bytes. without \0
1361 * 12: WORD nr_of_values - number of values.
1362 * 14: char name[name_len] - name string. No \0.
1363 * 14+name_len: disk values
1364 * nextkeyoffset: ... next disk key
1367 * 00: DWORD type - value type (hmm, could be WORD too)
1368 * 04: DWORD - unknown, usually 0
1369 * 08: WORD namelen - length of Name. 0 means name=NULL
1370 * 0C: WORD datalen - length of Data.
1371 * 10: char name[namelen] - name, no \0
1372 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1373 * 10+namelen+datalen: next values or disk key
1375 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1376 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1377 * structure) and reading another RGDB_section.
1378 * repeat until end of file.
1380 * An interesting relationship exists in RGDB_section. The value at offset
1381 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1382 * idea at the moment what this means. (Kevin Cozens)
1384 * FIXME: this description needs some serious help, yes.
1387 struct _w95keyvalue
{
1389 unsigned short datalen
;
1391 unsigned char *data
;
1399 struct _w95keyvalue
*values
;
1400 struct _w95key
*prevlvl
;
1401 struct _w95key
*nextsub
;
1402 struct _w95key
*next
;
1416 /******************************************************************************
1417 * _w95_processKey [Internal]
1419 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1420 int nrLS
, int nrMS
, struct _w95_info
*info
)
1423 /* Disk Key Header structure (RGDB part) */
1425 unsigned long nextkeyoff
;
1426 unsigned short nrLS
;
1427 unsigned short nrMS
;
1428 unsigned long bytesused
;
1429 unsigned short keynamelen
;
1430 unsigned short values
;
1433 /* disk key values or nothing */
1435 /* Disk Key Value structure */
1439 unsigned short valnamelen
;
1440 unsigned short valdatalen
;
1441 /* valname, valdata */
1447 char *rgdbdata
= info
->rgdbbuffer
;
1448 int nbytes
= info
->rgdbsize
;
1449 char *curdata
= rgdbdata
;
1450 char *end
= rgdbdata
+ nbytes
;
1452 char *next
= rgdbdata
;
1458 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1460 memcpy(&off_next_rgdb
,curdata
+4,4);
1461 next
= curdata
+ off_next_rgdb
;
1462 nrgdb
= (int) *((short *)curdata
+ 7);
1464 } while (nrgdb
!= nrMS
&& (next
< end
));
1466 /* curdata now points to the start of the right RGDB section */
1469 #define XREAD(whereto,len) \
1470 if ((curdata + len) <= end) {\
1471 memcpy(whereto,curdata,len);\
1476 while (curdata
< next
) {
1477 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1479 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1480 if (xdkh
->nrLS
== nrLS
) {
1481 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1482 curdata
+= sizeof(dkh
);
1485 curdata
+= xdkh
->nextkeyoff
;
1488 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1490 if (nrgdb
!= dkh
.nrMS
)
1493 assert((dkh
.keynamelen
<2) || curdata
[0]);
1494 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1495 curdata
+= dkh
.keynamelen
;
1497 for (i
=0;i
< dkh
.values
; i
++) {
1503 XREAD(&dkv
,sizeof(dkv
));
1505 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1506 curdata
+= dkv
.valnamelen
;
1508 if ((1 << dkv
.type
) & UNICONVMASK
) {
1509 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1510 len
= 2*(dkv
.valdatalen
+ 1);
1512 /* I don't think we want to NULL terminate all data */
1513 data
= xmalloc(dkv
.valdatalen
);
1514 memcpy (data
, curdata
, dkv
.valdatalen
);
1515 len
= dkv
.valdatalen
;
1518 curdata
+= dkv
.valdatalen
;
1532 /******************************************************************************
1533 * _w95_walkrgkn [Internal]
1535 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1536 struct _w95_info
*info
)
1539 /* Disk Key Entry structure (RGKN part) */
1543 unsigned long x3
;/*usually 0xFFFFFFFF */
1544 unsigned long prevlvl
;
1545 unsigned long nextsub
;
1547 unsigned short nrLS
;
1548 unsigned short nrMS
;
1549 } *dke
= (struct dke
*)off
;
1553 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1556 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1557 /* XXX <-- This is a hack*/
1562 if (dke
->nextsub
!= -1 &&
1563 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1564 && (dke
->nextsub
> 0x20)) {
1566 _w95_walkrgkn(lpxkey
,
1567 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1571 if (dke
->next
!= -1 &&
1572 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1573 (dke
->next
> 0x20)) {
1574 _w95_walkrgkn(prevkey
,
1575 info
->rgknbuffer
+ dke
->next
- 0x20,
1583 /******************************************************************************
1584 * _w95_loadreg [Internal]
1586 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1590 unsigned long where
,version
,rgdbsection
,end
;
1591 struct _w95_info info
;
1593 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1595 TRACE_(reg
)("Loading Win95 registry database '%s'\n",fn
);
1596 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1597 if (hfd
==HFILE_ERROR
)
1600 if (4!=_lread(hfd
,magic
,4))
1602 if (strcmp(magic
,"CREG")) {
1603 WARN_(reg
)("%s is not a w95 registry.\n",fn
);
1606 if (4!=_lread(hfd
,&version
,4))
1608 if (4!=_lread(hfd
,&rgdbsection
,4))
1610 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1612 if (4!=_lread(hfd
,magic
,4))
1614 if (strcmp(magic
,"RGKN")) {
1615 WARN_(reg
)("second IFF header not RGKN, but %s\n", magic
);
1619 /* STEP 1: Keylink structures */
1620 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1625 info
.rgknsize
= end
- where
;
1626 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1627 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1630 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1633 end
= hfdinfo
.nFileSizeLow
;
1634 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1636 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1639 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1640 info
.rgdbsize
= end
- rgdbsection
;
1642 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1646 _w95_walkrgkn(lpkey
, NULL
, &info
);
1648 free (info
.rgdbbuffer
);
1649 free (info
.rgknbuffer
);
1653 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1656 reghack - windows 3.11 registry data format demo program.
1658 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1659 a combined hash table and tree description, and finally a text table.
1661 The header is obvious from the struct header. The taboff1 and taboff2
1662 fields are always 0x20, and their usage is unknown.
1664 The 8-byte entry table has various entry types.
1666 tabent[0] is a root index. The second word has the index of the root of
1668 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1669 the index of the key/value that has that hash. Data with the same
1670 hash value are on a circular list. The other three words in the
1671 hash entry are always zero.
1672 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1673 entry: dirent and keyent/valent. They are identified by context.
1674 tabent[freeidx] is the first free entry. The first word in a free entry
1675 is the index of the next free entry. The last has 0 as a link.
1676 The other three words in the free list are probably irrelevant.
1678 Entries in text table are preceeded by a word at offset-2. This word
1679 has the value (2*index)+1, where index is the referring keyent/valent
1680 entry in the table. I have no suggestion for the 2* and the +1.
1681 Following the word, there are N bytes of data, as per the keyent/valent
1682 entry length. The offset of the keyent/valent entry is from the start
1683 of the text table to the first data byte.
1685 This information is not available from Microsoft. The data format is
1686 deduced from the reg.dat file by me. Mistakes may
1687 have been made. I claim no rights and give no guarantees for this program.
1689 Tor Sjøwall, tor@sn.no
1692 /* reg.dat header format */
1693 struct _w31_header
{
1694 char cookie
[8]; /* 'SHCC3.10' */
1695 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1696 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1697 unsigned long tabcnt
; /* number of entries in index table */
1698 unsigned long textoff
; /* offset of text part */
1699 unsigned long textsize
; /* byte size of text part */
1700 unsigned short hashsize
; /* hash size */
1701 unsigned short freeidx
; /* free index */
1704 /* generic format of table entries */
1705 struct _w31_tabent
{
1706 unsigned short w0
, w1
, w2
, w3
;
1709 /* directory tabent: */
1710 struct _w31_dirent
{
1711 unsigned short sibling_idx
; /* table index of sibling dirent */
1712 unsigned short child_idx
; /* table index of child dirent */
1713 unsigned short key_idx
; /* table index of key keyent */
1714 unsigned short value_idx
; /* table index of value valent */
1718 struct _w31_keyent
{
1719 unsigned short hash_idx
; /* hash chain index for string */
1720 unsigned short refcnt
; /* reference count */
1721 unsigned short length
; /* length of string */
1722 unsigned short string_off
; /* offset of string in text table */
1726 struct _w31_valent
{
1727 unsigned short hash_idx
; /* hash chain index for string */
1728 unsigned short refcnt
; /* reference count */
1729 unsigned short length
; /* length of string */
1730 unsigned short string_off
; /* offset of string in text table */
1733 /* recursive helper function to display a directory tree */
1735 __w31_dumptree( unsigned short idx
,
1737 struct _w31_tabent
*tab
,
1738 struct _w31_header
*head
,
1740 time_t lastmodified
,
1743 struct _w31_dirent
*dir
;
1744 struct _w31_keyent
*key
;
1745 struct _w31_valent
*val
;
1746 LPKEYSTRUCT xlpkey
= NULL
;
1748 static char tail
[400];
1751 dir
=(struct _w31_dirent
*)&tab
[idx
];
1754 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1756 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1757 tail
[key
->length
]='\0';
1758 /* all toplevel entries AND the entries in the
1759 * toplevel subdirectory belong to \SOFTWARE\Classes
1761 if (!level
&& !lstrcmpA(tail
,".classes")) {
1762 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1763 idx
=dir
->sibling_idx
;
1766 name
=strdupA2W(tail
);
1768 xlpkey
=_find_or_add_key(lpkey
,name
);
1770 /* only add if leaf node or valued node */
1771 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1772 if (dir
->value_idx
) {
1773 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1774 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1775 tail
[val
->length
]='\0';
1776 value
=strdupA2W(tail
);
1777 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1781 TRACE_(reg
)("strange: no directory key name, idx=%04x\n", idx
);
1783 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1784 idx
=dir
->sibling_idx
;
1789 /******************************************************************************
1790 * _w31_loadreg [Internal]
1792 void _w31_loadreg(void) {
1794 struct _w31_header head
;
1795 struct _w31_tabent
*tab
;
1799 BY_HANDLE_FILE_INFORMATION hfinfo
;
1800 time_t lastmodified
;
1803 TRACE_(reg
)("(void)\n");
1805 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1806 if (hf
==HFILE_ERROR
)
1809 /* read & dump header */
1810 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1811 ERR_(reg
)("reg.dat is too short.\n");
1815 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1816 ERR_(reg
)("reg.dat has bad signature.\n");
1821 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1822 /* read and dump index table */
1824 if (len
!=_lread(hf
,tab
,len
)) {
1825 ERR_(reg
)("couldn't read %d bytes.\n",len
);
1832 txt
= xmalloc(head
.textsize
);
1833 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1834 ERR_(reg
)("couldn't seek to textblock.\n");
1840 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1841 ERR_(reg
)("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1848 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1849 ERR_(reg
)("GetFileInformationByHandle failed?.\n");
1855 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1856 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1857 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1865 /**********************************************************************************
1866 * SHELL_LoadRegistry [Internal]
1868 void SHELL_LoadRegistry( void )
1871 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1874 TRACE_(reg
)("(void)\n");
1876 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1877 HKU
= lookup_hkey(HKEY_USERS
);
1878 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1880 /* Load windows 3.1 entries */
1882 /* Load windows 95 entries */
1883 _w95_loadreg("C:\\system.1st", HKLM
);
1884 _w95_loadreg("system.dat", HKLM
);
1885 _w95_loadreg("user.dat", HKU
);
1888 * Load the global HKU hive directly from sysconfdir
1890 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1893 * Load the global machine defaults directly form sysconfdir
1895 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1898 * Load the user saved registries
1900 if ((home
= getenv( "HOME" )))
1903 * Load user's personal versions of global HKU/.Default keys
1907 strlen(WINE_PREFIX
)+
1908 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1911 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1912 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1916 * Load HKCU, attempt to get the registry location from the config
1917 * file first, if exist, load and keep going.
1919 fn
= xmalloc( MAX_PATHNAME_LEN
);
1920 if ( PROFILE_GetWineIniString(
1925 MAX_PATHNAME_LEN
- 1))
1927 _wine_loadreg(HKCU
,fn
,0);
1933 strlen(WINE_PREFIX
)+
1934 strlen(SAVE_CURRENT_USER
)+2);
1937 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1938 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
1942 * Load HKLM, attempt to get the registry location from the config
1943 * file first, if exist, load and keep going.
1945 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1946 if ( PROFILE_GetWineIniString(
1948 "LocalMachineFileName",
1951 MAX_PATHNAME_LEN
- 1))
1953 _wine_loadreg(HKLM
, fn
, 0);
1959 strlen(WINE_PREFIX
)+
1960 strlen(SAVE_LOCAL_MACHINE
)+2);
1963 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1964 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
1969 WARN_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1973 * Obtain the handle of the HKU\.Default key.
1974 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1976 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1977 lpkey
= lookup_hkey(hkey
);
1979 WARN_(reg
)("Could not create global user default key\n");
1981 _copy_registry(lpkey
, HKCU
);
1986 * Since HKU is built from the global HKU and the local user HKU file we must
1987 * flush the HKU tree we have built at this point otherwise the part brought
1988 * in from the global HKU is saved into the local HKU. To avoid this
1989 * useless dupplication of HKU keys we reread the local HKU key.
1992 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1993 _flush_registry(HKU
);
1995 /* Reload user's local HKU hive */
1998 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
)
1999 + strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
2002 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2004 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2010 * Make sure the update mode is there
2012 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2014 DWORD junk
,type
,len
;
2018 if (( RegQueryValueExA(
2024 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2026 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2034 /********************* API FUNCTIONS ***************************************/
2038 * All functions are stubs to RegOpenKeyEx32W where all the
2042 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2043 * RegOpenKey32W -> RegOpenKeyEx32W
2047 /******************************************************************************
2048 * RegOpenKeyEx32W [ADVAPI32.150]
2049 * Opens the specified key
2051 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2054 * hkey [I] Handle of open key
2055 * lpszSubKey [I] Name of subkey to open
2056 * dwReserved [I] Reserved - must be zero
2057 * samDesired [I] Security access mask
2058 * retkey [O] Address of handle of open key
2061 * Success: ERROR_SUCCESS
2062 * Failure: Error code
2064 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2065 REGSAM samDesired
, LPHKEY retkey
)
2067 LPKEYSTRUCT lpNextKey
,lpxkey
;
2071 TRACE_(reg
)("(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2074 lpNextKey
= lookup_hkey( hkey
);
2076 return ERROR_INVALID_HANDLE
;
2078 if (!lpszSubKey
|| !*lpszSubKey
) {
2079 /* Either NULL or pointer to empty string, so return a new handle
2080 to the original hkey */
2082 add_handle(currenthandle
,lpNextKey
,samDesired
);
2083 *retkey
=currenthandle
;
2084 return ERROR_SUCCESS
;
2087 if (lpszSubKey
[0] == '\\') {
2088 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2089 return ERROR_BAD_PATHNAME
;
2092 split_keypath(lpszSubKey
,&wps
,&wpc
);
2094 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2098 lpxkey
=lpNextKey
->nextsub
;
2100 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2103 lpxkey
=lpxkey
->next
;
2107 TRACE_(reg
)("Could not find subkey %s\n",debugstr_w(wps
[i
]));
2109 return ERROR_FILE_NOT_FOUND
;
2116 add_handle(currenthandle
,lpxkey
,samDesired
);
2117 *retkey
= currenthandle
;
2118 TRACE_(reg
)(" Returning %x\n", currenthandle
);
2120 return ERROR_SUCCESS
;
2124 /******************************************************************************
2125 * RegOpenKeyEx32A [ADVAPI32.149]
2127 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2128 REGSAM samDesired
, LPHKEY retkey
)
2130 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2133 TRACE_(reg
)("(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2135 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2141 /******************************************************************************
2142 * RegOpenKey32W [ADVAPI32.151]
2145 * hkey [I] Handle of open key
2146 * lpszSubKey [I] Address of name of subkey to open
2147 * retkey [O] Address of handle of open key
2150 * Success: ERROR_SUCCESS
2151 * Failure: Error code
2153 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2155 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2156 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2160 /******************************************************************************
2161 * RegOpenKey32A [ADVAPI32.148]
2163 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2166 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2167 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2168 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2174 /******************************************************************************
2175 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2177 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2179 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2180 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2187 * All those functions convert their respective
2188 * arguments and call RegCreateKeyExW at the end.
2190 * We stay away from the Ex functions as long as possible because there are
2191 * differences in the return values
2194 * RegCreateKeyEx32A \
2195 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2199 /******************************************************************************
2200 * RegCreateKeyEx32W [ADVAPI32.131]
2203 * hkey [I] Handle of an open key
2204 * lpszSubKey [I] Address of subkey name
2205 * dwReserved [I] Reserved - must be 0
2206 * lpszClass [I] Address of class string
2207 * fdwOptions [I] Special options flag
2208 * samDesired [I] Desired security access
2209 * lpSecAttribs [I] Address of key security structure
2210 * retkey [O] Address of buffer for opened handle
2211 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2213 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2214 DWORD dwReserved
, LPWSTR lpszClass
,
2215 DWORD fdwOptions
, REGSAM samDesired
,
2216 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2217 LPHKEY retkey
, LPDWORD lpDispos
)
2219 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2223 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2224 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2225 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2227 lpNextKey
= lookup_hkey(hkey
);
2229 return ERROR_INVALID_HANDLE
;
2231 /* Check for valid options */
2232 switch(fdwOptions
) {
2233 case REG_OPTION_NON_VOLATILE
:
2234 case REG_OPTION_VOLATILE
:
2235 case REG_OPTION_BACKUP_RESTORE
:
2238 return ERROR_INVALID_PARAMETER
;
2241 /* Sam has to be a combination of the following */
2243 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2244 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2245 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2246 return ERROR_INVALID_PARAMETER
;
2248 if (!lpszSubKey
|| !*lpszSubKey
) {
2250 add_handle(currenthandle
,lpNextKey
,samDesired
);
2251 *retkey
=currenthandle
;
2252 TRACE_(reg
)("Returning %x\n", currenthandle
);
2253 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2254 return ERROR_SUCCESS
;
2257 if (lpszSubKey
[0] == '\\') {
2258 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2259 return ERROR_BAD_PATHNAME
;
2262 split_keypath(lpszSubKey
,&wps
,&wpc
);
2264 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2267 lpxkey
=lpNextKey
->nextsub
;
2269 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2271 lpxkey
=lpxkey
->next
;
2280 add_handle(currenthandle
,lpxkey
,samDesired
);
2281 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2282 *retkey
= currenthandle
;
2283 TRACE_(reg
)("Returning %x\n", currenthandle
);
2285 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2287 return ERROR_SUCCESS
;
2290 /* Good. Now the hard part */
2292 lplpPrevKey
= &(lpNextKey
->nextsub
);
2293 lpxkey
= *lplpPrevKey
;
2295 lplpPrevKey
= &(lpxkey
->next
);
2296 lpxkey
= *lplpPrevKey
;
2298 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2299 if (!*lplpPrevKey
) {
2301 TRACE_(reg
)("Returning OUTOFMEMORY\n");
2302 return ERROR_OUTOFMEMORY
;
2304 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2305 TRACE_(reg
)("Adding %s\n", debugstr_w(wps
[i
]));
2306 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2307 (*lplpPrevKey
)->next
= NULL
;
2308 (*lplpPrevKey
)->nextsub
= NULL
;
2309 (*lplpPrevKey
)->values
= NULL
;
2310 (*lplpPrevKey
)->nrofvalues
= 0;
2311 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2313 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2315 (*lplpPrevKey
)->class = NULL
;
2316 lpNextKey
= *lplpPrevKey
;
2320 add_handle(currenthandle
,lpNextKey
,samDesired
);
2322 /*FIXME: flag handling correct? */
2323 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2325 lpNextKey
->class = strdupW(lpszClass
);
2327 lpNextKey
->class = NULL
;
2328 *retkey
= currenthandle
;
2329 TRACE_(reg
)("Returning %x\n", currenthandle
);
2331 *lpDispos
= REG_CREATED_NEW_KEY
;
2333 return ERROR_SUCCESS
;
2337 /******************************************************************************
2338 * RegCreateKeyEx32A [ADVAPI32.130]
2340 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2341 LPSTR lpszClass
, DWORD fdwOptions
,
2343 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2344 LPHKEY retkey
, LPDWORD lpDispos
)
2346 LPWSTR lpszSubKeyW
, lpszClassW
;
2349 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2350 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2353 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2354 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2356 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2357 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2360 if(lpszSubKeyW
) free(lpszSubKeyW
);
2361 if(lpszClassW
) free(lpszClassW
);
2367 /******************************************************************************
2368 * RegCreateKey32W [ADVAPI32.132]
2370 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2373 LPKEYSTRUCT lpNextKey
;
2375 TRACE_(reg
)("(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2377 /* This check is here because the return value is different than the
2378 one from the Ex functions */
2379 lpNextKey
= lookup_hkey(hkey
);
2381 return ERROR_BADKEY
;
2383 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2384 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2389 /******************************************************************************
2390 * RegCreateKey32A [ADVAPI32.129]
2392 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2397 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2398 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2399 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2400 if(lpszSubKeyW
) free(lpszSubKeyW
);
2405 /******************************************************************************
2406 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2408 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2410 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2411 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2416 * Query Value Functions
2417 * Win32 differs between keynames and valuenames.
2418 * multiple values may belong to one key, the special value
2419 * with name NULL is the default value used by the win31
2423 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2424 * RegQueryValue32W -> RegQueryValueEx32W
2428 /******************************************************************************
2429 * RegQueryValueEx32W [ADVAPI32.158]
2430 * Retrieves type and data for a specified name associated with an open key
2433 * hkey [I] Handle of key to query
2434 * lpValueName [I] Name of value to query
2435 * lpdwReserved [I] Reserved - must be NULL
2436 * lpdwType [O] Address of buffer for value type. If NULL, the type
2438 * lpbData [O] Address of data buffer. If NULL, the actual data is
2440 * lpcbData [I/O] Address of data buffer size
2443 * ERROR_SUCCESS: Success
2444 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2445 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2447 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR lpValueName
,
2448 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2449 LPBYTE lpbData
, LPDWORD lpcbData
)
2455 TRACE_(reg
)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2456 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2458 lpkey
= lookup_hkey(hkey
);
2461 return ERROR_INVALID_HANDLE
;
2463 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2464 return ERROR_INVALID_PARAMETER
;
2466 /* An empty name string is equivalent to NULL */
2467 if (lpValueName
&& !*lpValueName
)
2470 if (lpValueName
==NULL
)
2471 { /* Use key's unnamed or default value, if any */
2472 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2473 if (lpkey
->values
[i
].name
==NULL
)
2477 { /* Search for the key name */
2478 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2479 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2483 if (i
==lpkey
->nrofvalues
)
2484 { TRACE_(reg
)(" Key not found\n");
2485 if (lpValueName
==NULL
)
2486 { /* Empty keyname not found */
2488 { *(WCHAR
*)lpbData
= 0;
2493 TRACE_(reg
)(" Returning an empty string\n");
2494 return ERROR_SUCCESS
;
2496 return ERROR_FILE_NOT_FOUND
;
2499 ret
= ERROR_SUCCESS
;
2501 if (lpdwType
) /* type required ?*/
2502 *lpdwType
= lpkey
->values
[i
].type
;
2504 if (lpbData
) /* data required ?*/
2505 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2506 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2508 *lpcbData
= lpkey
->values
[i
].len
;
2509 ret
= ERROR_MORE_DATA
;
2513 if (lpcbData
) /* size required ?*/
2514 { *lpcbData
= lpkey
->values
[i
].len
;
2517 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2519 TRACE_(reg
)(" (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2525 /******************************************************************************
2526 * RegQueryValue32W [ADVAPI32.159]
2528 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2534 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2535 lpcbData
?*lpcbData
:0);
2537 /* Only open subkey, if we really do descend */
2538 if (lpszSubKey
&& *lpszSubKey
) {
2539 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2540 if (ret
!= ERROR_SUCCESS
) {
2541 WARN_(reg
)("Could not open %s\n", debugstr_w(lpszSubKey
));
2548 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2556 /******************************************************************************
2557 * RegQueryValueEx32A [ADVAPI32.157]
2560 * the documantation is wrong: if the buffer is to small it remains untouched
2562 * FIXME: check returnvalue (len) for an empty key
2564 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2565 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2566 LPBYTE lpbData
, LPDWORD lpcbData
)
2568 LPWSTR lpszValueNameW
;
2569 LPBYTE mybuf
= NULL
;
2570 DWORD ret
, mytype
, mylen
= 0;
2572 TRACE_(reg
)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2573 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2575 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2576 { return ERROR_INVALID_PARAMETER
;
2579 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2581 /* get just the type first */
2582 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2584 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2585 { if(lpszValueNameW
) free(lpszValueNameW
);
2589 if (lpcbData
) /* at least length requested? */
2590 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2591 { if (lpbData
) /* value requested? */
2592 { mylen
= 2*( *lpcbData
);
2593 mybuf
= (LPBYTE
)xmalloc( mylen
);
2596 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2598 if (ret
== ERROR_SUCCESS
)
2600 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2604 *lpcbData
= mylen
/2; /* size is in byte! */
2606 else /* no strings, call it straight */
2607 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2611 if (lpdwType
) /* type when requested */
2612 { *lpdwType
= mytype
;
2615 TRACE_(reg
)(" (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2617 if(mybuf
) free(mybuf
);
2618 if(lpszValueNameW
) free(lpszValueNameW
);
2623 /******************************************************************************
2624 * RegQueryValueEx16 [KERNEL.225]
2626 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2627 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2628 LPBYTE lpbData
, LPDWORD lpcbData
)
2630 TRACE_(reg
)("(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2631 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2632 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2633 lpbData
, lpcbData
);
2637 /******************************************************************************
2638 * RegQueryValue32A [ADVAPI32.156]
2640 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2646 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2647 lpcbData
?*lpcbData
:0);
2649 if (lpszSubKey
&& *lpszSubKey
) {
2650 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2651 if( ret
!= ERROR_SUCCESS
)
2657 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2660 RegCloseKey( xhkey
);
2665 /******************************************************************************
2666 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2669 * Is this HACK still applicable?
2672 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2673 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2676 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2679 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2680 lpcbData
?*lpcbData
:0);
2683 *lpcbData
&= 0xFFFF;
2684 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2689 * Setting values of Registry keys
2692 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2693 * RegSetValue32W -> RegSetValueEx32W
2697 /******************************************************************************
2698 * RegSetValueEx32W [ADVAPI32.170]
2699 * Sets the data and type of a value under a register key
2702 * hkey [I] Handle of key to set value for
2703 * lpszValueName [I] Name of value to set
2704 * dwReserved [I] Reserved - must be zero
2705 * dwType [I] Flag for value type
2706 * lpbData [I] Address of value data
2707 * cbData [I] Size of value data
2710 * Success: ERROR_SUCCESS
2711 * Failure: Error code
2714 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2716 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR lpszValueName
,
2717 DWORD dwReserved
, DWORD dwType
,
2718 CONST BYTE
*lpbData
, DWORD cbData
)
2723 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2724 dwReserved
, dwType
, lpbData
, cbData
);
2726 lpkey
= lookup_hkey( hkey
);
2729 return ERROR_INVALID_HANDLE
;
2731 lpkey
->flags
|= REG_OPTION_TAINTED
;
2733 if (lpszValueName
==NULL
) {
2734 /* Sets type and name for key's unnamed or default value */
2735 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2736 if (lpkey
->values
[i
].name
==NULL
)
2739 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2740 if ( lpkey
->values
[i
].name
&&
2741 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2745 if (i
==lpkey
->nrofvalues
) {
2746 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2748 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2750 lpkey
->nrofvalues
++;
2751 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2753 if (lpkey
->values
[i
].name
==NULL
) {
2755 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2757 lpkey
->values
[i
].name
= NULL
;
2760 if (dwType
== REG_SZ
)
2761 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2763 lpkey
->values
[i
].len
= cbData
;
2764 lpkey
->values
[i
].type
= dwType
;
2765 if (lpkey
->values
[i
].data
!=NULL
)
2766 free(lpkey
->values
[i
].data
);
2767 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2768 lpkey
->values
[i
].lastmodified
= time(NULL
);
2769 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2770 return ERROR_SUCCESS
;
2774 /******************************************************************************
2775 * RegSetValueEx32A [ADVAPI32.169]
2778 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2780 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2781 DWORD dwReserved
, DWORD dwType
,
2782 CONST BYTE
*lpbData
, DWORD cbData
)
2785 LPWSTR lpszValueNameW
;
2789 return (ERROR_INVALID_PARAMETER
);
2791 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2792 dwReserved
,dwType
,lpbData
,cbData
);
2794 if ((1<<dwType
) & UNICONVMASK
)
2795 { if (dwType
== REG_SZ
)
2796 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2798 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2799 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2803 buf
=(LPBYTE
)lpbData
;
2806 lpszValueNameW
= strdupA2W(lpszValueName
);
2808 lpszValueNameW
= NULL
;
2810 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2813 free(lpszValueNameW
);
2822 /******************************************************************************
2823 * RegSetValueEx16 [KERNEL.226]
2825 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2826 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2828 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2829 dwReserved
,dwType
,lpbData
,cbData
);
2830 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2835 /******************************************************************************
2836 * RegSetValue32W [ADVAPI32.171]
2838 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2839 LPCWSTR lpszData
, DWORD cbData
)
2844 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",
2845 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2847 if (lpszSubKey
&& *lpszSubKey
) {
2848 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2849 if (ret
!=ERROR_SUCCESS
)
2853 if (dwType
!=REG_SZ
) {
2854 TRACE_(reg
)("dwType=%ld - Changing to REG_SZ\n",dwType
);
2857 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2858 TRACE_(reg
)("Len=%ld != strlen(%s)+1=%d!\n",
2859 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2861 cbData
=2*lstrlenW(lpszData
)+2;
2863 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2870 /******************************************************************************
2871 * RegSetValue32A [ADVAPI32.168]
2874 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2875 LPCSTR lpszData
, DWORD cbData
)
2880 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2881 if (lpszSubKey
&& *lpszSubKey
) {
2882 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2883 if (ret
!=ERROR_SUCCESS
)
2888 if (dwType
!=REG_SZ
) {
2889 TRACE_(reg
)("dwType=%ld!\n",dwType
);
2892 if (cbData
!=strlen(lpszData
)+1)
2893 cbData
=strlen(lpszData
)+1;
2894 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2901 /******************************************************************************
2902 * RegSetValue16 [KERNEL.221] [SHELL.5]
2904 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2905 LPCSTR lpszData
, DWORD cbData
)
2907 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2908 debugstr_a(lpszData
),cbData
);
2909 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2917 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2918 * RegEnumKey32W -> RegEnumKeyEx32W
2922 /******************************************************************************
2923 * RegEnumKeyEx32W [ADVAPI32.139]
2926 * hkey [I] Handle to key to enumerate
2927 * iSubKey [I] Index of subkey to enumerate
2928 * lpszName [O] Buffer for subkey name
2929 * lpcchName [O] Size of subkey buffer
2930 * lpdwReserved [I] Reserved
2931 * lpszClass [O] Buffer for class string
2932 * lpcchClass [O] Size of class buffer
2933 * ft [O] Time key last written to
2935 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2936 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2937 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2940 LPKEYSTRUCT lpkey
,lpxkey
;
2942 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2943 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2945 lpkey
= lookup_hkey( hkey
);
2947 return ERROR_INVALID_HANDLE
;
2949 if (!lpkey
->nextsub
)
2950 return ERROR_NO_MORE_ITEMS
;
2951 lpxkey
=lpkey
->nextsub
;
2953 /* Traverse the subkeys */
2954 while (iSubkey
&& lpxkey
) {
2956 lpxkey
=lpxkey
->next
;
2959 if (iSubkey
|| !lpxkey
)
2960 return ERROR_NO_MORE_ITEMS
;
2961 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
) {
2962 *lpcchName
= lstrlenW(lpxkey
->keyname
)+1;
2963 return ERROR_MORE_DATA
;
2965 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
2968 *lpcchName
= lstrlenW(lpszName
);
2971 /* FIXME: what should we write into it? */
2975 return ERROR_SUCCESS
;
2979 /******************************************************************************
2980 * RegEnumKey32W [ADVAPI32.140]
2982 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2987 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2988 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2992 /******************************************************************************
2993 * RegEnumKeyEx32A [ADVAPI32.138]
2995 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2996 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2997 LPSTR lpszClass
, LPDWORD lpcchClass
,
3000 DWORD ret
,lpcchNameW
,lpcchClassW
;
3001 LPWSTR lpszNameW
,lpszClassW
;
3004 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3005 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3008 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3009 lpcchNameW
= *lpcchName
;
3015 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3016 lpcchClassW
= *lpcchClass
;
3031 if (ret
==ERROR_SUCCESS
) {
3032 lstrcpyWtoA(lpszName
,lpszNameW
);
3033 *lpcchName
=strlen(lpszName
);
3035 lstrcpyWtoA(lpszClass
,lpszClassW
);
3036 *lpcchClass
=strlen(lpszClass
);
3047 /******************************************************************************
3048 * RegEnumKey32A [ADVAPI32.137]
3050 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3055 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3056 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3061 /******************************************************************************
3062 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3064 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3067 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3068 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3073 * Enumerate Registry Values
3076 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3080 /******************************************************************************
3081 * RegEnumValue32W [ADVAPI32.142]
3084 * hkey [I] Handle to key to query
3085 * iValue [I] Index of value to query
3086 * lpszValue [O] Value string
3087 * lpcchValue [I/O] Size of value buffer (in wchars)
3088 * lpdReserved [I] Reserved
3089 * lpdwType [O] Type code
3090 * lpbData [O] Value data
3091 * lpcbData [I/O] Size of data buffer (in bytes)
3093 * Note: wide character functions that take and/or return "character counts"
3094 * use TCHAR (that is unsigned short or char) not byte counts.
3096 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3097 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3098 LPDWORD lpdwType
, LPBYTE lpbData
,
3104 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3105 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3107 lpkey
= lookup_hkey( hkey
);
3109 if (!lpcbData
&& lpbData
)
3110 return ERROR_INVALID_PARAMETER
;
3113 return ERROR_INVALID_HANDLE
;
3115 if (lpkey
->nrofvalues
<= iValue
)
3116 return ERROR_NO_MORE_ITEMS
;
3118 val
= &(lpkey
->values
[iValue
]);
3121 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3122 *lpcchValue
= lstrlenW(val
->name
)+1;
3123 return ERROR_MORE_DATA
;
3125 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3126 *lpcchValue
=lstrlenW(val
->name
);
3132 /* Can be NULL if the type code is not required */
3134 *lpdwType
= val
->type
;
3137 if (val
->len
>*lpcbData
) {
3138 *lpcbData
= val
->len
;
3139 return ERROR_MORE_DATA
;
3141 memcpy(lpbData
,val
->data
,val
->len
);
3142 *lpcbData
= val
->len
;
3145 debug_print_value ( val
->data
, val
);
3146 return ERROR_SUCCESS
;
3150 /******************************************************************************
3151 * RegEnumValue32A [ADVAPI32.141]
3153 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3154 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3155 LPDWORD lpdwType
, LPBYTE lpbData
,
3160 DWORD ret
,lpcbDataW
;
3163 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3164 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3166 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3168 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3169 lpcbDataW
= *lpcbData
;
3173 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3174 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3179 if (ret
==ERROR_SUCCESS
) {
3180 lstrcpyWtoA(lpszValue
,lpszValueW
);
3182 if ((1<<dwType
) & UNICONVMASK
) {
3183 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3185 if (lpcbDataW
> *lpcbData
) {
3186 *lpcbData
= lpcbDataW
;
3187 ret
= ERROR_MORE_DATA
;
3189 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3191 *lpcbData
= lpcbDataW
;
3194 if (lpbDataW
) free(lpbDataW
);
3195 if (lpszValueW
) free(lpszValueW
);
3200 /******************************************************************************
3201 * RegEnumValue16 [KERNEL.223]
3203 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3204 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3205 LPDWORD lpdwType
, LPBYTE lpbData
,
3208 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3209 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3210 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3211 lpdwType
, lpbData
, lpcbData
);
3215 /******************************************************************************
3216 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3217 * Releases the handle of the specified key
3220 * hkey [I] Handle of key to close
3223 * Success: ERROR_SUCCESS
3224 * Failure: Error code
3226 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3228 TRACE_(reg
)("(%x)\n",hkey
);
3230 /* The standard handles are allowed to succeed, even though they are not
3232 if (is_standard_hkey(hkey
))
3233 return ERROR_SUCCESS
;
3235 return remove_handle(hkey
);
3240 * Delete registry key
3243 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3247 /******************************************************************************
3248 * RegDeleteKey32W [ADVAPI32.134]
3251 * hkey [I] Handle to open key
3252 * lpszSubKey [I] Name of subkey to delete
3255 * Success: ERROR_SUCCESS
3256 * Failure: Error code
3258 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR lpszSubKey
)
3260 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3264 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3266 lpNextKey
= lookup_hkey(hkey
);
3268 return ERROR_INVALID_HANDLE
;
3270 /* Subkey param cannot be NULL */
3271 if (!lpszSubKey
|| !*lpszSubKey
)
3272 return ERROR_BADKEY
;
3274 /* We need to know the previous key in the hier. */
3275 split_keypath(lpszSubKey
,&wps
,&wpc
);
3279 lpxkey
=lpNextKey
->nextsub
;
3281 TRACE_(reg
)(" Scanning [%s]\n",
3282 debugstr_w(lpxkey
->keyname
));
3283 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3285 lpxkey
=lpxkey
->next
;
3289 TRACE_(reg
)(" Not found.\n");
3290 /* not found is success */
3291 return ERROR_SUCCESS
;
3296 lpxkey
= lpNextKey
->nextsub
;
3297 lplpPrevKey
= &(lpNextKey
->nextsub
);
3299 TRACE_(reg
)(" Scanning [%s]\n",
3300 debugstr_w(lpxkey
->keyname
));
3301 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3303 lplpPrevKey
= &(lpxkey
->next
);
3304 lpxkey
= lpxkey
->next
;
3309 WARN_(reg
)(" Not found.\n");
3310 return ERROR_FILE_NOT_FOUND
;
3313 if (lpxkey
->nextsub
) {
3315 WARN_(reg
)(" Not empty.\n");
3316 return ERROR_CANTWRITE
;
3318 *lplpPrevKey
= lpxkey
->next
;
3319 free(lpxkey
->keyname
);
3321 free(lpxkey
->class);
3323 free(lpxkey
->values
);
3326 TRACE_(reg
)(" Done.\n");
3327 return ERROR_SUCCESS
;
3331 /******************************************************************************
3332 * RegDeleteKey32A [ADVAPI32.133]
3334 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3339 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3340 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3341 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3342 if(lpszSubKeyW
) free(lpszSubKeyW
);
3347 /******************************************************************************
3348 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3350 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3352 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3353 return RegDeleteKeyA( hkey
, lpszSubKey
);
3358 * Delete registry value
3361 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3365 /******************************************************************************
3366 * RegDeleteValue32W [ADVAPI32.136]
3374 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR lpszValue
)
3380 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3382 lpkey
= lookup_hkey( hkey
);
3384 return ERROR_INVALID_HANDLE
;
3387 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3388 if ( lpkey
->values
[i
].name
&&
3389 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3393 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3394 if (lpkey
->values
[i
].name
==NULL
)
3398 if (i
== lpkey
->nrofvalues
)
3399 return ERROR_FILE_NOT_FOUND
;
3401 val
= lpkey
->values
+i
;
3402 if (val
->name
) free(val
->name
);
3403 if (val
->data
) free(val
->data
);
3407 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3409 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3411 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3413 lpkey
->nrofvalues
--;
3414 return ERROR_SUCCESS
;
3418 /******************************************************************************
3419 * RegDeleteValue32A [ADVAPI32.135]
3421 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR lpszValue
)
3426 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3427 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3428 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3429 if(lpszValueW
) free(lpszValueW
);
3434 /******************************************************************************
3435 * RegDeleteValue16 [KERNEL.222]
3437 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3439 TRACE_(reg
)("(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3440 return RegDeleteValueA( hkey
, lpszValue
);
3444 /******************************************************************************
3445 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3446 * Writes key to registry
3449 * hkey [I] Handle of key to write
3452 * Success: ERROR_SUCCESS
3453 * Failure: Error code
3455 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3460 TRACE_(reg
)("(%x)\n", hkey
);
3462 lpkey
= lookup_hkey( hkey
);
3464 return ERROR_BADKEY
;
3466 ERR_(reg
)("What is the correct filename?\n");
3468 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3471 return ERROR_SUCCESS
;
3473 return ERROR_UNKNOWN
; /* FIXME */
3477 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3480 /******************************************************************************
3481 * RegQueryInfoKey32W [ADVAPI32.153]
3484 * hkey [I] Handle to key to query
3485 * lpszClass [O] Buffer for class string
3486 * lpcchClass [O] Size of class string buffer
3487 * lpdwReserved [I] Reserved
3488 * lpcSubKeys [I] Buffer for number of subkeys
3489 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3490 * lpcchMaxClass [O] Buffer for longest class string length
3491 * lpcValues [O] Buffer for number of value entries
3492 * lpcchMaxValueName [O] Buffer for longest value name length
3493 * lpccbMaxValueData [O] Buffer for longest value data length
3494 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3496 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3497 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3498 * lpcchClass is NULL
3499 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3500 * (it's hard to test validity, so test !NULL instead)
3502 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3503 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3504 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3505 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3506 LPDWORD lpcchMaxValueName
,
3507 LPDWORD lpccbMaxValueData
,
3508 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3510 LPKEYSTRUCT lpkey
,lpxkey
;
3511 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3514 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3515 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3516 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3517 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3519 lpkey
= lookup_hkey(hkey
);
3521 return ERROR_INVALID_HANDLE
;
3523 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3524 return ERROR_INVALID_PARAMETER
;
3526 /* either lpcchClass is valid or this is win95 and lpcchClass
3529 DWORD classLen
= lstrlenW(lpkey
->class);
3531 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3532 *lpcchClass
=classLen
+1;
3533 return ERROR_MORE_DATA
;
3536 *lpcchClass
=classLen
;
3537 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3545 *lpcchClass
= lstrlenW(lpkey
->class);
3547 lpxkey
=lpkey
->nextsub
;
3548 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3551 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3552 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3553 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3554 maxclass
=lstrlenW(lpxkey
->class);
3555 lpxkey
=lpxkey
->next
;
3557 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3558 LPKEYVALUE val
=lpkey
->values
+i
;
3560 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3561 maxvname
=lstrlenW(val
->name
);
3562 if (val
->len
>maxvdata
)
3565 if (!maxclass
) maxclass
= 1;
3566 if (!maxvname
) maxvname
= 1;
3568 *lpcValues
= lpkey
->nrofvalues
;
3570 *lpcSubKeys
= nrofkeys
;
3572 *lpcchMaxSubkey
= maxsubkey
;
3574 *lpcchMaxClass
= maxclass
;
3575 if (lpcchMaxValueName
)
3576 *lpcchMaxValueName
= maxvname
;
3577 if (lpccbMaxValueData
)
3578 *lpccbMaxValueData
= maxvdata
;
3579 return ERROR_SUCCESS
;
3583 /******************************************************************************
3584 * RegQueryInfoKey32A [ADVAPI32.152]
3586 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3587 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3588 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3589 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3590 LPDWORD lpccbMaxValueData
,
3591 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3593 LPWSTR lpszClassW
= NULL
;
3596 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3597 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3598 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3599 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3603 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3604 } else if (VERSION_GetVersion() == WIN95
) {
3605 /* win95 allows lpcchClass to be null */
3606 /* we don't know how big lpszClass is, would
3607 MAX_PATHNAME_LEN be the correct default? */
3608 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3613 ret
=RegQueryInfoKeyW(
3624 lpcbSecurityDescriptor
,
3627 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3628 lstrcpyWtoA(lpszClass
,lpszClassW
);
3635 /******************************************************************************
3636 * RegConnectRegistry32W [ADVAPI32.128]
3639 * lpMachineName [I] Address of name of remote computer
3640 * hHey [I] Predefined registry handle
3641 * phkResult [I] Address of buffer for remote registry handle
3643 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3646 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3648 if (!lpMachineName
|| !*lpMachineName
) {
3649 /* Use the local machine name */
3650 return RegOpenKey16( hKey
, "", phkResult
);
3653 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
3654 return ERROR_BAD_NETPATH
;
3658 /******************************************************************************
3659 * RegConnectRegistry32A [ADVAPI32.127]
3661 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3664 LPWSTR machineW
= strdupA2W(machine
);
3665 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3671 /******************************************************************************
3672 * RegGetKeySecurity [ADVAPI32.144]
3673 * Retrieves a copy of security descriptor protecting the registry key
3676 * hkey [I] Open handle of key to set
3677 * SecurityInformation [I] Descriptor contents
3678 * pSecurityDescriptor [O] Address of descriptor for key
3679 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3682 * Success: ERROR_SUCCESS
3683 * Failure: Error code
3685 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3686 SECURITY_INFORMATION SecurityInformation
,
3687 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3688 LPDWORD lpcbSecurityDescriptor
)
3692 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3693 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3695 lpkey
= lookup_hkey( hkey
);
3697 return ERROR_INVALID_HANDLE
;
3699 /* FIXME: Check for valid SecurityInformation values */
3701 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3702 return ERROR_INSUFFICIENT_BUFFER
;
3704 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3705 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3707 return ERROR_SUCCESS
;
3711 /******************************************************************************
3712 * RegLoadKey32W [ADVAPI32.???]
3715 * hkey [I] Handle of open key
3716 * lpszSubKey [I] Address of name of subkey
3717 * lpszFile [I] Address of filename for registry information
3719 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3722 TRACE_(reg
)("(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3724 /* Do this check before the hkey check */
3725 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3726 return ERROR_INVALID_PARAMETER
;
3728 lpkey
= lookup_hkey( hkey
);
3730 return ERROR_INVALID_HANDLE
;
3732 FIXME_(reg
)("(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3733 debugstr_w(lpszFile
));
3735 return ERROR_SUCCESS
;
3739 /******************************************************************************
3740 * RegLoadKey32A [ADVAPI32.???]
3742 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3745 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3746 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3747 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3748 if(lpszFileW
) free(lpszFileW
);
3749 if(lpszSubKeyW
) free(lpszSubKeyW
);
3754 /******************************************************************************
3755 * RegNotifyChangeKeyValue [ADVAPI32.???]
3758 * hkey [I] Handle of key to watch
3759 * fWatchSubTree [I] Flag for subkey notification
3760 * fdwNotifyFilter [I] Changes to be reported
3761 * hEvent [I] Handle of signaled event
3762 * fAsync [I] Flag for asynchronous reporting
3764 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3765 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3769 TRACE_(reg
)("(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3772 lpkey
= lookup_hkey( hkey
);
3774 return ERROR_INVALID_HANDLE
;
3776 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3779 return ERROR_SUCCESS
;
3783 /******************************************************************************
3784 * RegUnLoadKey32W [ADVAPI32.173]
3787 * hkey [I] Handle of open key
3788 * lpSubKey [I] Address of name of subkey to unload
3790 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3792 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3793 return ERROR_SUCCESS
;
3797 /******************************************************************************
3798 * RegUnLoadKey32A [ADVAPI32.172]
3800 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3803 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3804 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3805 if(lpSubKeyW
) free(lpSubKeyW
);
3810 /******************************************************************************
3811 * RegSetKeySecurity [ADVAPI32.167]
3814 * hkey [I] Open handle of key to set
3815 * SecurityInfo [I] Descriptor contents
3816 * pSecurityDesc [I] Address of descriptor for key
3818 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3819 PSECURITY_DESCRIPTOR pSecurityDesc
)
3823 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3825 /* It seems to perform this check before the hkey check */
3826 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3827 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3828 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3829 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3832 return ERROR_INVALID_PARAMETER
;
3835 return ERROR_INVALID_PARAMETER
;
3837 lpkey
= lookup_hkey( hkey
);
3839 return ERROR_INVALID_HANDLE
;
3841 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3843 return ERROR_SUCCESS
;
3847 /******************************************************************************
3848 * RegSaveKey32W [ADVAPI32.166]
3851 * hkey [I] Handle of key where save begins
3852 * lpFile [I] Address of filename to save to
3853 * sa [I] Address of security structure
3855 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3856 LPSECURITY_ATTRIBUTES sa
)
3860 TRACE_(reg
)("(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3862 /* It appears to do this check before the hkey check */
3863 if (!lpFile
|| !*lpFile
)
3864 return ERROR_INVALID_PARAMETER
;
3866 lpkey
= lookup_hkey( hkey
);
3868 return ERROR_INVALID_HANDLE
;
3870 FIXME_(reg
)("(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3872 return ERROR_SUCCESS
;
3876 /******************************************************************************
3877 * RegSaveKey32A [ADVAPI32.165]
3879 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3880 LPSECURITY_ATTRIBUTES sa
)
3883 LPWSTR lpFileW
= strdupA2W(lpFile
);
3884 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3890 /******************************************************************************
3891 * RegRestoreKey32W [ADVAPI32.164]
3894 * hkey [I] Handle of key where restore begins
3895 * lpFile [I] Address of filename containing saved tree
3896 * dwFlags [I] Optional flags
3898 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3902 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3904 /* It seems to do this check before the hkey check */
3905 if (!lpFile
|| !*lpFile
)
3906 return ERROR_INVALID_PARAMETER
;
3908 lpkey
= lookup_hkey( hkey
);
3910 return ERROR_INVALID_HANDLE
;
3912 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3914 /* Check for file existence */
3916 return ERROR_SUCCESS
;
3920 /******************************************************************************
3921 * RegRestoreKey32A [ADVAPI32.163]
3923 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3926 LPWSTR lpFileW
= strdupA2W(lpFile
);
3927 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3928 if(lpFileW
) free(lpFileW
);
3933 /******************************************************************************
3934 * RegReplaceKey32W [ADVAPI32.162]
3937 * hkey [I] Handle of open key
3938 * lpSubKey [I] Address of name of subkey
3939 * lpNewFile [I] Address of filename for file with new data
3940 * lpOldFile [I] Address of filename for backup file
3942 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3947 TRACE_(reg
)("(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3948 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3950 lpkey
= lookup_hkey( hkey
);
3952 return ERROR_INVALID_HANDLE
;
3954 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3955 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3957 return ERROR_SUCCESS
;
3961 /******************************************************************************
3962 * RegReplaceKey32A [ADVAPI32.161]
3964 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3968 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3969 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3970 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3971 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);