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 ret
= ERROR_MORE_DATA
;
2511 if (lpcbData
) /* size required ?*/
2512 { *lpcbData
= lpkey
->values
[i
].len
;
2515 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2517 TRACE_(reg
)(" (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2523 /******************************************************************************
2524 * RegQueryValue32W [ADVAPI32.159]
2526 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2532 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2533 lpcbData
?*lpcbData
:0);
2535 /* Only open subkey, if we really do descend */
2536 if (lpszSubKey
&& *lpszSubKey
) {
2537 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2538 if (ret
!= ERROR_SUCCESS
) {
2539 WARN_(reg
)("Could not open %s\n", debugstr_w(lpszSubKey
));
2546 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2554 /******************************************************************************
2555 * RegQueryValueEx32A [ADVAPI32.157]
2558 * the documantation is wrong: if the buffer is to small it remains untouched
2560 * FIXME: check returnvalue (len) for an empty key
2562 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2563 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2564 LPBYTE lpbData
, LPDWORD lpcbData
)
2566 LPWSTR lpszValueNameW
;
2567 LPBYTE mybuf
= NULL
;
2568 DWORD ret
, mytype
, mylen
= 0;
2570 TRACE_(reg
)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2571 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2573 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2574 { return ERROR_INVALID_PARAMETER
;
2577 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2579 /* get just the type first */
2580 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2582 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2583 { if(lpszValueNameW
) free(lpszValueNameW
);
2587 if (lpcbData
) /* at least length requested? */
2588 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2589 { if (lpbData
) /* value requested? */
2590 { mylen
= 2*( *lpcbData
);
2591 mybuf
= (LPBYTE
)xmalloc( mylen
);
2594 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2596 if (ret
== ERROR_SUCCESS
)
2598 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2602 *lpcbData
= mylen
/2; /* size is in byte! */
2604 else /* no strings, call it straight */
2605 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2609 if (lpdwType
) /* type when requested */
2610 { *lpdwType
= mytype
;
2613 TRACE_(reg
)(" (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2615 if(mybuf
) free(mybuf
);
2616 if(lpszValueNameW
) free(lpszValueNameW
);
2621 /******************************************************************************
2622 * RegQueryValueEx16 [KERNEL.225]
2624 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2625 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2626 LPBYTE lpbData
, LPDWORD lpcbData
)
2628 TRACE_(reg
)("(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2629 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2630 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2631 lpbData
, lpcbData
);
2635 /******************************************************************************
2636 * RegQueryValue32A [ADVAPI32.156]
2638 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2644 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2645 lpcbData
?*lpcbData
:0);
2647 if (lpszSubKey
&& *lpszSubKey
) {
2648 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2649 if( ret
!= ERROR_SUCCESS
)
2655 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2658 RegCloseKey( xhkey
);
2663 /******************************************************************************
2664 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2667 * Is this HACK still applicable?
2670 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2671 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2674 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2677 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2678 lpcbData
?*lpcbData
:0);
2681 *lpcbData
&= 0xFFFF;
2682 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2687 * Setting values of Registry keys
2690 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2691 * RegSetValue32W -> RegSetValueEx32W
2695 /******************************************************************************
2696 * RegSetValueEx32W [ADVAPI32.170]
2697 * Sets the data and type of a value under a register key
2700 * hkey [I] Handle of key to set value for
2701 * lpszValueName [I] Name of value to set
2702 * dwReserved [I] Reserved - must be zero
2703 * dwType [I] Flag for value type
2704 * lpbData [I] Address of value data
2705 * cbData [I] Size of value data
2708 * Success: ERROR_SUCCESS
2709 * Failure: Error code
2712 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2714 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR lpszValueName
,
2715 DWORD dwReserved
, DWORD dwType
,
2716 CONST BYTE
*lpbData
, DWORD cbData
)
2721 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2722 dwReserved
, dwType
, lpbData
, cbData
);
2724 lpkey
= lookup_hkey( hkey
);
2727 return ERROR_INVALID_HANDLE
;
2729 lpkey
->flags
|= REG_OPTION_TAINTED
;
2731 if (lpszValueName
==NULL
) {
2732 /* Sets type and name for key's unnamed or default value */
2733 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2734 if (lpkey
->values
[i
].name
==NULL
)
2737 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2738 if ( lpkey
->values
[i
].name
&&
2739 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2743 if (i
==lpkey
->nrofvalues
) {
2744 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2746 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2748 lpkey
->nrofvalues
++;
2749 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2751 if (lpkey
->values
[i
].name
==NULL
) {
2753 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2755 lpkey
->values
[i
].name
= NULL
;
2758 if (dwType
== REG_SZ
)
2759 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2761 lpkey
->values
[i
].len
= cbData
;
2762 lpkey
->values
[i
].type
= dwType
;
2763 if (lpkey
->values
[i
].data
!=NULL
)
2764 free(lpkey
->values
[i
].data
);
2765 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2766 lpkey
->values
[i
].lastmodified
= time(NULL
);
2767 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2768 return ERROR_SUCCESS
;
2772 /******************************************************************************
2773 * RegSetValueEx32A [ADVAPI32.169]
2776 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2778 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2779 DWORD dwReserved
, DWORD dwType
,
2780 CONST BYTE
*lpbData
, DWORD cbData
)
2783 LPWSTR lpszValueNameW
;
2787 return (ERROR_INVALID_PARAMETER
);
2789 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2790 dwReserved
,dwType
,lpbData
,cbData
);
2792 if ((1<<dwType
) & UNICONVMASK
)
2793 { if (dwType
== REG_SZ
)
2794 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2796 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2797 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2801 buf
=(LPBYTE
)lpbData
;
2804 lpszValueNameW
= strdupA2W(lpszValueName
);
2806 lpszValueNameW
= NULL
;
2808 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2811 free(lpszValueNameW
);
2820 /******************************************************************************
2821 * RegSetValueEx16 [KERNEL.226]
2823 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2824 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2826 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2827 dwReserved
,dwType
,lpbData
,cbData
);
2828 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2833 /******************************************************************************
2834 * RegSetValue32W [ADVAPI32.171]
2836 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2837 LPCWSTR lpszData
, DWORD cbData
)
2842 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",
2843 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2845 if (lpszSubKey
&& *lpszSubKey
) {
2846 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2847 if (ret
!=ERROR_SUCCESS
)
2851 if (dwType
!=REG_SZ
) {
2852 TRACE_(reg
)("dwType=%ld - Changing to REG_SZ\n",dwType
);
2855 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2856 TRACE_(reg
)("Len=%ld != strlen(%s)+1=%d!\n",
2857 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2859 cbData
=2*lstrlenW(lpszData
)+2;
2861 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2868 /******************************************************************************
2869 * RegSetValue32A [ADVAPI32.168]
2872 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2873 LPCSTR lpszData
, DWORD cbData
)
2878 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2879 if (lpszSubKey
&& *lpszSubKey
) {
2880 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2881 if (ret
!=ERROR_SUCCESS
)
2886 if (dwType
!=REG_SZ
) {
2887 TRACE_(reg
)("dwType=%ld!\n",dwType
);
2890 if (cbData
!=strlen(lpszData
)+1)
2891 cbData
=strlen(lpszData
)+1;
2892 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2899 /******************************************************************************
2900 * RegSetValue16 [KERNEL.221] [SHELL.5]
2902 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2903 LPCSTR lpszData
, DWORD cbData
)
2905 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2906 debugstr_a(lpszData
),cbData
);
2907 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2915 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2916 * RegEnumKey32W -> RegEnumKeyEx32W
2920 /******************************************************************************
2921 * RegEnumKeyEx32W [ADVAPI32.139]
2924 * hkey [I] Handle to key to enumerate
2925 * iSubKey [I] Index of subkey to enumerate
2926 * lpszName [O] Buffer for subkey name
2927 * lpcchName [O] Size of subkey buffer
2928 * lpdwReserved [I] Reserved
2929 * lpszClass [O] Buffer for class string
2930 * lpcchClass [O] Size of class buffer
2931 * ft [O] Time key last written to
2933 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2934 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2935 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2938 LPKEYSTRUCT lpkey
,lpxkey
;
2940 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2941 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2943 lpkey
= lookup_hkey( hkey
);
2945 return ERROR_INVALID_HANDLE
;
2947 if (!lpkey
->nextsub
)
2948 return ERROR_NO_MORE_ITEMS
;
2949 lpxkey
=lpkey
->nextsub
;
2951 /* Traverse the subkeys */
2952 while (iSubkey
&& lpxkey
) {
2954 lpxkey
=lpxkey
->next
;
2957 if (iSubkey
|| !lpxkey
)
2958 return ERROR_NO_MORE_ITEMS
;
2959 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
2960 return ERROR_MORE_DATA
;
2961 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
2964 *lpcchName
= lstrlenW(lpszName
);
2967 /* FIXME: what should we write into it? */
2971 return ERROR_SUCCESS
;
2975 /******************************************************************************
2976 * RegEnumKey32W [ADVAPI32.140]
2978 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2983 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2984 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2988 /******************************************************************************
2989 * RegEnumKeyEx32A [ADVAPI32.138]
2991 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2992 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2993 LPSTR lpszClass
, LPDWORD lpcchClass
,
2996 DWORD ret
,lpcchNameW
,lpcchClassW
;
2997 LPWSTR lpszNameW
,lpszClassW
;
3000 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3001 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3004 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3005 lpcchNameW
= *lpcchName
;
3011 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3012 lpcchClassW
= *lpcchClass
;
3027 if (ret
==ERROR_SUCCESS
) {
3028 lstrcpyWtoA(lpszName
,lpszNameW
);
3029 *lpcchName
=strlen(lpszName
);
3031 lstrcpyWtoA(lpszClass
,lpszClassW
);
3032 *lpcchClass
=strlen(lpszClass
);
3043 /******************************************************************************
3044 * RegEnumKey32A [ADVAPI32.137]
3046 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3051 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3052 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3057 /******************************************************************************
3058 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3060 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3063 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3064 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3069 * Enumerate Registry Values
3072 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3076 /******************************************************************************
3077 * RegEnumValue32W [ADVAPI32.142]
3080 * hkey [I] Handle to key to query
3081 * iValue [I] Index of value to query
3082 * lpszValue [O] Value string
3083 * lpcchValue [I/O] Size of value buffer (in wchars)
3084 * lpdReserved [I] Reserved
3085 * lpdwType [O] Type code
3086 * lpbData [O] Value data
3087 * lpcbData [I/O] Size of data buffer (in bytes)
3089 * Note: wide character functions that take and/or return "character counts"
3090 * use TCHAR (that is unsigned short or char) not byte counts.
3092 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3093 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3094 LPDWORD lpdwType
, LPBYTE lpbData
,
3100 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3101 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3103 lpkey
= lookup_hkey( hkey
);
3105 if (!lpcbData
&& lpbData
)
3106 return ERROR_INVALID_PARAMETER
;
3109 return ERROR_INVALID_HANDLE
;
3111 if (lpkey
->nrofvalues
<= iValue
)
3112 return ERROR_NO_MORE_ITEMS
;
3114 val
= &(lpkey
->values
[iValue
]);
3117 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3118 *lpcchValue
= lstrlenW(val
->name
)+1;
3119 return ERROR_MORE_DATA
;
3121 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3122 *lpcchValue
=lstrlenW(val
->name
);
3128 /* Can be NULL if the type code is not required */
3130 *lpdwType
= val
->type
;
3133 if (val
->len
>*lpcbData
)
3134 return ERROR_MORE_DATA
;
3135 memcpy(lpbData
,val
->data
,val
->len
);
3136 *lpcbData
= val
->len
;
3139 debug_print_value ( val
->data
, val
);
3140 return ERROR_SUCCESS
;
3144 /******************************************************************************
3145 * RegEnumValue32A [ADVAPI32.141]
3147 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3148 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3149 LPDWORD lpdwType
, LPBYTE lpbData
,
3154 DWORD ret
,lpcbDataW
;
3157 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3158 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3160 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3162 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3163 lpcbDataW
= *lpcbData
;
3167 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3168 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3173 if (ret
==ERROR_SUCCESS
) {
3174 lstrcpyWtoA(lpszValue
,lpszValueW
);
3176 if ((1<<dwType
) & UNICONVMASK
) {
3177 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3179 if (lpcbDataW
> *lpcbData
)
3180 ret
= ERROR_MORE_DATA
;
3182 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3184 *lpcbData
= lpcbDataW
;
3187 if (lpbDataW
) free(lpbDataW
);
3188 if (lpszValueW
) free(lpszValueW
);
3193 /******************************************************************************
3194 * RegEnumValue16 [KERNEL.223]
3196 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3197 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3198 LPDWORD lpdwType
, LPBYTE lpbData
,
3201 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3202 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3203 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3204 lpdwType
, lpbData
, lpcbData
);
3208 /******************************************************************************
3209 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3210 * Releases the handle of the specified key
3213 * hkey [I] Handle of key to close
3216 * Success: ERROR_SUCCESS
3217 * Failure: Error code
3219 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3221 TRACE_(reg
)("(%x)\n",hkey
);
3223 /* The standard handles are allowed to succeed, even though they are not
3225 if (is_standard_hkey(hkey
))
3226 return ERROR_SUCCESS
;
3228 return remove_handle(hkey
);
3233 * Delete registry key
3236 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3240 /******************************************************************************
3241 * RegDeleteKey32W [ADVAPI32.134]
3244 * hkey [I] Handle to open key
3245 * lpszSubKey [I] Name of subkey to delete
3248 * Success: ERROR_SUCCESS
3249 * Failure: Error code
3251 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR lpszSubKey
)
3253 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3257 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3259 lpNextKey
= lookup_hkey(hkey
);
3261 return ERROR_INVALID_HANDLE
;
3263 /* Subkey param cannot be NULL */
3264 if (!lpszSubKey
|| !*lpszSubKey
)
3265 return ERROR_BADKEY
;
3267 /* We need to know the previous key in the hier. */
3268 split_keypath(lpszSubKey
,&wps
,&wpc
);
3272 lpxkey
=lpNextKey
->nextsub
;
3274 TRACE_(reg
)(" Scanning [%s]\n",
3275 debugstr_w(lpxkey
->keyname
));
3276 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3278 lpxkey
=lpxkey
->next
;
3282 TRACE_(reg
)(" Not found.\n");
3283 /* not found is success */
3284 return ERROR_SUCCESS
;
3289 lpxkey
= lpNextKey
->nextsub
;
3290 lplpPrevKey
= &(lpNextKey
->nextsub
);
3292 TRACE_(reg
)(" Scanning [%s]\n",
3293 debugstr_w(lpxkey
->keyname
));
3294 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3296 lplpPrevKey
= &(lpxkey
->next
);
3297 lpxkey
= lpxkey
->next
;
3302 WARN_(reg
)(" Not found.\n");
3303 return ERROR_FILE_NOT_FOUND
;
3306 if (lpxkey
->nextsub
) {
3308 WARN_(reg
)(" Not empty.\n");
3309 return ERROR_CANTWRITE
;
3311 *lplpPrevKey
= lpxkey
->next
;
3312 free(lpxkey
->keyname
);
3314 free(lpxkey
->class);
3316 free(lpxkey
->values
);
3319 TRACE_(reg
)(" Done.\n");
3320 return ERROR_SUCCESS
;
3324 /******************************************************************************
3325 * RegDeleteKey32A [ADVAPI32.133]
3327 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3332 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3333 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3334 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3335 if(lpszSubKeyW
) free(lpszSubKeyW
);
3340 /******************************************************************************
3341 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3343 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3345 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3346 return RegDeleteKeyA( hkey
, lpszSubKey
);
3351 * Delete registry value
3354 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3358 /******************************************************************************
3359 * RegDeleteValue32W [ADVAPI32.136]
3367 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR lpszValue
)
3373 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3375 lpkey
= lookup_hkey( hkey
);
3377 return ERROR_INVALID_HANDLE
;
3380 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3381 if ( lpkey
->values
[i
].name
&&
3382 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3386 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3387 if (lpkey
->values
[i
].name
==NULL
)
3391 if (i
== lpkey
->nrofvalues
)
3392 return ERROR_FILE_NOT_FOUND
;
3394 val
= lpkey
->values
+i
;
3395 if (val
->name
) free(val
->name
);
3396 if (val
->data
) free(val
->data
);
3400 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3402 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3404 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3406 lpkey
->nrofvalues
--;
3407 return ERROR_SUCCESS
;
3411 /******************************************************************************
3412 * RegDeleteValue32A [ADVAPI32.135]
3414 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR lpszValue
)
3419 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3420 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3421 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3422 if(lpszValueW
) free(lpszValueW
);
3427 /******************************************************************************
3428 * RegDeleteValue16 [KERNEL.222]
3430 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3432 TRACE_(reg
)("(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3433 return RegDeleteValueA( hkey
, lpszValue
);
3437 /******************************************************************************
3438 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3439 * Writes key to registry
3442 * hkey [I] Handle of key to write
3445 * Success: ERROR_SUCCESS
3446 * Failure: Error code
3448 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3453 TRACE_(reg
)("(%x)\n", hkey
);
3455 lpkey
= lookup_hkey( hkey
);
3457 return ERROR_BADKEY
;
3459 ERR_(reg
)("What is the correct filename?\n");
3461 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3464 return ERROR_SUCCESS
;
3466 return ERROR_UNKNOWN
; /* FIXME */
3470 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3473 /******************************************************************************
3474 * RegQueryInfoKey32W [ADVAPI32.153]
3477 * hkey [I] Handle to key to query
3478 * lpszClass [O] Buffer for class string
3479 * lpcchClass [O] Size of class string buffer
3480 * lpdwReserved [I] Reserved
3481 * lpcSubKeys [I] Buffer for number of subkeys
3482 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3483 * lpcchMaxClass [O] Buffer for longest class string length
3484 * lpcValues [O] Buffer for number of value entries
3485 * lpcchMaxValueName [O] Buffer for longest value name length
3486 * lpccbMaxValueData [O] Buffer for longest value data length
3487 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3489 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3490 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3491 * lpcchClass is NULL
3492 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3493 * (it's hard to test validity, so test !NULL instead)
3495 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3496 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3497 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3498 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3499 LPDWORD lpcchMaxValueName
,
3500 LPDWORD lpccbMaxValueData
,
3501 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3503 LPKEYSTRUCT lpkey
,lpxkey
;
3504 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3507 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3508 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3509 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3510 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3512 lpkey
= lookup_hkey(hkey
);
3514 return ERROR_INVALID_HANDLE
;
3516 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3517 return ERROR_INVALID_PARAMETER
;
3519 /* either lpcchClass is valid or this is win95 and lpcchClass
3522 DWORD classLen
= lstrlenW(lpkey
->class);
3524 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3525 *lpcchClass
=classLen
+1;
3526 return ERROR_MORE_DATA
;
3529 *lpcchClass
=classLen
;
3530 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3538 *lpcchClass
= lstrlenW(lpkey
->class);
3540 lpxkey
=lpkey
->nextsub
;
3541 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3544 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3545 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3546 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3547 maxclass
=lstrlenW(lpxkey
->class);
3548 lpxkey
=lpxkey
->next
;
3550 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3551 LPKEYVALUE val
=lpkey
->values
+i
;
3553 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3554 maxvname
=lstrlenW(val
->name
);
3555 if (val
->len
>maxvdata
)
3558 if (!maxclass
) maxclass
= 1;
3559 if (!maxvname
) maxvname
= 1;
3561 *lpcValues
= lpkey
->nrofvalues
;
3563 *lpcSubKeys
= nrofkeys
;
3565 *lpcchMaxSubkey
= maxsubkey
;
3567 *lpcchMaxClass
= maxclass
;
3568 if (lpcchMaxValueName
)
3569 *lpcchMaxValueName
= maxvname
;
3570 if (lpccbMaxValueData
)
3571 *lpccbMaxValueData
= maxvdata
;
3572 return ERROR_SUCCESS
;
3576 /******************************************************************************
3577 * RegQueryInfoKey32A [ADVAPI32.152]
3579 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3580 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3581 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3582 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3583 LPDWORD lpccbMaxValueData
,
3584 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3586 LPWSTR lpszClassW
= NULL
;
3589 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3590 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3591 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3592 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3596 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3597 } else if (VERSION_GetVersion() == WIN95
) {
3598 /* win95 allows lpcchClass to be null */
3599 /* we don't know how big lpszClass is, would
3600 MAX_PATHNAME_LEN be the correct default? */
3601 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3606 ret
=RegQueryInfoKeyW(
3617 lpcbSecurityDescriptor
,
3620 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3621 lstrcpyWtoA(lpszClass
,lpszClassW
);
3628 /******************************************************************************
3629 * RegConnectRegistry32W [ADVAPI32.128]
3632 * lpMachineName [I] Address of name of remote computer
3633 * hHey [I] Predefined registry handle
3634 * phkResult [I] Address of buffer for remote registry handle
3636 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3639 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3641 if (!lpMachineName
|| !*lpMachineName
) {
3642 /* Use the local machine name */
3643 return RegOpenKey16( hKey
, "", phkResult
);
3646 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
3647 return ERROR_BAD_NETPATH
;
3651 /******************************************************************************
3652 * RegConnectRegistry32A [ADVAPI32.127]
3654 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3657 LPWSTR machineW
= strdupA2W(machine
);
3658 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3664 /******************************************************************************
3665 * RegGetKeySecurity [ADVAPI32.144]
3666 * Retrieves a copy of security descriptor protecting the registry key
3669 * hkey [I] Open handle of key to set
3670 * SecurityInformation [I] Descriptor contents
3671 * pSecurityDescriptor [O] Address of descriptor for key
3672 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3675 * Success: ERROR_SUCCESS
3676 * Failure: Error code
3678 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3679 SECURITY_INFORMATION SecurityInformation
,
3680 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3681 LPDWORD lpcbSecurityDescriptor
)
3685 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3686 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3688 lpkey
= lookup_hkey( hkey
);
3690 return ERROR_INVALID_HANDLE
;
3692 /* FIXME: Check for valid SecurityInformation values */
3694 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3695 return ERROR_INSUFFICIENT_BUFFER
;
3697 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3698 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3700 return ERROR_SUCCESS
;
3704 /******************************************************************************
3705 * RegLoadKey32W [ADVAPI32.???]
3708 * hkey [I] Handle of open key
3709 * lpszSubKey [I] Address of name of subkey
3710 * lpszFile [I] Address of filename for registry information
3712 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3715 TRACE_(reg
)("(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3717 /* Do this check before the hkey check */
3718 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3719 return ERROR_INVALID_PARAMETER
;
3721 lpkey
= lookup_hkey( hkey
);
3723 return ERROR_INVALID_HANDLE
;
3725 FIXME_(reg
)("(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3726 debugstr_w(lpszFile
));
3728 return ERROR_SUCCESS
;
3732 /******************************************************************************
3733 * RegLoadKey32A [ADVAPI32.???]
3735 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3738 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3739 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3740 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3741 if(lpszFileW
) free(lpszFileW
);
3742 if(lpszSubKeyW
) free(lpszSubKeyW
);
3747 /******************************************************************************
3748 * RegNotifyChangeKeyValue [ADVAPI32.???]
3751 * hkey [I] Handle of key to watch
3752 * fWatchSubTree [I] Flag for subkey notification
3753 * fdwNotifyFilter [I] Changes to be reported
3754 * hEvent [I] Handle of signaled event
3755 * fAsync [I] Flag for asynchronous reporting
3757 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3758 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3762 TRACE_(reg
)("(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3765 lpkey
= lookup_hkey( hkey
);
3767 return ERROR_INVALID_HANDLE
;
3769 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3772 return ERROR_SUCCESS
;
3776 /******************************************************************************
3777 * RegUnLoadKey32W [ADVAPI32.173]
3780 * hkey [I] Handle of open key
3781 * lpSubKey [I] Address of name of subkey to unload
3783 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3785 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3786 return ERROR_SUCCESS
;
3790 /******************************************************************************
3791 * RegUnLoadKey32A [ADVAPI32.172]
3793 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3796 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3797 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3798 if(lpSubKeyW
) free(lpSubKeyW
);
3803 /******************************************************************************
3804 * RegSetKeySecurity [ADVAPI32.167]
3807 * hkey [I] Open handle of key to set
3808 * SecurityInfo [I] Descriptor contents
3809 * pSecurityDesc [I] Address of descriptor for key
3811 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3812 PSECURITY_DESCRIPTOR pSecurityDesc
)
3816 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3818 /* It seems to perform this check before the hkey check */
3819 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3820 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3821 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3822 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3825 return ERROR_INVALID_PARAMETER
;
3828 return ERROR_INVALID_PARAMETER
;
3830 lpkey
= lookup_hkey( hkey
);
3832 return ERROR_INVALID_HANDLE
;
3834 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3836 return ERROR_SUCCESS
;
3840 /******************************************************************************
3841 * RegSaveKey32W [ADVAPI32.166]
3844 * hkey [I] Handle of key where save begins
3845 * lpFile [I] Address of filename to save to
3846 * sa [I] Address of security structure
3848 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3849 LPSECURITY_ATTRIBUTES sa
)
3853 TRACE_(reg
)("(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3855 /* It appears to do this check before the hkey check */
3856 if (!lpFile
|| !*lpFile
)
3857 return ERROR_INVALID_PARAMETER
;
3859 lpkey
= lookup_hkey( hkey
);
3861 return ERROR_INVALID_HANDLE
;
3863 FIXME_(reg
)("(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3865 return ERROR_SUCCESS
;
3869 /******************************************************************************
3870 * RegSaveKey32A [ADVAPI32.165]
3872 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3873 LPSECURITY_ATTRIBUTES sa
)
3876 LPWSTR lpFileW
= strdupA2W(lpFile
);
3877 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3883 /******************************************************************************
3884 * RegRestoreKey32W [ADVAPI32.164]
3887 * hkey [I] Handle of key where restore begins
3888 * lpFile [I] Address of filename containing saved tree
3889 * dwFlags [I] Optional flags
3891 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3895 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3897 /* It seems to do this check before the hkey check */
3898 if (!lpFile
|| !*lpFile
)
3899 return ERROR_INVALID_PARAMETER
;
3901 lpkey
= lookup_hkey( hkey
);
3903 return ERROR_INVALID_HANDLE
;
3905 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3907 /* Check for file existence */
3909 return ERROR_SUCCESS
;
3913 /******************************************************************************
3914 * RegRestoreKey32A [ADVAPI32.163]
3916 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3919 LPWSTR lpFileW
= strdupA2W(lpFile
);
3920 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3921 if(lpFileW
) free(lpFileW
);
3926 /******************************************************************************
3927 * RegReplaceKey32W [ADVAPI32.162]
3930 * hkey [I] Handle of open key
3931 * lpSubKey [I] Address of name of subkey
3932 * lpNewFile [I] Address of filename for file with new data
3933 * lpOldFile [I] Address of filename for backup file
3935 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3940 TRACE_(reg
)("(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3941 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3943 lpkey
= lookup_hkey( hkey
);
3945 return ERROR_INVALID_HANDLE
;
3947 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3948 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3950 return ERROR_SUCCESS
;
3954 /******************************************************************************
3955 * RegReplaceKey32A [ADVAPI32.161]
3957 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3961 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3962 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3963 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3964 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);