4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
7 * December 21, 1997 - Kevin Cozens
8 * Fixed bugs in the _w95_loadreg() function. Added extra information
9 * regarding the format of the Windows '95 registry files.
12 * When changing this file, please re-run the regtest program to ensure
13 * the conditions are handled properly.
18 * Time for RegEnumKey*, RegQueryInfoKey*
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
43 #include "winversion.h"
45 static void REGISTRY_Init(void);
46 /* FIXME: following defines should be configured global ... */
48 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
49 #define WINE_PREFIX "/.wine"
50 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
51 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
53 /* relative in ~user/.wine/ : */
54 #define SAVE_CURRENT_USER "user.reg"
55 #define SAVE_LOCAL_MACHINE "system.reg"
57 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
58 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
60 /* one value of a key */
61 typedef struct tagKEYVALUE
63 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
64 DWORD type
; /* type of value */
65 DWORD len
; /* length of data in BYTEs */
66 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
67 LPBYTE data
; /* content, may be strings, binaries, etc. */
68 } KEYVALUE
,*LPKEYVALUE
;
71 typedef struct tagKEYSTRUCT
73 LPWSTR keyname
; /* name of THIS key (UNICODE) */
74 DWORD flags
; /* flags. */
77 DWORD nrofvalues
; /* nr of values in THIS key */
78 LPKEYVALUE values
; /* values in THIS key */
79 /* key management pointers */
80 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
81 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
82 } KEYSTRUCT
, *LPKEYSTRUCT
;
85 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
86 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
87 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
88 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
90 /* dynamic, not saved */
91 static KEYSTRUCT
*key_performance_data
=NULL
;
92 static KEYSTRUCT
*key_current_config
=NULL
;
93 static KEYSTRUCT
*key_dyn_data
=NULL
;
95 /* what valuetypes do we need to convert? */
96 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
99 static struct openhandle
{
104 static int nrofopenhandles
=0;
105 /* Starts after 1 because 0,1 are reserved for Win16 */
106 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
107 HKEYs for remote registry access */
108 static int currenthandle
=2;
113 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
114 * If so, can we remove them?
116 * No, the memory handling functions are called very often in here,
117 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
118 * loading 100 times slower. -MM
120 static LPWSTR
strdupA2W(LPCSTR src
)
123 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
124 lstrcpyAtoW(dest
,src
);
130 static LPWSTR
strdupW(LPCWSTR a
) {
135 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
136 b
=(LPWSTR
)xmalloc(len
);
143 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
146 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
148 lstrcpynAtoW(dest
,src
,nchars
+1);
153 * we need to convert A to W with '\0' in strings (MULTI_SZ)
156 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
159 TRACE(reg
,"\"%s\" %i\n",src
, n
);
161 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
165 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
168 TRACE(string
,"L\"%s\" %i\n",debugstr_w(src
), n
);
170 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
175 static void debug_print_value (LPBYTE lpbData
, DWORD type
, DWORD len
)
176 { if (TRACE_ON(reg
) && lpbData
)
179 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
183 TRACE(reg
," Data(dword)=0x%08lx\n",(DWORD
)*lpbData
);
188 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
190 { TRACE(reg
, " MULTI_SZ(%i=%s)\n", i
, debugstr_w(ptr
));
191 ptr
+= lstrlenW(ptr
)+1;
197 { char szTemp
[100]; /* 3*32 + 3 + 1 */
199 for ( i
= 0; i
< len
; i
++)
200 { sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
202 { sprintf (&(szTemp
[i
*3+3]),"...");
206 TRACE(reg
," Data(raw)=(%s)\n", szTemp
);
211 FIXME(reg
, " Unknown data type %ld\n", type
);
218 /******************************************************************************
219 * is_standard_hkey [Internal]
220 * Determines if a hkey is a standard key
222 static BOOL
is_standard_hkey( HKEY hkey
)
227 case HKEY_CLASSES_ROOT
:
228 case HKEY_CURRENT_CONFIG
:
229 case HKEY_CURRENT_USER
:
230 case HKEY_LOCAL_MACHINE
:
232 case HKEY_PERFORMANCE_DATA
:
240 /******************************************************************************
241 * add_handle [Internal]
243 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
247 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
248 /* Check for duplicates */
249 for (i
=0;i
<nrofopenhandles
;i
++) {
250 if (openhandles
[i
].lpkey
==lpkey
) {
251 /* This is not really an error - the user is allowed to create
252 two (or more) handles to the same key */
253 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
255 if (openhandles
[i
].hkey
==hkey
) {
256 WARN(reg
, "Adding handle %x twice\n",hkey
);
259 openhandles
=xrealloc( openhandles
,
260 sizeof(struct openhandle
)*(nrofopenhandles
+1));
262 openhandles
[i
].lpkey
= lpkey
;
263 openhandles
[i
].hkey
= hkey
;
264 openhandles
[i
].accessmask
= accessmask
;
269 /******************************************************************************
270 * get_handle [Internal]
273 * Success: Pointer to key
276 static LPKEYSTRUCT
get_handle( HKEY hkey
)
280 for (i
=0; i
<nrofopenhandles
; i
++)
281 if (openhandles
[i
].hkey
== hkey
)
282 return openhandles
[i
].lpkey
;
283 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
288 /******************************************************************************
289 * remove_handle [Internal]
292 * hkey [I] Handle of key to remove
295 * Success: ERROR_SUCCESS
296 * Failure: ERROR_INVALID_HANDLE
298 static DWORD
remove_handle( HKEY hkey
)
302 for (i
=0;i
<nrofopenhandles
;i
++)
303 if (openhandles
[i
].hkey
==hkey
)
306 if (i
== nrofopenhandles
) {
307 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
308 return ERROR_INVALID_HANDLE
;
311 memcpy( openhandles
+i
,
313 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
315 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
317 return ERROR_SUCCESS
;
320 /******************************************************************************
321 * lookup_hkey [Internal]
323 * Just as the name says. Creates the root keys on demand, so we can call the
324 * Reg* functions at any time.
327 * Success: Pointer to key structure
330 #define ADD_ROOT_KEY(xx) \
331 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
332 memset(xx,'\0',sizeof(KEYSTRUCT));\
333 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
335 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
338 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
339 * some programs. Do not remove those cases. -MM
343 case HKEY_CLASSES_ROOT
: {
344 if (!key_classes_root
) {
347 /* calls lookup_hkey recursively, TWICE */
348 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
349 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
352 key_classes_root
= lookup_hkey(cl_r_hkey
);
354 return key_classes_root
;
356 case HKEY_CURRENT_USER
:
357 if (!key_current_user
) {
361 pwd
=getpwuid(getuid());
362 /* calls lookup_hkey recursively, TWICE */
363 if (pwd
&& pwd
->pw_name
) {
364 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
365 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
368 key_current_user
= lookup_hkey(c_u_hkey
);
370 /* nothing found, use standalone */
371 ADD_ROOT_KEY(key_current_user
);
374 return key_current_user
;
375 case HKEY_LOCAL_MACHINE
:
376 if (!key_local_machine
) {
377 ADD_ROOT_KEY(key_local_machine
);
380 return key_local_machine
;
383 ADD_ROOT_KEY(key_users
);
386 case HKEY_PERFORMANCE_DATA
:
387 if (!key_performance_data
) {
388 ADD_ROOT_KEY(key_performance_data
);
390 return key_performance_data
;
393 ADD_ROOT_KEY(key_dyn_data
);
396 case HKEY_CURRENT_CONFIG
:
397 if (!key_current_config
) {
398 ADD_ROOT_KEY(key_current_config
);
400 return key_current_config
;
402 return get_handle(hkey
);
407 /* so we don't accidently access them ... */
408 #define key_current_config NULL NULL
409 #define key_current_user NULL NULL
410 #define key_users NULL NULL
411 #define key_local_machine NULL NULL
412 #define key_classes_root NULL NULL
413 #define key_dyn_data NULL NULL
414 #define key_performance_data NULL NULL
416 /******************************************************************************
417 * split_keypath [Internal]
418 * splits the unicode string 'wp' into an array of strings.
419 * the array is allocated by this function.
420 * Free the array using FREE_KEY_PATH
423 * wp [I] String to split up
424 * wpv [O] Array of pointers to strings
425 * wpc [O] Number of components
427 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
432 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
434 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
436 /* We know we have at least one substring */
439 /* Replace each backslash with NULL, and increment the count */
440 for (i
=0;ws
[i
];i
++) {
449 /* Allocate the space for the array of pointers, leaving room for the
451 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
454 /* Assign each pointer to the appropriate character in the string */
459 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
464 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
469 /******************************************************************************
470 * REGISTRY_Init [Internal]
471 * Registry initialisation, allocates some default keys.
473 static void REGISTRY_Init(void) {
477 TRACE(reg
,"(void)\n");
479 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
482 /* This was an Open, but since it is called before the real registries
483 are loaded, it was changed to a Create - MTB 980507*/
484 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
485 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
488 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
492 * string RegisteredOwner
493 * string RegisteredOrganization
496 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
501 if (-1!=gethostname(buf
,200)) {
502 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
503 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
509 /************************ SAVE Registry Function ****************************/
511 #define REGISTRY_SAVE_VERSION 0x00000001
513 /* Registry saveformat:
514 * If you change it, increase above number by 1, which will flush
515 * old registry database files.
518 * "WINE REGISTRY Version %d"
522 * valuename=lastmodified,type,data
526 * keyname,valuename,stringdata:
527 * the usual ascii characters from 0x00-0xff (well, not 0x00)
528 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
529 * ( "=\\\t" escaped in \uXXXX form.)
533 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
535 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
536 * SaveOnlyUpdatedKeys=yes
539 /******************************************************************************
540 * _save_check_tainted [Internal]
542 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
548 if (lpkey
->flags
& REG_OPTION_TAINTED
)
553 if (_save_check_tainted(lpkey
->nextsub
)) {
554 lpkey
->flags
|= REG_OPTION_TAINTED
;
562 /******************************************************************************
563 * _save_USTRING [Internal]
565 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
579 if (escapeeq
&& *s
=='=')
582 fputc(*s
,F
); /* if \\ then put it twice. */
584 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
591 /******************************************************************************
592 * _savesubkey [Internal]
595 * REG_MULTI_SZ is handled as binary (like in win95) (js)
597 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
604 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
605 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
607 for (tabs
=level
;tabs
--;)
609 _save_USTRING(F
,lpxkey
->keyname
,1);
611 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
612 LPKEYVALUE val
=lpxkey
->values
+i
;
614 for (tabs
=level
+1;tabs
--;)
616 _save_USTRING(F
,val
->name
,0);
618 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
619 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
620 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
622 for (j
=0;j
<val
->len
;j
++)
623 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
626 /* descend recursively */
627 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
636 /******************************************************************************
637 * _savesubreg [Internal]
639 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
641 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
642 _save_check_tainted(lpkey
->nextsub
);
643 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
647 /******************************************************************************
648 * _savereg [Internal]
650 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
656 WARN(reg
,"Couldn't open %s for writing: %s\n",
661 if (!_savesubreg(F
,lpkey
,all
)) {
664 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
672 /******************************************************************************
673 * SHELL_SaveRegistry [Internal]
675 void SHELL_SaveRegistry( void )
685 TRACE(reg
,"(void)\n");
688 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
694 if ( (ERROR_SUCCESS
!=RegQueryValueExA(
706 if (lstrcmpiA(buf
,"yes"))
709 /* Try saving a config file specified User.reg save/load name */
710 fn
= xmalloc( MAX_PATHNAME_LEN
);
711 if (PROFILE_GetWineIniString ("Registry", "UserFileName", "", fn
, MAX_PATHNAME_LEN
- 1)) {
712 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
717 /* Try saving a config file specified System.reg save/load name*/
718 fn
= xmalloc ( MAX_PATHNAME_LEN
);
719 if (PROFILE_GetWineIniString ("Registry", "LocalMachineFileName", "", fn
, MAX_PATHNAME_LEN
- 1)){
720 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
725 pwd
=getpwuid(getuid());
726 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
730 /* Hack to disable double save */
731 if (usedCfgUser
== 0){
733 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
734 strlen(SAVE_CURRENT_USER
) + 2 );
735 strcpy(fn
,pwd
->pw_dir
);
736 strcat(fn
,WINE_PREFIX
);
737 /* create the directory. don't care about errorcodes. */
738 mkdir(fn
,0755); /* drwxr-xr-x */
739 strcat(fn
,"/"SAVE_CURRENT_USER
);
740 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
741 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
742 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
743 if (-1==rename(tmp
,fn
)) {
744 perror("rename tmp registry");
753 /* Hack to disable double save */
756 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
757 strcpy(fn
,pwd
->pw_dir
);
758 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
759 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
760 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
761 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
762 if (-1==rename(tmp
,fn
)) {
763 perror("rename tmp registry");
772 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
776 /************************ LOAD Registry Function ****************************/
780 /******************************************************************************
781 * _find_or_add_key [Internal]
783 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
785 LPKEYSTRUCT lpxkey
,*lplpkey
;
787 if ((!keyname
) || (keyname
[0]==0)) {
791 lplpkey
= &(lpkey
->nextsub
);
794 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
795 !lstrcmpiW(lpxkey
->keyname
,keyname
)
798 lplpkey
= &(lpxkey
->next
);
802 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
804 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
805 lpxkey
->keyname
= keyname
;
811 /******************************************************************************
812 * _find_or_add_value [Internal]
814 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
815 LPBYTE data
, DWORD len
, DWORD lastmodified
)
820 if (name
&& !*name
) {/* empty string equals default (NULL) value */
825 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
831 if ( val
->name
!=NULL
&&
832 val
->name
[0]==name
[0] &&
833 !lstrcmpiW(val
->name
,name
)
838 if (i
==lpkey
->nrofvalues
) {
839 lpkey
->values
= xrealloc(
841 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
844 memset(val
,'\0',sizeof(KEYVALUE
));
850 if (val
->lastmodified
<lastmodified
) {
851 val
->lastmodified
=lastmodified
;
862 /******************************************************************************
863 * _wine_read_line [Internal]
865 * reads a line including dynamically enlarging the readbuffer and throwing
868 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
878 s
=fgets(curread
,mylen
,F
);
881 if (NULL
==(s
=strchr(curread
,'\n'))) {
882 /* buffer wasn't large enough */
883 curoff
= strlen(*buf
);
884 *buf
= xrealloc(*buf
,*len
*2);
885 curread
= *buf
+ curoff
;
886 mylen
= *len
; /* we filled up the buffer and
887 * got new '*len' bytes to fill
895 /* throw away comments */
896 if (**buf
=='#' || **buf
==';') {
901 if (s
) /* got end of line */
908 /******************************************************************************
909 * _wine_read_USTRING [Internal]
911 * converts a char* into a UNICODE string (up to a special char)
912 * and returns the position exactly after that string
914 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
919 /* read up to "=" or "\0" or "\n" */
922 /* empty string is the win3.1 default value(NULL)*/
926 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
928 while (*s
&& (*s
!='\n') && (*s
!='=')) {
930 *ws
++=*((unsigned char*)s
++);
934 /* Dangling \ ... may only happen if a registry
935 * write was short. FIXME: What do to?
945 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
953 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
954 if (!sscanf(xbuf
,"%x",&wc
))
955 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
957 *ws
++ =(unsigned short)wc
;
964 *str
= strdupW(*str
);
972 /******************************************************************************
973 * _wine_loadsubkey [Internal]
976 * It seems like this is returning a boolean. Should it?
982 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
983 int *buflen
, DWORD optflag
)
990 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
993 lpkey
->flags
|= optflag
;
995 /* Good. We already got a line here ... so parse it */
1005 WARN(reg
,"Got a subhierarchy without resp. key?\n");
1008 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1012 /* let the caller handle this line */
1013 if (i
<level
|| **buf
=='\0')
1016 /* it can be: a value or a keyname. Parse the name first */
1017 s
=_wine_read_USTRING(s
,&name
);
1019 /* switch() default: hack to avoid gotos */
1023 lpxkey
=_find_or_add_key(lpkey
,name
);
1026 int len
,lastmodified
,type
;
1029 WARN(reg
,"Unexpected character: %c\n",*s
);
1033 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1034 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
1038 s
=strchr(s
,',');s
++;
1039 s
=strchr(s
,',');s
++;
1040 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1041 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1043 len
= lstrlenW((LPWSTR
)data
)*2+2;
1048 data
= (LPBYTE
)xmalloc(len
+1);
1049 for (i
=0;i
<len
;i
++) {
1051 if (*s
>='0' && *s
<='9')
1052 data
[i
]=(*s
-'0')<<4;
1053 if (*s
>='a' && *s
<='f')
1054 data
[i
]=(*s
-'a'+'\xa')<<4;
1055 if (*s
>='A' && *s
<='F')
1056 data
[i
]=(*s
-'A'+'\xa')<<4;
1058 if (*s
>='0' && *s
<='9')
1060 if (*s
>='a' && *s
<='f')
1061 data
[i
]|=*s
-'a'+'\xa';
1062 if (*s
>='A' && *s
<='F')
1063 data
[i
]|=*s
-'A'+'\xa';
1067 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1070 /* read the next line */
1071 if (!_wine_read_line(F
,buf
,buflen
))
1078 /******************************************************************************
1079 * _wine_loadsubreg [Internal]
1081 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1087 buf
=xmalloc(10);buflen
=10;
1088 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1092 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1096 if (ver
!=REGISTRY_SAVE_VERSION
) {
1097 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1101 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1105 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1114 /******************************************************************************
1115 * _wine_loadreg [Internal]
1117 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1121 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1125 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1128 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1137 /******************************************************************************
1138 * _copy_registry [Internal]
1140 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1148 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1150 for (j
=0;j
<from
->nrofvalues
;j
++) {
1154 valfrom
= from
->values
+j
;
1156 if (name
) name
=strdupW(name
);
1157 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1158 memcpy(data
,valfrom
->data
,valfrom
->len
);
1166 valfrom
->lastmodified
1169 _copy_registry(from
,lpxkey
);
1175 /* WINDOWS 95 REGISTRY LOADER */
1177 * Structure of a win95 registry database.
1179 * 0 : "CREG" - magic
1181 * 8 : DWORD offset_of_RGDB_part
1182 * 0C..0F: ? (someone fill in please)
1183 * 10: WORD number of RGDB blocks
1185 * 14: WORD always 0000?
1186 * 16: WORD always 0001?
1187 * 18..1F: ? (someone fill in please)
1191 * 0 : "RGKN" - magic
1192 * 4 : DWORD offset to first RGDB section
1193 * 8 : DWORD offset to the root record
1194 * C..0x1B: ? (fill in)
1195 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1197 * Disk Key Entry Structure:
1198 * 00: DWORD - Free entry indicator(?)
1199 * 04: DWORD - Hash = sum of bytes of keyname
1200 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1201 * 0C: DWORD - disk address of PreviousLevel Key.
1202 * 10: DWORD - disk address of Next Sublevel Key.
1203 * 14: DWORD - disk address of Next Key (on same level).
1204 * DKEP>18: WORD - Nr, Low Significant part.
1205 * 1A: WORD - Nr, High Significant part.
1207 * The disk address always points to the nr part of the previous key entry
1208 * of the referenced key. Don't ask me why, or even if I got this correct
1209 * from staring at 1kg of hexdumps. (DKEP)
1211 * The High significant part of the structure seems to equal the number
1212 * of the RGDB section. The low significant part is a unique ID within
1215 * There are two minor corrections to the position of that structure.
1216 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1217 * the DKE reread from there.
1218 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1219 * CPS - I have not experienced the above phenomenon in my registry files
1222 * 00: "RGDB" - magic
1223 * 04: DWORD offset to next RGDB section
1225 * 0C: WORD always 000d?
1226 * 0E: WORD RGDB block number
1227 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1229 * 20.....: disk keys
1232 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1233 * 08: WORD nrLS - low significant part of NR
1234 * 0A: WORD nrHS - high significant part of NR
1235 * 0C: DWORD bytesused - bytes used in this structure.
1236 * 10: WORD name_len - length of name in bytes. without \0
1237 * 12: WORD nr_of_values - number of values.
1238 * 14: char name[name_len] - name string. No \0.
1239 * 14+name_len: disk values
1240 * nextkeyoffset: ... next disk key
1243 * 00: DWORD type - value type (hmm, could be WORD too)
1244 * 04: DWORD - unknown, usually 0
1245 * 08: WORD namelen - length of Name. 0 means name=NULL
1246 * 0C: WORD datalen - length of Data.
1247 * 10: char name[namelen] - name, no \0
1248 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1249 * 10+namelen+datalen: next values or disk key
1251 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1252 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1253 * structure) and reading another RGDB_section.
1254 * repeat until end of file.
1256 * An interesting relationship exists in RGDB_section. The value at offset
1257 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1258 * idea at the moment what this means. (Kevin Cozens)
1260 * FIXME: this description needs some serious help, yes.
1263 struct _w95keyvalue
{
1265 unsigned short datalen
;
1267 unsigned char *data
;
1275 struct _w95keyvalue
*values
;
1276 struct _w95key
*prevlvl
;
1277 struct _w95key
*nextsub
;
1278 struct _w95key
*next
;
1292 /******************************************************************************
1293 * _w95_processKey [Internal]
1295 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1296 int nrLS
, int nrMS
, struct _w95_info
*info
)
1299 /* Disk Key Header structure (RGDB part) */
1301 unsigned long nextkeyoff
;
1302 unsigned short nrLS
;
1303 unsigned short nrMS
;
1304 unsigned long bytesused
;
1305 unsigned short keynamelen
;
1306 unsigned short values
;
1309 /* disk key values or nothing */
1311 /* Disk Key Value structure */
1315 unsigned short valnamelen
;
1316 unsigned short valdatalen
;
1317 /* valname, valdata */
1323 char *rgdbdata
= info
->rgdbbuffer
;
1324 int nbytes
= info
->rgdbsize
;
1325 char *curdata
= rgdbdata
;
1326 char *end
= rgdbdata
+ nbytes
;
1328 char *next
= rgdbdata
;
1334 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1336 memcpy(&off_next_rgdb
,curdata
+4,4);
1337 next
= curdata
+ off_next_rgdb
;
1338 nrgdb
= (int) *((short *)curdata
+ 7);
1340 } while (nrgdb
!= nrMS
&& (next
< end
));
1342 /* curdata now points to the start of the right RGDB section */
1345 #define XREAD(whereto,len) \
1346 if ((curdata + len) <end) {\
1347 memcpy(whereto,curdata,len);\
1352 while (curdata
< next
) {
1353 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1355 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1356 if (xdkh
->nrLS
== nrLS
) {
1357 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1358 curdata
+= sizeof(dkh
);
1361 curdata
+= xdkh
->nextkeyoff
;
1364 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1366 if (nrgdb
!= dkh
.nrMS
)
1369 assert((dkh
.keynamelen
<2) || curdata
[0]);
1370 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1371 curdata
+= dkh
.keynamelen
;
1373 for (i
=0;i
< dkh
.values
; i
++) {
1379 XREAD(&dkv
,sizeof(dkv
));
1381 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1382 curdata
+= dkv
.valnamelen
;
1384 if ((1 << dkv
.type
) & UNICONVMASK
) {
1385 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1386 len
= 2*(dkv
.valdatalen
+ 1);
1388 /* I don't think we want to NULL terminate all data */
1389 data
= xmalloc(dkv
.valdatalen
);
1390 memcpy (data
, curdata
, dkv
.valdatalen
);
1391 len
= dkv
.valdatalen
;
1394 curdata
+= dkv
.valdatalen
;
1408 /******************************************************************************
1409 * _w95_walkrgkn [Internal]
1411 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1412 struct _w95_info
*info
)
1415 /* Disk Key Entry structure (RGKN part) */
1419 unsigned long x3
;/*usually 0xFFFFFFFF */
1420 unsigned long prevlvl
;
1421 unsigned long nextsub
;
1423 unsigned short nrLS
;
1424 unsigned short nrMS
;
1425 } *dke
= (struct dke
*)off
;
1429 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1432 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1433 /* XXX <-- This is a hack*/
1438 if (dke
->nextsub
!= -1 &&
1439 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1440 && (dke
->nextsub
> 0x20)) {
1442 _w95_walkrgkn(lpxkey
,
1443 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1447 if (dke
->next
!= -1 &&
1448 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1449 (dke
->next
> 0x20)) {
1450 _w95_walkrgkn(prevkey
,
1451 info
->rgknbuffer
+ dke
->next
- 0x20,
1459 /******************************************************************************
1460 * _w95_loadreg [Internal]
1462 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1466 unsigned long where
,version
,rgdbsection
,end
;
1467 struct _w95_info info
;
1469 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1471 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1472 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1473 if (hfd
==HFILE_ERROR
)
1476 if (4!=_lread(hfd
,magic
,4))
1478 if (strcmp(magic
,"CREG")) {
1479 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1482 if (4!=_lread(hfd
,&version
,4))
1484 if (4!=_lread(hfd
,&rgdbsection
,4))
1486 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1488 if (4!=_lread(hfd
,magic
,4))
1490 if (strcmp(magic
,"RGKN")) {
1491 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1495 /* STEP 1: Keylink structures */
1496 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1501 info
.rgknsize
= end
- where
;
1502 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1503 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1506 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1509 end
= hfdinfo
.nFileSizeLow
;
1510 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1512 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1515 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1516 info
.rgdbsize
= end
- rgdbsection
;
1518 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1522 _w95_walkrgkn(lpkey
, NULL
, &info
);
1524 free (info
.rgdbbuffer
);
1525 free (info
.rgknbuffer
);
1529 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1532 reghack - windows 3.11 registry data format demo program.
1534 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1535 a combined hash table and tree description, and finally a text table.
1537 The header is obvious from the struct header. The taboff1 and taboff2
1538 fields are always 0x20, and their usage is unknown.
1540 The 8-byte entry table has various entry types.
1542 tabent[0] is a root index. The second word has the index of the root of
1544 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1545 the index of the key/value that has that hash. Data with the same
1546 hash value are on a circular list. The other three words in the
1547 hash entry are always zero.
1548 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1549 entry: dirent and keyent/valent. They are identified by context.
1550 tabent[freeidx] is the first free entry. The first word in a free entry
1551 is the index of the next free entry. The last has 0 as a link.
1552 The other three words in the free list are probably irrelevant.
1554 Entries in text table are preceeded by a word at offset-2. This word
1555 has the value (2*index)+1, where index is the referring keyent/valent
1556 entry in the table. I have no suggestion for the 2* and the +1.
1557 Following the word, there are N bytes of data, as per the keyent/valent
1558 entry length. The offset of the keyent/valent entry is from the start
1559 of the text table to the first data byte.
1561 This information is not available from Microsoft. The data format is
1562 deduced from the reg.dat file by me. Mistakes may
1563 have been made. I claim no rights and give no guarantees for this program.
1565 Tor Sjøwall, tor@sn.no
1568 /* reg.dat header format */
1569 struct _w31_header
{
1570 char cookie
[8]; /* 'SHCC3.10' */
1571 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1572 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1573 unsigned long tabcnt
; /* number of entries in index table */
1574 unsigned long textoff
; /* offset of text part */
1575 unsigned long textsize
; /* byte size of text part */
1576 unsigned short hashsize
; /* hash size */
1577 unsigned short freeidx
; /* free index */
1580 /* generic format of table entries */
1581 struct _w31_tabent
{
1582 unsigned short w0
, w1
, w2
, w3
;
1585 /* directory tabent: */
1586 struct _w31_dirent
{
1587 unsigned short sibling_idx
; /* table index of sibling dirent */
1588 unsigned short child_idx
; /* table index of child dirent */
1589 unsigned short key_idx
; /* table index of key keyent */
1590 unsigned short value_idx
; /* table index of value valent */
1594 struct _w31_keyent
{
1595 unsigned short hash_idx
; /* hash chain index for string */
1596 unsigned short refcnt
; /* reference count */
1597 unsigned short length
; /* length of string */
1598 unsigned short string_off
; /* offset of string in text table */
1602 struct _w31_valent
{
1603 unsigned short hash_idx
; /* hash chain index for string */
1604 unsigned short refcnt
; /* reference count */
1605 unsigned short length
; /* length of string */
1606 unsigned short string_off
; /* offset of string in text table */
1609 /* recursive helper function to display a directory tree */
1611 __w31_dumptree( unsigned short idx
,
1613 struct _w31_tabent
*tab
,
1614 struct _w31_header
*head
,
1616 time_t lastmodified
,
1619 struct _w31_dirent
*dir
;
1620 struct _w31_keyent
*key
;
1621 struct _w31_valent
*val
;
1622 LPKEYSTRUCT xlpkey
= NULL
;
1624 static char tail
[400];
1627 dir
=(struct _w31_dirent
*)&tab
[idx
];
1630 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1632 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1633 tail
[key
->length
]='\0';
1634 /* all toplevel entries AND the entries in the
1635 * toplevel subdirectory belong to \SOFTWARE\Classes
1637 if (!level
&& !lstrcmpA(tail
,".classes")) {
1638 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1639 idx
=dir
->sibling_idx
;
1642 name
=strdupA2W(tail
);
1644 xlpkey
=_find_or_add_key(lpkey
,name
);
1646 /* only add if leaf node or valued node */
1647 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1648 if (dir
->value_idx
) {
1649 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1650 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1651 tail
[val
->length
]='\0';
1652 value
=strdupA2W(tail
);
1653 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1657 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1659 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1660 idx
=dir
->sibling_idx
;
1665 /******************************************************************************
1666 * _w31_loadreg [Internal]
1668 void _w31_loadreg(void) {
1670 struct _w31_header head
;
1671 struct _w31_tabent
*tab
;
1675 BY_HANDLE_FILE_INFORMATION hfinfo
;
1676 time_t lastmodified
;
1679 TRACE(reg
,"(void)\n");
1681 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1682 if (hf
==HFILE_ERROR
)
1685 /* read & dump header */
1686 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1687 ERR(reg
, "reg.dat is too short.\n");
1691 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1692 ERR(reg
, "reg.dat has bad signature.\n");
1697 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1698 /* read and dump index table */
1700 if (len
!=_lread(hf
,tab
,len
)) {
1701 ERR(reg
,"couldn't read %d bytes.\n",len
);
1708 txt
= xmalloc(head
.textsize
);
1709 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1710 ERR(reg
,"couldn't seek to textblock.\n");
1716 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1717 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1724 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1725 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1731 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1732 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1733 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1741 /**********************************************************************************
1742 * SHELL_LoadRegistry [Internal]
1744 void SHELL_LoadRegistry( void )
1751 TRACE(reg
,"(void)\n");
1753 /* Load windows 3.1 entries */
1755 /* Load windows 95 entries */
1756 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1757 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1758 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1760 /* the global user default is loaded under HKEY_USERS\\.Default */
1761 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1762 lpkey
= lookup_hkey(hkey
);
1764 WARN(reg
,"Could not create global user default key\n");
1765 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1767 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1768 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1771 /* the global machine defaults */
1772 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1774 /* load the user saved registries */
1776 /* Try to load config file specified files */
1778 fn
= xmalloc( MAX_PATHNAME_LEN
);
1779 if (PROFILE_GetWineIniString ("Registry", "UserFileName", "", fn
, MAX_PATHNAME_LEN
- 1)) {
1780 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,0);
1784 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1785 if (PROFILE_GetWineIniString ("Registry", "LocalMachineFileName", "", fn
, MAX_PATHNAME_LEN
- 1)){
1786 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, 0);
1790 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1791 /* FIXME: user's home/.wine/user.reg and system.reg files are not
1792 blocked from loading not sure if we want to or not.*/
1795 pwd
=getpwuid(getuid());
1796 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1797 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1798 strcpy(fn
,pwd
->pw_dir
);
1799 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1800 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1802 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1803 strcpy(fn
,pwd
->pw_dir
);
1804 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1805 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1808 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1809 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1810 DWORD junk
,type
,len
;
1814 if (( RegQueryValueExA(
1821 )!=ERROR_SUCCESS
) ||
1824 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1830 /********************* API FUNCTIONS ***************************************/
1834 * All functions are stubs to RegOpenKeyEx32W where all the
1838 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1839 * RegOpenKey32W -> RegOpenKeyEx32W
1843 /******************************************************************************
1844 * RegOpenKeyEx32W [ADVAPI32.150]
1845 * Opens the specified key
1847 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1850 * hkey [I] Handle of open key
1851 * lpszSubKey [I] Name of subkey to open
1852 * dwReserved [I] Reserved - must be zero
1853 * samDesired [I] Security access mask
1854 * retkey [O] Address of handle of open key
1857 * Success: ERROR_SUCCESS
1858 * Failure: Error code
1860 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1861 REGSAM samDesired
, LPHKEY retkey
)
1863 LPKEYSTRUCT lpNextKey
,lpxkey
;
1867 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1870 lpNextKey
= lookup_hkey( hkey
);
1872 return ERROR_INVALID_HANDLE
;
1874 if (!lpszSubKey
|| !*lpszSubKey
) {
1875 /* Either NULL or pointer to empty string, so return a new handle
1876 to the original hkey */
1878 add_handle(currenthandle
,lpNextKey
,samDesired
);
1879 *retkey
=currenthandle
;
1880 return ERROR_SUCCESS
;
1883 if (lpszSubKey
[0] == '\\') {
1884 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1885 return ERROR_BAD_PATHNAME
;
1888 split_keypath(lpszSubKey
,&wps
,&wpc
);
1890 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1894 lpxkey
=lpNextKey
->nextsub
;
1896 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
1899 lpxkey
=lpxkey
->next
;
1903 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1905 return ERROR_FILE_NOT_FOUND
;
1912 add_handle(currenthandle
,lpxkey
,samDesired
);
1913 *retkey
= currenthandle
;
1914 TRACE(reg
," Returning %x\n", currenthandle
);
1916 return ERROR_SUCCESS
;
1920 /******************************************************************************
1921 * RegOpenKeyEx32A [ADVAPI32.149]
1923 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1924 REGSAM samDesired
, LPHKEY retkey
)
1926 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1929 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1931 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
1937 /******************************************************************************
1938 * RegOpenKey32W [ADVAPI32.151]
1941 * hkey [I] Handle of open key
1942 * lpszSubKey [I] Address of name of subkey to open
1943 * retkey [O] Address of handle of open key
1946 * Success: ERROR_SUCCESS
1947 * Failure: Error code
1949 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1951 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1952 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
1956 /******************************************************************************
1957 * RegOpenKey32A [ADVAPI32.148]
1959 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1962 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1963 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1964 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
1970 /******************************************************************************
1971 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1973 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1975 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1976 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
1983 * All those functions convert their respective
1984 * arguments and call RegCreateKeyExW at the end.
1986 * We stay away from the Ex functions as long as possible because there are
1987 * differences in the return values
1990 * RegCreateKeyEx32A \
1991 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1995 /******************************************************************************
1996 * RegCreateKeyEx32W [ADVAPI32.131]
1999 * hkey [I] Handle of an open key
2000 * lpszSubKey [I] Address of subkey name
2001 * dwReserved [I] Reserved - must be 0
2002 * lpszClass [I] Address of class string
2003 * fdwOptions [I] Special options flag
2004 * samDesired [I] Desired security access
2005 * lpSecAttribs [I] Address of key security structure
2006 * retkey [O] Address of buffer for opened handle
2007 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2009 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2010 DWORD dwReserved
, LPWSTR lpszClass
,
2011 DWORD fdwOptions
, REGSAM samDesired
,
2012 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2013 LPHKEY retkey
, LPDWORD lpDispos
)
2015 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2019 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2020 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2021 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2023 lpNextKey
= lookup_hkey(hkey
);
2025 return ERROR_INVALID_HANDLE
;
2027 /* Check for valid options */
2028 switch(fdwOptions
) {
2029 case REG_OPTION_NON_VOLATILE
:
2030 case REG_OPTION_VOLATILE
:
2031 case REG_OPTION_BACKUP_RESTORE
:
2034 return ERROR_INVALID_PARAMETER
;
2037 /* Sam has to be a combination of the following */
2039 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2040 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2041 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2042 return ERROR_INVALID_PARAMETER
;
2044 if (!lpszSubKey
|| !*lpszSubKey
) {
2046 add_handle(currenthandle
,lpNextKey
,samDesired
);
2047 *retkey
=currenthandle
;
2048 TRACE(reg
, "Returning %x\n", currenthandle
);
2049 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2050 return ERROR_SUCCESS
;
2053 if (lpszSubKey
[0] == '\\') {
2054 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2055 return ERROR_BAD_PATHNAME
;
2058 split_keypath(lpszSubKey
,&wps
,&wpc
);
2060 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2063 lpxkey
=lpNextKey
->nextsub
;
2065 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2067 lpxkey
=lpxkey
->next
;
2076 add_handle(currenthandle
,lpxkey
,samDesired
);
2077 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2078 *retkey
= currenthandle
;
2079 TRACE(reg
, "Returning %x\n", currenthandle
);
2081 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2083 return ERROR_SUCCESS
;
2086 /* Good. Now the hard part */
2088 lplpPrevKey
= &(lpNextKey
->nextsub
);
2089 lpxkey
= *lplpPrevKey
;
2091 lplpPrevKey
= &(lpxkey
->next
);
2092 lpxkey
= *lplpPrevKey
;
2094 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2095 if (!*lplpPrevKey
) {
2097 TRACE(reg
, "Returning OUTOFMEMORY\n");
2098 return ERROR_OUTOFMEMORY
;
2100 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2101 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
2102 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2103 (*lplpPrevKey
)->next
= NULL
;
2104 (*lplpPrevKey
)->nextsub
= NULL
;
2105 (*lplpPrevKey
)->values
= NULL
;
2106 (*lplpPrevKey
)->nrofvalues
= 0;
2107 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2109 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2111 (*lplpPrevKey
)->class = NULL
;
2112 lpNextKey
= *lplpPrevKey
;
2116 add_handle(currenthandle
,lpNextKey
,samDesired
);
2118 /*FIXME: flag handling correct? */
2119 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2121 lpNextKey
->class = strdupW(lpszClass
);
2123 lpNextKey
->class = NULL
;
2124 *retkey
= currenthandle
;
2125 TRACE(reg
, "Returning %x\n", currenthandle
);
2127 *lpDispos
= REG_CREATED_NEW_KEY
;
2129 return ERROR_SUCCESS
;
2133 /******************************************************************************
2134 * RegCreateKeyEx32A [ADVAPI32.130]
2136 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2137 LPSTR lpszClass
, DWORD fdwOptions
,
2139 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2140 LPHKEY retkey
, LPDWORD lpDispos
)
2142 LPWSTR lpszSubKeyW
, lpszClassW
;
2145 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2146 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2149 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2150 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2152 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2153 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2156 if(lpszSubKeyW
) free(lpszSubKeyW
);
2157 if(lpszClassW
) free(lpszClassW
);
2163 /******************************************************************************
2164 * RegCreateKey32W [ADVAPI32.132]
2166 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2169 LPKEYSTRUCT lpNextKey
;
2171 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2173 /* This check is here because the return value is different than the
2174 one from the Ex functions */
2175 lpNextKey
= lookup_hkey(hkey
);
2177 return ERROR_BADKEY
;
2179 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2180 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2185 /******************************************************************************
2186 * RegCreateKey32A [ADVAPI32.129]
2188 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2193 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2194 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2195 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2196 if(lpszSubKeyW
) free(lpszSubKeyW
);
2201 /******************************************************************************
2202 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2204 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2206 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2207 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2212 * Query Value Functions
2213 * Win32 differs between keynames and valuenames.
2214 * multiple values may belong to one key, the special value
2215 * with name NULL is the default value used by the win31
2219 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2220 * RegQueryValue32W -> RegQueryValueEx32W
2224 /******************************************************************************
2225 * RegQueryValueEx32W [ADVAPI32.158]
2226 * Retrieves type and data for a specified name associated with an open key
2229 * hkey [I] Handle of key to query
2230 * lpValueName [I] Name of value to query
2231 * lpdwReserved [I] Reserved - must be NULL
2232 * lpdwType [O] Address of buffer for value type. If NULL, the type
2234 * lpbData [O] Address of data buffer. If NULL, the actual data is
2236 * lpcbData [I/O] Address of data buffer size
2239 * ERROR_SUCCESS: Success
2240 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2241 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2243 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2244 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2245 LPBYTE lpbData
, LPDWORD lpcbData
)
2251 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2252 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2254 lpkey
= lookup_hkey(hkey
);
2257 return ERROR_INVALID_HANDLE
;
2259 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2260 return ERROR_INVALID_PARAMETER
;
2262 /* An empty name string is equivalent to NULL */
2263 if (lpValueName
&& !*lpValueName
)
2266 if (lpValueName
==NULL
)
2267 { /* Use key's unnamed or default value, if any */
2268 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2269 if (lpkey
->values
[i
].name
==NULL
)
2273 { /* Search for the key name */
2274 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2275 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2279 if (i
==lpkey
->nrofvalues
)
2280 { TRACE(reg
," Key not found\n");
2281 if (lpValueName
==NULL
)
2282 { /* Empty keyname not found */
2284 { *(WCHAR
*)lpbData
= 0;
2289 TRACE(reg
, " Returning an empty string\n");
2290 return ERROR_SUCCESS
;
2292 return ERROR_FILE_NOT_FOUND
;
2295 ret
= ERROR_SUCCESS
;
2297 if (lpdwType
) /* type required ?*/
2298 *lpdwType
= lpkey
->values
[i
].type
;
2300 if (lpbData
) /* data required ?*/
2301 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2302 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2304 ret
= ERROR_MORE_DATA
;
2307 if (lpcbData
) /* size required ?*/
2308 { *lpcbData
= lpkey
->values
[i
].len
;
2311 debug_print_value ( lpbData
, lpkey
->values
[i
].type
, lpkey
->values
[i
].len
);
2313 TRACE(reg
," (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2319 /******************************************************************************
2320 * RegQueryValue32W [ADVAPI32.159]
2322 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2328 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2329 lpcbData
?*lpcbData
:0);
2331 /* Only open subkey, if we really do descend */
2332 if (lpszSubKey
&& *lpszSubKey
) {
2333 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2334 if (ret
!= ERROR_SUCCESS
) {
2335 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2342 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2350 /******************************************************************************
2351 * RegQueryValueEx32A [ADVAPI32.157]
2354 * the documantation is wrong: if the buffer is to small it remains untouched
2356 * FIXME: check returnvalue (len) for an empty key
2358 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2359 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2360 LPBYTE lpbData
, LPDWORD lpcbData
)
2362 LPWSTR lpszValueNameW
;
2363 LPBYTE mybuf
= NULL
;
2364 DWORD ret
, mytype
, mylen
= 0;
2366 TRACE(reg
,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2367 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2369 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2370 { return ERROR_INVALID_PARAMETER
;
2373 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2375 /* get just the type first */
2376 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2378 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2379 { if(lpszValueNameW
) free(lpszValueNameW
);
2383 if (lpcbData
) /* at least length requested? */
2384 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2385 { if (lpbData
) /* value requested? */
2386 { mylen
= 2*( *lpcbData
);
2387 mybuf
= (LPBYTE
)xmalloc( mylen
);
2390 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2392 if (ret
== ERROR_SUCCESS
)
2394 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2398 *lpcbData
= mylen
/2; /* size is in byte! */
2400 else /* no strings, call it straight */
2401 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2405 if (lpdwType
) /* type when requested */
2406 { *lpdwType
= mytype
;
2409 TRACE(reg
," (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2411 if(mybuf
) free(mybuf
);
2412 if(lpszValueNameW
) free(lpszValueNameW
);
2417 /******************************************************************************
2418 * RegQueryValueEx16 [KERNEL.225]
2420 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2421 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2422 LPBYTE lpbData
, LPDWORD lpcbData
)
2424 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2425 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2426 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2427 lpbData
, lpcbData
);
2431 /******************************************************************************
2432 * RegQueryValue32A [ADVAPI32.156]
2434 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2440 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2441 lpcbData
?*lpcbData
:0);
2443 if (lpszSubKey
&& *lpszSubKey
) {
2444 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2445 if( ret
!= ERROR_SUCCESS
)
2451 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2454 RegCloseKey( xhkey
);
2459 /******************************************************************************
2460 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2463 * Is this HACK still applicable?
2466 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2467 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2470 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2473 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2474 lpcbData
?*lpcbData
:0);
2477 *lpcbData
&= 0xFFFF;
2478 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2483 * Setting values of Registry keys
2486 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2487 * RegSetValue32W -> RegSetValueEx32W
2491 /******************************************************************************
2492 * RegSetValueEx32W [ADVAPI32.170]
2493 * Sets the data and type of a value under a register key
2496 * hkey [I] Handle of key to set value for
2497 * lpszValueName [I] Name of value to set
2498 * dwReserved [I] Reserved - must be zero
2499 * dwType [I] Flag for value type
2500 * lpbData [I] Address of value data
2501 * cbData [I] Size of value data
2504 * Success: ERROR_SUCCESS
2505 * Failure: Error code
2508 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2510 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2511 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2517 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2518 dwReserved
, dwType
, lpbData
, cbData
);
2520 debug_print_value ( lpbData
, dwType
, cbData
);
2522 lpkey
= lookup_hkey( hkey
);
2525 return ERROR_INVALID_HANDLE
;
2527 lpkey
->flags
|= REG_OPTION_TAINTED
;
2529 if (lpszValueName
==NULL
) {
2530 /* Sets type and name for key's unnamed or default value */
2531 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2532 if (lpkey
->values
[i
].name
==NULL
)
2535 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2536 if ( lpkey
->values
[i
].name
&&
2537 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2541 if (i
==lpkey
->nrofvalues
) {
2542 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2544 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2546 lpkey
->nrofvalues
++;
2547 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2549 if (lpkey
->values
[i
].name
==NULL
) {
2551 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2553 lpkey
->values
[i
].name
= NULL
;
2556 if (dwType
== REG_SZ
)
2557 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2559 lpkey
->values
[i
].len
= cbData
;
2560 lpkey
->values
[i
].type
= dwType
;
2561 if (lpkey
->values
[i
].data
!=NULL
)
2562 free(lpkey
->values
[i
].data
);
2563 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2564 lpkey
->values
[i
].lastmodified
= time(NULL
);
2565 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2566 return ERROR_SUCCESS
;
2570 /******************************************************************************
2571 * RegSetValueEx32A [ADVAPI32.169]
2574 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2576 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2577 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2581 LPWSTR lpszValueNameW
;
2585 return (ERROR_INVALID_PARAMETER
);
2587 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2588 dwReserved
,dwType
,lpbData
,cbData
);
2590 if ((1<<dwType
) & UNICONVMASK
)
2591 { if (dwType
== REG_SZ
)
2592 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2594 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2595 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2602 lpszValueNameW
= strdupA2W(lpszValueName
);
2604 lpszValueNameW
= NULL
;
2606 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2609 free(lpszValueNameW
);
2618 /******************************************************************************
2619 * RegSetValueEx16 [KERNEL.226]
2621 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2622 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2624 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2625 dwReserved
,dwType
,lpbData
,cbData
);
2626 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2631 /******************************************************************************
2632 * RegSetValue32W [ADVAPI32.171]
2634 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2635 LPCWSTR lpszData
, DWORD cbData
)
2640 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2641 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2643 if (lpszSubKey
&& *lpszSubKey
) {
2644 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2645 if (ret
!=ERROR_SUCCESS
)
2649 if (dwType
!=REG_SZ
) {
2650 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2653 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2654 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2655 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2657 cbData
=2*lstrlenW(lpszData
)+2;
2659 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2666 /******************************************************************************
2667 * RegSetValue32A [ADVAPI32.168]
2670 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2671 LPCSTR lpszData
, DWORD cbData
)
2676 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2677 if (lpszSubKey
&& *lpszSubKey
) {
2678 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2679 if (ret
!=ERROR_SUCCESS
)
2684 if (dwType
!=REG_SZ
) {
2685 TRACE(reg
,"dwType=%ld!\n",dwType
);
2688 if (cbData
!=strlen(lpszData
)+1)
2689 cbData
=strlen(lpszData
)+1;
2690 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2697 /******************************************************************************
2698 * RegSetValue16 [KERNEL.221] [SHELL.5]
2700 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2701 LPCSTR lpszData
, DWORD cbData
)
2703 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2704 debugstr_a(lpszData
),cbData
);
2705 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2713 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2714 * RegEnumKey32W -> RegEnumKeyEx32W
2718 /******************************************************************************
2719 * RegEnumKeyEx32W [ADVAPI32.139]
2722 * hkey [I] Handle to key to enumerate
2723 * iSubKey [I] Index of subkey to enumerate
2724 * lpszName [O] Buffer for subkey name
2725 * lpcchName [O] Size of subkey buffer
2726 * lpdwReserved [I] Reserved
2727 * lpszClass [O] Buffer for class string
2728 * lpcchClass [O] Size of class buffer
2729 * ft [O] Time key last written to
2731 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2732 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2733 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2736 LPKEYSTRUCT lpkey
,lpxkey
;
2738 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2739 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2741 lpkey
= lookup_hkey( hkey
);
2743 return ERROR_INVALID_HANDLE
;
2745 if (!lpkey
->nextsub
)
2746 return ERROR_NO_MORE_ITEMS
;
2747 lpxkey
=lpkey
->nextsub
;
2749 /* Traverse the subkeys */
2750 while (iSubkey
&& lpxkey
) {
2752 lpxkey
=lpxkey
->next
;
2755 if (iSubkey
|| !lpxkey
)
2756 return ERROR_NO_MORE_ITEMS
;
2757 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
2758 return ERROR_MORE_DATA
;
2759 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
2762 *lpcchName
= lstrlenW(lpszName
);
2765 /* FIXME: what should we write into it? */
2769 return ERROR_SUCCESS
;
2773 /******************************************************************************
2774 * RegEnumKey32W [ADVAPI32.140]
2776 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2781 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2782 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2786 /******************************************************************************
2787 * RegEnumKeyEx32A [ADVAPI32.138]
2789 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2790 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2791 LPSTR lpszClass
, LPDWORD lpcchClass
,
2794 DWORD ret
,lpcchNameW
,lpcchClassW
;
2795 LPWSTR lpszNameW
,lpszClassW
;
2798 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2799 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2802 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2803 lpcchNameW
= *lpcchName
;
2809 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2810 lpcchClassW
= *lpcchClass
;
2825 if (ret
==ERROR_SUCCESS
) {
2826 lstrcpyWtoA(lpszName
,lpszNameW
);
2827 *lpcchName
=strlen(lpszName
);
2829 lstrcpyWtoA(lpszClass
,lpszClassW
);
2830 *lpcchClass
=strlen(lpszClass
);
2841 /******************************************************************************
2842 * RegEnumKey32A [ADVAPI32.137]
2844 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2849 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2850 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2855 /******************************************************************************
2856 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2858 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2861 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2862 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
2867 * Enumerate Registry Values
2870 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2874 /******************************************************************************
2875 * RegEnumValue32W [ADVAPI32.142]
2878 * hkey [I] Handle to key to query
2879 * iValue [I] Index of value to query
2880 * lpszValue [O] Value string
2881 * lpcchValue [I/O] Size of value buffer (in wchars)
2882 * lpdReserved [I] Reserved
2883 * lpdwType [O] Type code
2884 * lpbData [O] Value data
2885 * lpcbData [I/O] Size of data buffer (in bytes)
2887 * Note: wide character functions that take and/or return "character counts"
2888 * use TCHAR (that is unsigned short or char) not byte counts.
2890 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
2891 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2892 LPDWORD lpdwType
, LPBYTE lpbData
,
2898 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
2899 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2901 lpkey
= lookup_hkey( hkey
);
2903 if (!lpcbData
&& lpbData
)
2904 return ERROR_INVALID_PARAMETER
;
2907 return ERROR_INVALID_HANDLE
;
2909 if (lpkey
->nrofvalues
<= iValue
)
2910 return ERROR_NO_MORE_ITEMS
;
2912 val
= &(lpkey
->values
[iValue
]);
2915 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
2916 *lpcchValue
= lstrlenW(val
->name
)+1;
2917 return ERROR_MORE_DATA
;
2919 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
2920 *lpcchValue
=lstrlenW(val
->name
);
2926 /* Can be NULL if the type code is not required */
2928 *lpdwType
= val
->type
;
2931 if (val
->len
>*lpcbData
)
2932 return ERROR_MORE_DATA
;
2933 memcpy(lpbData
,val
->data
,val
->len
);
2934 *lpcbData
= val
->len
;
2937 debug_print_value ( val
->data
, val
->type
, val
->len
);
2938 return ERROR_SUCCESS
;
2942 /******************************************************************************
2943 * RegEnumValue32A [ADVAPI32.141]
2945 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2946 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2947 LPDWORD lpdwType
, LPBYTE lpbData
,
2952 DWORD ret
,lpcbDataW
;
2955 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2956 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2958 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2960 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2961 lpcbDataW
= *lpcbData
;
2965 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
2966 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
2971 if (ret
==ERROR_SUCCESS
) {
2972 lstrcpyWtoA(lpszValue
,lpszValueW
);
2974 if ((1<<dwType
) & UNICONVMASK
) {
2975 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2977 if (lpcbDataW
> *lpcbData
)
2978 ret
= ERROR_MORE_DATA
;
2980 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2982 *lpcbData
= lpcbDataW
;
2985 if (lpbDataW
) free(lpbDataW
);
2986 if (lpszValueW
) free(lpszValueW
);
2991 /******************************************************************************
2992 * RegEnumValue16 [KERNEL.223]
2994 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2995 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2996 LPDWORD lpdwType
, LPBYTE lpbData
,
2999 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3000 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3001 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3002 lpdwType
, lpbData
, lpcbData
);
3006 /******************************************************************************
3007 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3008 * Releases the handle of the specified key
3011 * hkey [I] Handle of key to close
3014 * Success: ERROR_SUCCESS
3015 * Failure: Error code
3017 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3019 TRACE(reg
,"(%x)\n",hkey
);
3021 /* The standard handles are allowed to succeed, even though they are not
3023 if (is_standard_hkey(hkey
))
3024 return ERROR_SUCCESS
;
3026 return remove_handle(hkey
);
3031 * Delete registry key
3034 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3038 /******************************************************************************
3039 * RegDeleteKey32W [ADVAPI32.134]
3042 * hkey [I] Handle to open key
3043 * lpszSubKey [I] Name of subkey to delete
3046 * Success: ERROR_SUCCESS
3047 * Failure: Error code
3049 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3051 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3055 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3057 lpNextKey
= lookup_hkey(hkey
);
3059 return ERROR_INVALID_HANDLE
;
3061 /* Subkey param cannot be NULL */
3062 if (!lpszSubKey
|| !*lpszSubKey
)
3063 return ERROR_BADKEY
;
3065 /* We need to know the previous key in the hier. */
3066 split_keypath(lpszSubKey
,&wps
,&wpc
);
3070 lpxkey
=lpNextKey
->nextsub
;
3072 TRACE(reg
, " Scanning [%s]\n",
3073 debugstr_w(lpxkey
->keyname
));
3074 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3076 lpxkey
=lpxkey
->next
;
3080 TRACE(reg
, " Not found.\n");
3081 /* not found is success */
3082 return ERROR_SUCCESS
;
3087 lpxkey
= lpNextKey
->nextsub
;
3088 lplpPrevKey
= &(lpNextKey
->nextsub
);
3090 TRACE(reg
, " Scanning [%s]\n",
3091 debugstr_w(lpxkey
->keyname
));
3092 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3094 lplpPrevKey
= &(lpxkey
->next
);
3095 lpxkey
= lpxkey
->next
;
3100 WARN(reg
, " Not found.\n");
3101 return ERROR_FILE_NOT_FOUND
;
3104 if (lpxkey
->nextsub
) {
3106 WARN(reg
, " Not empty.\n");
3107 return ERROR_CANTWRITE
;
3109 *lplpPrevKey
= lpxkey
->next
;
3110 free(lpxkey
->keyname
);
3112 free(lpxkey
->class);
3114 free(lpxkey
->values
);
3117 TRACE(reg
, " Done.\n");
3118 return ERROR_SUCCESS
;
3122 /******************************************************************************
3123 * RegDeleteKey32A [ADVAPI32.133]
3125 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3130 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3131 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3132 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3133 if(lpszSubKeyW
) free(lpszSubKeyW
);
3138 /******************************************************************************
3139 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3141 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3143 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3144 return RegDeleteKeyA( hkey
, lpszSubKey
);
3149 * Delete registry value
3152 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3156 /******************************************************************************
3157 * RegDeleteValue32W [ADVAPI32.136]
3165 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3171 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3173 lpkey
= lookup_hkey( hkey
);
3175 return ERROR_INVALID_HANDLE
;
3178 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3179 if ( lpkey
->values
[i
].name
&&
3180 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3184 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3185 if (lpkey
->values
[i
].name
==NULL
)
3189 if (i
== lpkey
->nrofvalues
)
3190 return ERROR_FILE_NOT_FOUND
;
3192 val
= lpkey
->values
+i
;
3193 if (val
->name
) free(val
->name
);
3194 if (val
->data
) free(val
->data
);
3198 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3200 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3202 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3204 lpkey
->nrofvalues
--;
3205 return ERROR_SUCCESS
;
3209 /******************************************************************************
3210 * RegDeleteValue32A [ADVAPI32.135]
3212 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3217 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3218 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3219 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3220 if(lpszValueW
) free(lpszValueW
);
3225 /******************************************************************************
3226 * RegDeleteValue16 [KERNEL.222]
3228 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3230 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3231 return RegDeleteValueA( hkey
, lpszValue
);
3235 /******************************************************************************
3236 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3237 * Writes key to registry
3240 * hkey [I] Handle of key to write
3243 * Success: ERROR_SUCCESS
3244 * Failure: Error code
3246 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3251 TRACE(reg
, "(%x)\n", hkey
);
3253 lpkey
= lookup_hkey( hkey
);
3255 return ERROR_BADKEY
;
3257 ERR(reg
, "What is the correct filename?\n");
3259 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3262 return ERROR_SUCCESS
;
3264 return ERROR_UNKNOWN
; /* FIXME */
3268 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3271 /******************************************************************************
3272 * RegQueryInfoKey32W [ADVAPI32.153]
3275 * hkey [I] Handle to key to query
3276 * lpszClass [O] Buffer for class string
3277 * lpcchClass [O] Size of class string buffer
3278 * lpdwReserved [I] Reserved
3279 * lpcSubKeys [I] Buffer for number of subkeys
3280 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3281 * lpcchMaxClass [O] Buffer for longest class string length
3282 * lpcValues [O] Buffer for number of value entries
3283 * lpcchMaxValueName [O] Buffer for longest value name length
3284 * lpccbMaxValueData [O] Buffer for longest value data length
3285 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3287 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3288 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3289 * lpcchClass is NULL
3290 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3291 * (it's hard to test validity, so test !NULL instead)
3293 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3294 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3295 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3296 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3297 LPDWORD lpcchMaxValueName
,
3298 LPDWORD lpccbMaxValueData
,
3299 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3301 LPKEYSTRUCT lpkey
,lpxkey
;
3302 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3305 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3306 lpkey
= lookup_hkey(hkey
);
3308 return ERROR_INVALID_HANDLE
;
3310 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3311 return ERROR_INVALID_PARAMETER
;
3313 /* either lpcchClass is valid or this is win95 and lpcchClass
3316 DWORD classLen
= lstrlenW(lpkey
->class);
3318 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3319 *lpcchClass
=classLen
+1;
3320 return ERROR_MORE_DATA
;
3323 *lpcchClass
=classLen
;
3324 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3332 *lpcchClass
= lstrlenW(lpkey
->class);
3334 lpxkey
=lpkey
->nextsub
;
3335 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3338 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3339 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3340 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3341 maxclass
=lstrlenW(lpxkey
->class);
3342 lpxkey
=lpxkey
->next
;
3344 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3345 LPKEYVALUE val
=lpkey
->values
+i
;
3347 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3348 maxvname
=lstrlenW(val
->name
);
3349 if (val
->len
>maxvdata
)
3352 if (!maxclass
) maxclass
= 1;
3353 if (!maxvname
) maxvname
= 1;
3355 *lpcValues
= lpkey
->nrofvalues
;
3357 *lpcSubKeys
= nrofkeys
;
3359 *lpcchMaxSubkey
= maxsubkey
;
3361 *lpcchMaxClass
= maxclass
;
3362 if (lpcchMaxValueName
)
3363 *lpcchMaxValueName
= maxvname
;
3364 if (lpccbMaxValueData
)
3365 *lpccbMaxValueData
= maxvdata
;
3366 return ERROR_SUCCESS
;
3370 /******************************************************************************
3371 * RegQueryInfoKey32A [ADVAPI32.152]
3373 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3374 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3375 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3376 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3377 LPDWORD lpccbMaxValueData
,
3378 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3380 LPWSTR lpszClassW
= NULL
;
3383 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3386 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3387 } else if (VERSION_GetVersion() == WIN95
) {
3388 /* win95 allows lpcchClass to be null */
3389 /* we don't know how big lpszClass is, would
3390 MAX_PATHNAME_LEN be the correct default? */
3391 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3396 ret
=RegQueryInfoKeyW(
3407 lpcbSecurityDescriptor
,
3410 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3411 lstrcpyWtoA(lpszClass
,lpszClassW
);
3418 /******************************************************************************
3419 * RegConnectRegistry32W [ADVAPI32.128]
3422 * lpMachineName [I] Address of name of remote computer
3423 * hHey [I] Predefined registry handle
3424 * phkResult [I] Address of buffer for remote registry handle
3426 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3429 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3431 if (!lpMachineName
|| !*lpMachineName
) {
3432 /* Use the local machine name */
3433 return RegOpenKey16( hKey
, "", phkResult
);
3436 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3437 return ERROR_BAD_NETPATH
;
3441 /******************************************************************************
3442 * RegConnectRegistry32A [ADVAPI32.127]
3444 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3447 LPWSTR machineW
= strdupA2W(machine
);
3448 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3454 /******************************************************************************
3455 * RegGetKeySecurity [ADVAPI32.144]
3456 * Retrieves a copy of security descriptor protecting the registry key
3459 * hkey [I] Open handle of key to set
3460 * SecurityInformation [I] Descriptor contents
3461 * pSecurityDescriptor [O] Address of descriptor for key
3462 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3465 * Success: ERROR_SUCCESS
3466 * Failure: Error code
3468 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3469 SECURITY_INFORMATION SecurityInformation
,
3470 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3471 LPDWORD lpcbSecurityDescriptor
)
3475 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3476 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3478 lpkey
= lookup_hkey( hkey
);
3480 return ERROR_INVALID_HANDLE
;
3482 /* FIXME: Check for valid SecurityInformation values */
3484 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3485 return ERROR_INSUFFICIENT_BUFFER
;
3487 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3488 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3490 return ERROR_SUCCESS
;
3494 /******************************************************************************
3495 * RegLoadKey32W [ADVAPI32.???]
3498 * hkey [I] Handle of open key
3499 * lpszSubKey [I] Address of name of subkey
3500 * lpszFile [I] Address of filename for registry information
3502 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3505 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3507 /* Do this check before the hkey check */
3508 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3509 return ERROR_INVALID_PARAMETER
;
3511 lpkey
= lookup_hkey( hkey
);
3513 return ERROR_INVALID_HANDLE
;
3515 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3516 debugstr_w(lpszFile
));
3518 return ERROR_SUCCESS
;
3522 /******************************************************************************
3523 * RegLoadKey32A [ADVAPI32.???]
3525 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3528 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3529 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3530 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3531 if(lpszFileW
) free(lpszFileW
);
3532 if(lpszSubKeyW
) free(lpszSubKeyW
);
3537 /******************************************************************************
3538 * RegNotifyChangeKeyValue [ADVAPI32.???]
3541 * hkey [I] Handle of key to watch
3542 * fWatchSubTree [I] Flag for subkey notification
3543 * fdwNotifyFilter [I] Changes to be reported
3544 * hEvent [I] Handle of signaled event
3545 * fAsync [I] Flag for asynchronous reporting
3547 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3548 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3552 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3555 lpkey
= lookup_hkey( hkey
);
3557 return ERROR_INVALID_HANDLE
;
3559 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3562 return ERROR_SUCCESS
;
3566 /******************************************************************************
3567 * RegUnLoadKey32W [ADVAPI32.173]
3570 * hkey [I] Handle of open key
3571 * lpSubKey [I] Address of name of subkey to unload
3573 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3575 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3576 return ERROR_SUCCESS
;
3580 /******************************************************************************
3581 * RegUnLoadKey32A [ADVAPI32.172]
3583 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3586 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3587 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3588 if(lpSubKeyW
) free(lpSubKeyW
);
3593 /******************************************************************************
3594 * RegSetKeySecurity [ADVAPI32.167]
3597 * hkey [I] Open handle of key to set
3598 * SecurityInfo [I] Descriptor contents
3599 * pSecurityDesc [I] Address of descriptor for key
3601 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3602 PSECURITY_DESCRIPTOR pSecurityDesc
)
3606 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3608 /* It seems to perform this check before the hkey check */
3609 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3610 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3611 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3612 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3615 return ERROR_INVALID_PARAMETER
;
3618 return ERROR_INVALID_PARAMETER
;
3620 lpkey
= lookup_hkey( hkey
);
3622 return ERROR_INVALID_HANDLE
;
3624 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3626 return ERROR_SUCCESS
;
3630 /******************************************************************************
3631 * RegSaveKey32W [ADVAPI32.166]
3634 * hkey [I] Handle of key where save begins
3635 * lpFile [I] Address of filename to save to
3636 * sa [I] Address of security structure
3638 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3639 LPSECURITY_ATTRIBUTES sa
)
3643 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3645 /* It appears to do this check before the hkey check */
3646 if (!lpFile
|| !*lpFile
)
3647 return ERROR_INVALID_PARAMETER
;
3649 lpkey
= lookup_hkey( hkey
);
3651 return ERROR_INVALID_HANDLE
;
3653 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3655 return ERROR_SUCCESS
;
3659 /******************************************************************************
3660 * RegSaveKey32A [ADVAPI32.165]
3662 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3663 LPSECURITY_ATTRIBUTES sa
)
3666 LPWSTR lpFileW
= strdupA2W(lpFile
);
3667 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3673 /******************************************************************************
3674 * RegRestoreKey32W [ADVAPI32.164]
3677 * hkey [I] Handle of key where restore begins
3678 * lpFile [I] Address of filename containing saved tree
3679 * dwFlags [I] Optional flags
3681 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3685 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3687 /* It seems to do this check before the hkey check */
3688 if (!lpFile
|| !*lpFile
)
3689 return ERROR_INVALID_PARAMETER
;
3691 lpkey
= lookup_hkey( hkey
);
3693 return ERROR_INVALID_HANDLE
;
3695 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3697 /* Check for file existence */
3699 return ERROR_SUCCESS
;
3703 /******************************************************************************
3704 * RegRestoreKey32A [ADVAPI32.163]
3706 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3709 LPWSTR lpFileW
= strdupA2W(lpFile
);
3710 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3711 if(lpFileW
) free(lpFileW
);
3716 /******************************************************************************
3717 * RegReplaceKey32W [ADVAPI32.162]
3720 * hkey [I] Handle of open key
3721 * lpSubKey [I] Address of name of subkey
3722 * lpNewFile [I] Address of filename for file with new data
3723 * lpOldFile [I] Address of filename for backup file
3725 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3730 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3731 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3733 lpkey
= lookup_hkey( hkey
);
3735 return ERROR_INVALID_HANDLE
;
3737 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3738 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3740 return ERROR_SUCCESS
;
3744 /******************************************************************************
3745 * RegReplaceKey32A [ADVAPI32.161]
3747 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3751 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3752 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3753 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3754 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);