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>
41 #include "winversion.h"
43 static void REGISTRY_Init(void);
44 /* FIXME: following defines should be configured global ... */
46 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
47 #define WINE_PREFIX "/.wine"
48 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
49 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
51 /* relative in ~user/.wine/ : */
52 #define SAVE_CURRENT_USER "user.reg"
53 #define SAVE_LOCAL_MACHINE "system.reg"
55 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
56 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
58 /* one value of a key */
59 typedef struct tagKEYVALUE
61 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
62 DWORD type
; /* type of value */
63 DWORD len
; /* length of data in BYTEs */
64 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
65 LPBYTE data
; /* content, may be strings, binaries, etc. */
66 } KEYVALUE
,*LPKEYVALUE
;
69 typedef struct tagKEYSTRUCT
71 LPWSTR keyname
; /* name of THIS key (UNICODE) */
72 DWORD flags
; /* flags. */
75 DWORD nrofvalues
; /* nr of values in THIS key */
76 LPKEYVALUE values
; /* values in THIS key */
77 /* key management pointers */
78 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
79 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
80 } KEYSTRUCT
, *LPKEYSTRUCT
;
83 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
84 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
85 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
86 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
88 /* dynamic, not saved */
89 static KEYSTRUCT
*key_performance_data
=NULL
;
90 static KEYSTRUCT
*key_current_config
=NULL
;
91 static KEYSTRUCT
*key_dyn_data
=NULL
;
93 /* what valuetypes do we need to convert? */
94 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
97 static struct openhandle
{
102 static int nrofopenhandles
=0;
103 /* Starts after 1 because 0,1 are reserved for Win16 */
104 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
105 HKEYs for remote registry access */
106 static int currenthandle
=2;
111 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112 * If so, can we remove them?
114 * No, the memory handling functions are called very often in here,
115 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
116 * loading 100 times slower. -MM
118 static LPWSTR
strdupA2W(LPCSTR src
)
121 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
122 lstrcpyAtoW(dest
,src
);
128 static LPWSTR
strdupW(LPCWSTR a
) {
133 len
=sizeof(WCHAR
)*(lstrlen32W(a
)+1);
134 b
=(LPWSTR
)xmalloc(len
);
141 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
144 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
146 lstrcpynAtoW(dest
,src
,nchars
+1);
152 /******************************************************************************
153 * is_standard_hkey [Internal]
154 * Determines if a hkey is a standard key
156 static BOOL32
is_standard_hkey( HKEY hkey
)
161 case HKEY_CLASSES_ROOT
:
162 case HKEY_CURRENT_CONFIG
:
163 case HKEY_CURRENT_USER
:
164 case HKEY_LOCAL_MACHINE
:
166 case HKEY_PERFORMANCE_DATA
:
174 /******************************************************************************
175 * add_handle [Internal]
177 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
181 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
182 /* Check for duplicates */
183 for (i
=0;i
<nrofopenhandles
;i
++) {
184 if (openhandles
[i
].lpkey
==lpkey
) {
185 /* This is not really an error - the user is allowed to create
186 two (or more) handles to the same key */
187 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
189 if (openhandles
[i
].hkey
==hkey
) {
190 WARN(reg
, "Adding handle %x twice\n",hkey
);
193 openhandles
=xrealloc( openhandles
,
194 sizeof(struct openhandle
)*(nrofopenhandles
+1));
196 openhandles
[i
].lpkey
= lpkey
;
197 openhandles
[i
].hkey
= hkey
;
198 openhandles
[i
].accessmask
= accessmask
;
203 /******************************************************************************
204 * get_handle [Internal]
207 * Success: Pointer to key
210 static LPKEYSTRUCT
get_handle( HKEY hkey
)
214 for (i
=0; i
<nrofopenhandles
; i
++)
215 if (openhandles
[i
].hkey
== hkey
)
216 return openhandles
[i
].lpkey
;
217 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
222 /******************************************************************************
223 * remove_handle [Internal]
226 * hkey [I] Handle of key to remove
229 * Success: ERROR_SUCCESS
230 * Failure: ERROR_INVALID_HANDLE
232 static DWORD
remove_handle( HKEY hkey
)
236 for (i
=0;i
<nrofopenhandles
;i
++)
237 if (openhandles
[i
].hkey
==hkey
)
240 if (i
== nrofopenhandles
) {
241 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
242 return ERROR_INVALID_HANDLE
;
245 memcpy( openhandles
+i
,
247 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
249 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
251 return ERROR_SUCCESS
;
254 /******************************************************************************
255 * lookup_hkey [Internal]
257 * Just as the name says. Creates the root keys on demand, so we can call the
258 * Reg* functions at any time.
261 * Success: Pointer to key structure
264 #define ADD_ROOT_KEY(xx) \
265 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
266 memset(xx,'\0',sizeof(KEYSTRUCT));\
267 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
269 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
272 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
273 * some programs. Do not remove those cases. -MM
277 case HKEY_CLASSES_ROOT
: {
278 if (!key_classes_root
) {
281 /* calls lookup_hkey recursively, TWICE */
282 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
283 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
286 key_classes_root
= lookup_hkey(cl_r_hkey
);
288 return key_classes_root
;
290 case HKEY_CURRENT_USER
:
291 if (!key_current_user
) {
295 pwd
=getpwuid(getuid());
296 /* calls lookup_hkey recursively, TWICE */
297 if (pwd
&& pwd
->pw_name
) {
298 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
299 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
302 key_current_user
= lookup_hkey(c_u_hkey
);
304 /* nothing found, use standalone */
305 ADD_ROOT_KEY(key_current_user
);
308 return key_current_user
;
309 case HKEY_LOCAL_MACHINE
:
310 if (!key_local_machine
) {
311 ADD_ROOT_KEY(key_local_machine
);
314 return key_local_machine
;
317 ADD_ROOT_KEY(key_users
);
320 case HKEY_PERFORMANCE_DATA
:
321 if (!key_performance_data
) {
322 ADD_ROOT_KEY(key_performance_data
);
324 return key_performance_data
;
327 ADD_ROOT_KEY(key_dyn_data
);
330 case HKEY_CURRENT_CONFIG
:
331 if (!key_current_config
) {
332 ADD_ROOT_KEY(key_current_config
);
334 return key_current_config
;
336 return get_handle(hkey
);
341 /* so we don't accidently access them ... */
342 #define key_current_config NULL NULL
343 #define key_current_user NULL NULL
344 #define key_users NULL NULL
345 #define key_local_machine NULL NULL
346 #define key_classes_root NULL NULL
347 #define key_dyn_data NULL NULL
348 #define key_performance_data NULL NULL
350 /******************************************************************************
351 * split_keypath [Internal]
352 * splits the unicode string 'wp' into an array of strings.
353 * the array is allocated by this function.
354 * Free the array using FREE_KEY_PATH
357 * wp [I] String to split up
358 * wpv [O] Array of pointers to strings
359 * wpc [O] Number of components
361 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
366 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
368 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
370 /* We know we have at least one substring */
373 /* Replace each backslash with NULL, and increment the count */
374 for (i
=0;ws
[i
];i
++) {
383 /* Allocate the space for the array of pointers, leaving room for the
385 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
388 /* Assign each pointer to the appropriate character in the string */
393 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
398 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
403 /******************************************************************************
404 * REGISTRY_Init [Internal]
405 * Registry initialisation, allocates some default keys.
407 static void REGISTRY_Init(void) {
411 TRACE(reg
,"(void)\n");
413 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
416 /* This was an Open, but since it is called before the real registries
417 are loaded, it was changed to a Create - MTB 980507*/
418 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
419 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
422 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
426 * string RegisteredOwner
427 * string RegisteredOrganization
430 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
435 if (-1!=gethostname(buf
,200)) {
436 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
437 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
443 /************************ SAVE Registry Function ****************************/
445 #define REGISTRY_SAVE_VERSION 0x00000001
447 /* Registry saveformat:
448 * If you change it, increase above number by 1, which will flush
449 * old registry database files.
452 * "WINE REGISTRY Version %d"
456 * valuename=lastmodified,type,data
460 * keyname,valuename,stringdata:
461 * the usual ascii characters from 0x00-0xff (well, not 0x00)
462 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
463 * ( "=\\\t" escaped in \uXXXX form.)
467 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
469 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
470 * SaveOnlyUpdatedKeys=yes
473 /******************************************************************************
474 * _save_check_tainted [Internal]
476 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
482 if (lpkey
->flags
& REG_OPTION_TAINTED
)
487 if (_save_check_tainted(lpkey
->nextsub
)) {
488 lpkey
->flags
|= REG_OPTION_TAINTED
;
496 /******************************************************************************
497 * _save_USTRING [Internal]
499 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
513 if (escapeeq
&& *s
=='=')
516 fputc(*s
,F
); /* if \\ then put it twice. */
518 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
525 /******************************************************************************
526 * _savesubkey [Internal]
528 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
535 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
536 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
538 for (tabs
=level
;tabs
--;)
540 _save_USTRING(F
,lpxkey
->keyname
,1);
542 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
543 LPKEYVALUE val
=lpxkey
->values
+i
;
545 for (tabs
=level
+1;tabs
--;)
547 _save_USTRING(F
,val
->name
,0);
549 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
550 if ((1<<val
->type
) & UNICONVMASK
)
551 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
553 for (j
=0;j
<val
->len
;j
++)
554 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
557 /* descend recursively */
558 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
567 /******************************************************************************
568 * _savesubreg [Internal]
570 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
572 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
573 _save_check_tainted(lpkey
->nextsub
);
574 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
578 /******************************************************************************
579 * _savereg [Internal]
581 static BOOL32
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
587 WARN(reg
,"Couldn't open %s for writing: %s\n",
592 if (!_savesubreg(F
,lpkey
,all
)) {
595 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
603 /******************************************************************************
604 * SHELL_SaveRegistry [Internal]
606 void SHELL_SaveRegistry( void )
614 TRACE(reg
,"(void)\n");
617 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
623 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
635 if (lstrcmpi32A(buf
,"yes"))
637 pwd
=getpwuid(getuid());
638 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
642 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
643 strlen(SAVE_CURRENT_USER
) + 2 );
644 strcpy(fn
,pwd
->pw_dir
);
645 strcat(fn
,WINE_PREFIX
);
646 /* create the directory. don't care about errorcodes. */
647 mkdir(fn
,0755); /* drwxr-xr-x */
648 strcat(fn
,"/"SAVE_CURRENT_USER
);
649 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
650 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
651 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
652 if (-1==rename(tmp
,fn
)) {
653 perror("rename tmp registry");
659 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
660 strcpy(fn
,pwd
->pw_dir
);
661 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
662 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
663 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
664 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
665 if (-1==rename(tmp
,fn
)) {
666 perror("rename tmp registry");
673 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
677 /************************ LOAD Registry Function ****************************/
681 /******************************************************************************
682 * _find_or_add_key [Internal]
684 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
686 LPKEYSTRUCT lpxkey
,*lplpkey
;
688 if ((!keyname
) || (keyname
[0]==0)) {
692 lplpkey
= &(lpkey
->nextsub
);
695 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
696 !lstrcmpi32W(lpxkey
->keyname
,keyname
)
699 lplpkey
= &(lpxkey
->next
);
703 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
705 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
706 lpxkey
->keyname
= keyname
;
712 /******************************************************************************
713 * _find_or_add_value [Internal]
715 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
716 LPBYTE data
, DWORD len
, DWORD lastmodified
)
721 if (name
&& !*name
) {/* empty string equals default (NULL) value */
726 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
732 if ( val
->name
!=NULL
&&
733 val
->name
[0]==name
[0] &&
734 !lstrcmpi32W(val
->name
,name
)
739 if (i
==lpkey
->nrofvalues
) {
740 lpkey
->values
= xrealloc(
742 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
745 memset(val
,'\0',sizeof(KEYVALUE
));
751 if (val
->lastmodified
<lastmodified
) {
752 val
->lastmodified
=lastmodified
;
763 /******************************************************************************
764 * _wine_read_line [Internal]
766 * reads a line including dynamically enlarging the readbuffer and throwing
769 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
779 s
=fgets(curread
,mylen
,F
);
782 if (NULL
==(s
=strchr(curread
,'\n'))) {
783 /* buffer wasn't large enough */
784 curoff
= strlen(*buf
);
785 *buf
= xrealloc(*buf
,*len
*2);
786 curread
= *buf
+ curoff
;
787 mylen
= *len
; /* we filled up the buffer and
788 * got new '*len' bytes to fill
796 /* throw away comments */
797 if (**buf
=='#' || **buf
==';') {
802 if (s
) /* got end of line */
809 /******************************************************************************
810 * _wine_read_USTRING [Internal]
812 * converts a char* into a UNICODE string (up to a special char)
813 * and returns the position exactly after that string
815 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
820 /* read up to "=" or "\0" or "\n" */
823 /* empty string is the win3.1 default value(NULL)*/
827 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
829 while (*s
&& (*s
!='\n') && (*s
!='=')) {
831 *ws
++=*((unsigned char*)s
++);
840 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
848 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
849 if (!sscanf(xbuf
,"%x",&wc
))
850 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
852 *ws
++ =(unsigned short)wc
;
859 *str
= strdupW(*str
);
867 /******************************************************************************
868 * _wine_loadsubkey [Internal]
871 * It seems like this is returning a boolean. Should it?
877 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
878 int *buflen
, DWORD optflag
)
885 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
888 lpkey
->flags
|= optflag
;
890 /* Good. We already got a line here ... so parse it */
900 WARN(reg
,"Got a subhierarchy without resp. key?\n");
903 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
907 /* let the caller handle this line */
908 if (i
<level
|| **buf
=='\0')
911 /* it can be: a value or a keyname. Parse the name first */
912 s
=_wine_read_USTRING(s
,&name
);
914 /* switch() default: hack to avoid gotos */
918 lpxkey
=_find_or_add_key(lpkey
,name
);
921 int len
,lastmodified
,type
;
924 WARN(reg
,"Unexpected character: %c\n",*s
);
928 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
929 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
935 if ((1<<type
) & UNICONVMASK
) {
936 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
938 len
= lstrlen32W((LPWSTR
)data
)*2+2;
943 data
= (LPBYTE
)xmalloc(len
+1);
944 for (i
=0;i
<len
;i
++) {
946 if (*s
>='0' && *s
<='9')
948 if (*s
>='a' && *s
<='f')
949 data
[i
]=(*s
-'a'+'\xa')<<4;
950 if (*s
>='A' && *s
<='F')
951 data
[i
]=(*s
-'A'+'\xa')<<4;
953 if (*s
>='0' && *s
<='9')
955 if (*s
>='a' && *s
<='f')
956 data
[i
]|=*s
-'a'+'\xa';
957 if (*s
>='A' && *s
<='F')
958 data
[i
]|=*s
-'A'+'\xa';
962 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
965 /* read the next line */
966 if (!_wine_read_line(F
,buf
,buflen
))
973 /******************************************************************************
974 * _wine_loadsubreg [Internal]
976 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
982 buf
=xmalloc(10);buflen
=10;
983 if (!_wine_read_line(F
,&buf
,&buflen
)) {
987 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
991 if (ver
!=REGISTRY_SAVE_VERSION
) {
992 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
996 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1000 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1009 /******************************************************************************
1010 * _wine_loadreg [Internal]
1012 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1016 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1020 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1023 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1032 /******************************************************************************
1033 * _copy_registry [Internal]
1035 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1043 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1045 for (j
=0;j
<from
->nrofvalues
;j
++) {
1049 valfrom
= from
->values
+j
;
1051 if (name
) name
=strdupW(name
);
1052 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1053 memcpy(data
,valfrom
->data
,valfrom
->len
);
1061 valfrom
->lastmodified
1064 _copy_registry(from
,lpxkey
);
1070 /* WINDOWS 95 REGISTRY LOADER */
1072 * Structure of a win95 registry database.
1074 * 0 : "CREG" - magic
1076 * 8 : DWORD offset_of_RGDB_part
1077 * 0C..0F: ? (someone fill in please)
1078 * 10: WORD number of RGDB blocks
1080 * 14: WORD always 0000?
1081 * 16: WORD always 0001?
1082 * 18..1F: ? (someone fill in please)
1086 * 0 : "RGKN" - magic
1087 * 4 : DWORD offset to first RGDB section
1088 * 8 : DWORD offset to the root record
1089 * C..0x1B: ? (fill in)
1090 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1092 * Disk Key Entry Structure:
1093 * 00: DWORD - Free entry indicator(?)
1094 * 04: DWORD - Hash = sum of bytes of keyname
1095 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1096 * 0C: DWORD - disk address of PreviousLevel Key.
1097 * 10: DWORD - disk address of Next Sublevel Key.
1098 * 14: DWORD - disk address of Next Key (on same level).
1099 * DKEP>18: WORD - Nr, Low Significant part.
1100 * 1A: WORD - Nr, High Significant part.
1102 * The disk address always points to the nr part of the previous key entry
1103 * of the referenced key. Don't ask me why, or even if I got this correct
1104 * from staring at 1kg of hexdumps. (DKEP)
1106 * The High significant part of the structure seems to equal the number
1107 * of the RGDB section. The low significant part is a unique ID within
1110 * There are two minor corrections to the position of that structure.
1111 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1112 * the DKE reread from there.
1113 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1114 * CPS - I have not experienced the above phenomenon in my registry files
1117 * 00: "RGDB" - magic
1118 * 04: DWORD offset to next RGDB section
1120 * 0C: WORD always 000d?
1121 * 0E: WORD RGDB block number
1122 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1124 * 20.....: disk keys
1127 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1128 * 08: WORD nrLS - low significant part of NR
1129 * 0A: WORD nrHS - high significant part of NR
1130 * 0C: DWORD bytesused - bytes used in this structure.
1131 * 10: WORD name_len - length of name in bytes. without \0
1132 * 12: WORD nr_of_values - number of values.
1133 * 14: char name[name_len] - name string. No \0.
1134 * 14+name_len: disk values
1135 * nextkeyoffset: ... next disk key
1138 * 00: DWORD type - value type (hmm, could be WORD too)
1139 * 04: DWORD - unknown, usually 0
1140 * 08: WORD namelen - length of Name. 0 means name=NULL
1141 * 0C: WORD datalen - length of Data.
1142 * 10: char name[namelen] - name, no \0
1143 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1144 * 10+namelen+datalen: next values or disk key
1146 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1147 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1148 * structure) and reading another RGDB_section.
1149 * repeat until end of file.
1151 * An interesting relationship exists in RGDB_section. The value at offset
1152 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1153 * idea at the moment what this means. (Kevin Cozens)
1155 * FIXME: this description needs some serious help, yes.
1158 struct _w95keyvalue
{
1160 unsigned short datalen
;
1162 unsigned char *data
;
1170 struct _w95keyvalue
*values
;
1171 struct _w95key
*prevlvl
;
1172 struct _w95key
*nextsub
;
1173 struct _w95key
*next
;
1187 /******************************************************************************
1188 * _w95_processKey [Internal]
1190 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1191 int nrLS
, int nrMS
, struct _w95_info
*info
)
1194 /* Disk Key Header structure (RGDB part) */
1196 unsigned long nextkeyoff
;
1197 unsigned short nrLS
;
1198 unsigned short nrMS
;
1199 unsigned long bytesused
;
1200 unsigned short keynamelen
;
1201 unsigned short values
;
1204 /* disk key values or nothing */
1206 /* Disk Key Value structure */
1210 unsigned short valnamelen
;
1211 unsigned short valdatalen
;
1212 /* valname, valdata */
1218 char *rgdbdata
= info
->rgdbbuffer
;
1219 int nbytes
= info
->rgdbsize
;
1220 char *curdata
= rgdbdata
;
1221 char *end
= rgdbdata
+ nbytes
;
1223 char *next
= rgdbdata
;
1229 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1231 memcpy(&off_next_rgdb
,curdata
+4,4);
1232 next
= curdata
+ off_next_rgdb
;
1233 nrgdb
= (int) *((short *)curdata
+ 7);
1235 } while (nrgdb
!= nrMS
&& (next
< end
));
1237 /* curdata now points to the start of the right RGDB section */
1240 #define XREAD(whereto,len) \
1241 if ((curdata + len) <end) {\
1242 memcpy(whereto,curdata,len);\
1247 while (curdata
< next
) {
1248 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1250 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1251 if (xdkh
->nrLS
== nrLS
) {
1252 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1253 curdata
+= sizeof(dkh
);
1256 curdata
+= xdkh
->nextkeyoff
;
1259 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1261 if (nrgdb
!= dkh
.nrMS
)
1264 assert((dkh
.keynamelen
<2) || curdata
[0]);
1265 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1266 curdata
+= dkh
.keynamelen
;
1268 for (i
=0;i
< dkh
.values
; i
++) {
1274 XREAD(&dkv
,sizeof(dkv
));
1276 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1277 curdata
+= dkv
.valnamelen
;
1279 if ((1 << dkv
.type
) & UNICONVMASK
) {
1280 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1281 len
= 2*(dkv
.valdatalen
+ 1);
1283 /* I don't think we want to NULL terminate all data */
1284 data
= xmalloc(dkv
.valdatalen
);
1285 memcpy (data
, curdata
, dkv
.valdatalen
);
1286 len
= dkv
.valdatalen
;
1289 curdata
+= dkv
.valdatalen
;
1303 /******************************************************************************
1304 * _w95_walkrgkn [Internal]
1306 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1307 struct _w95_info
*info
)
1310 /* Disk Key Entry structure (RGKN part) */
1314 unsigned long x3
;/*usually 0xFFFFFFFF */
1315 unsigned long prevlvl
;
1316 unsigned long nextsub
;
1318 unsigned short nrLS
;
1319 unsigned short nrMS
;
1320 } *dke
= (struct dke
*)off
;
1324 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1327 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1328 /* XXX <-- This is a hack*/
1333 if (dke
->nextsub
!= -1 &&
1334 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1335 && (dke
->nextsub
> 0x20)) {
1337 _w95_walkrgkn(lpxkey
,
1338 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1342 if (dke
->next
!= -1 &&
1343 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1344 (dke
->next
> 0x20)) {
1345 _w95_walkrgkn(prevkey
,
1346 info
->rgknbuffer
+ dke
->next
- 0x20,
1354 /******************************************************************************
1355 * _w95_loadreg [Internal]
1357 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1361 unsigned long where
,version
,rgdbsection
,end
;
1362 struct _w95_info info
;
1364 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1366 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1367 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1368 if (hfd
==HFILE_ERROR32
)
1371 if (4!=_lread32(hfd
,magic
,4))
1373 if (strcmp(magic
,"CREG")) {
1374 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1377 if (4!=_lread32(hfd
,&version
,4))
1379 if (4!=_lread32(hfd
,&rgdbsection
,4))
1381 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1383 if (4!=_lread32(hfd
,magic
,4))
1385 if (strcmp(magic
,"RGKN")) {
1386 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1390 /* STEP 1: Keylink structures */
1391 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1396 info
.rgknsize
= end
- where
;
1397 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1398 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1401 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1404 end
= hfdinfo
.nFileSizeLow
;
1405 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1407 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1410 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1411 info
.rgdbsize
= end
- rgdbsection
;
1413 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1417 _w95_walkrgkn(lpkey
, NULL
, &info
);
1419 free (info
.rgdbbuffer
);
1420 free (info
.rgknbuffer
);
1424 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1427 reghack - windows 3.11 registry data format demo program.
1429 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1430 a combined hash table and tree description, and finally a text table.
1432 The header is obvious from the struct header. The taboff1 and taboff2
1433 fields are always 0x20, and their usage is unknown.
1435 The 8-byte entry table has various entry types.
1437 tabent[0] is a root index. The second word has the index of the root of
1439 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1440 the index of the key/value that has that hash. Data with the same
1441 hash value are on a circular list. The other three words in the
1442 hash entry are always zero.
1443 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1444 entry: dirent and keyent/valent. They are identified by context.
1445 tabent[freeidx] is the first free entry. The first word in a free entry
1446 is the index of the next free entry. The last has 0 as a link.
1447 The other three words in the free list are probably irrelevant.
1449 Entries in text table are preceeded by a word at offset-2. This word
1450 has the value (2*index)+1, where index is the referring keyent/valent
1451 entry in the table. I have no suggestion for the 2* and the +1.
1452 Following the word, there are N bytes of data, as per the keyent/valent
1453 entry length. The offset of the keyent/valent entry is from the start
1454 of the text table to the first data byte.
1456 This information is not available from Microsoft. The data format is
1457 deduced from the reg.dat file by me. Mistakes may
1458 have been made. I claim no rights and give no guarantees for this program.
1460 Tor Sjøwall, tor@sn.no
1463 /* reg.dat header format */
1464 struct _w31_header
{
1465 char cookie
[8]; /* 'SHCC3.10' */
1466 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1467 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1468 unsigned long tabcnt
; /* number of entries in index table */
1469 unsigned long textoff
; /* offset of text part */
1470 unsigned long textsize
; /* byte size of text part */
1471 unsigned short hashsize
; /* hash size */
1472 unsigned short freeidx
; /* free index */
1475 /* generic format of table entries */
1476 struct _w31_tabent
{
1477 unsigned short w0
, w1
, w2
, w3
;
1480 /* directory tabent: */
1481 struct _w31_dirent
{
1482 unsigned short sibling_idx
; /* table index of sibling dirent */
1483 unsigned short child_idx
; /* table index of child dirent */
1484 unsigned short key_idx
; /* table index of key keyent */
1485 unsigned short value_idx
; /* table index of value valent */
1489 struct _w31_keyent
{
1490 unsigned short hash_idx
; /* hash chain index for string */
1491 unsigned short refcnt
; /* reference count */
1492 unsigned short length
; /* length of string */
1493 unsigned short string_off
; /* offset of string in text table */
1497 struct _w31_valent
{
1498 unsigned short hash_idx
; /* hash chain index for string */
1499 unsigned short refcnt
; /* reference count */
1500 unsigned short length
; /* length of string */
1501 unsigned short string_off
; /* offset of string in text table */
1504 /* recursive helper function to display a directory tree */
1506 __w31_dumptree( unsigned short idx
,
1508 struct _w31_tabent
*tab
,
1509 struct _w31_header
*head
,
1511 time_t lastmodified
,
1514 struct _w31_dirent
*dir
;
1515 struct _w31_keyent
*key
;
1516 struct _w31_valent
*val
;
1517 LPKEYSTRUCT xlpkey
= NULL
;
1519 static char tail
[400];
1522 dir
=(struct _w31_dirent
*)&tab
[idx
];
1525 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1527 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1528 tail
[key
->length
]='\0';
1529 /* all toplevel entries AND the entries in the
1530 * toplevel subdirectory belong to \SOFTWARE\Classes
1532 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1533 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1534 idx
=dir
->sibling_idx
;
1537 name
=strdupA2W(tail
);
1539 xlpkey
=_find_or_add_key(lpkey
,name
);
1541 /* only add if leaf node or valued node */
1542 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1543 if (dir
->value_idx
) {
1544 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1545 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1546 tail
[val
->length
]='\0';
1547 value
=strdupA2W(tail
);
1548 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1552 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1554 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1555 idx
=dir
->sibling_idx
;
1560 /******************************************************************************
1561 * _w31_loadreg [Internal]
1563 void _w31_loadreg(void) {
1565 struct _w31_header head
;
1566 struct _w31_tabent
*tab
;
1570 BY_HANDLE_FILE_INFORMATION hfinfo
;
1571 time_t lastmodified
;
1574 TRACE(reg
,"(void)\n");
1576 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1577 if (hf
==HFILE_ERROR32
)
1580 /* read & dump header */
1581 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1582 ERR(reg
, "reg.dat is too short.\n");
1586 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1587 ERR(reg
, "reg.dat has bad signature.\n");
1592 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1593 /* read and dump index table */
1595 if (len
!=_lread32(hf
,tab
,len
)) {
1596 ERR(reg
,"couldn't read %d bytes.\n",len
);
1603 txt
= xmalloc(head
.textsize
);
1604 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1605 ERR(reg
,"couldn't seek to textblock.\n");
1611 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1612 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1619 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1620 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1626 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1627 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1628 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1636 /**********************************************************************************
1637 * SHELL_LoadRegistry [Internal]
1639 void SHELL_LoadRegistry( void )
1646 TRACE(reg
,"(void)\n");
1648 /* Load windows 3.1 entries */
1650 /* Load windows 95 entries */
1651 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1652 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1653 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1655 /* the global user default is loaded under HKEY_USERS\\.Default */
1656 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1657 lpkey
= lookup_hkey(hkey
);
1659 WARN(reg
,"Could not create global user default key\n");
1660 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1662 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1663 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1666 /* the global machine defaults */
1667 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1669 /* load the user saved registries */
1671 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1673 pwd
=getpwuid(getuid());
1674 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1675 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1676 strcpy(fn
,pwd
->pw_dir
);
1677 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1678 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1680 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1681 strcpy(fn
,pwd
->pw_dir
);
1682 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1683 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1686 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1687 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1688 DWORD junk
,type
,len
;
1692 if (( RegQueryValueEx32A(
1699 )!=ERROR_SUCCESS
) ||
1702 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1708 /********************* API FUNCTIONS ***************************************/
1712 * All functions are stubs to RegOpenKeyEx32W where all the
1716 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1717 * RegOpenKey32W -> RegOpenKeyEx32W
1721 /******************************************************************************
1722 * RegOpenKeyEx32W [ADVAPI32.150]
1723 * Opens the specified key
1725 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1728 * hkey [I] Handle of open key
1729 * lpszSubKey [I] Name of subkey to open
1730 * dwReserved [I] Reserved - must be zero
1731 * samDesired [I] Security access mask
1732 * retkey [O] Address of handle of open key
1735 * Success: ERROR_SUCCESS
1736 * Failure: Error code
1738 DWORD WINAPI
RegOpenKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1739 REGSAM samDesired
, LPHKEY retkey
)
1741 LPKEYSTRUCT lpNextKey
,lpxkey
;
1745 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1748 lpNextKey
= lookup_hkey( hkey
);
1750 return ERROR_INVALID_HANDLE
;
1752 if (!lpszSubKey
|| !*lpszSubKey
) {
1753 /* Either NULL or pointer to empty string, so return a new handle
1754 to the original hkey */
1756 add_handle(currenthandle
,lpNextKey
,samDesired
);
1757 *retkey
=currenthandle
;
1758 return ERROR_SUCCESS
;
1761 if (lpszSubKey
[0] == '\\') {
1762 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1763 return ERROR_BAD_PATHNAME
;
1766 split_keypath(lpszSubKey
,&wps
,&wpc
);
1768 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1772 lpxkey
=lpNextKey
->nextsub
;
1774 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
)) {
1777 lpxkey
=lpxkey
->next
;
1781 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1783 return ERROR_FILE_NOT_FOUND
;
1790 add_handle(currenthandle
,lpxkey
,samDesired
);
1791 *retkey
= currenthandle
;
1792 TRACE(reg
," Returning %x\n", currenthandle
);
1794 return ERROR_SUCCESS
;
1798 /******************************************************************************
1799 * RegOpenKeyEx32A [ADVAPI32.149]
1801 DWORD WINAPI
RegOpenKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1802 REGSAM samDesired
, LPHKEY retkey
)
1804 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1807 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1809 ret
= RegOpenKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
1815 /******************************************************************************
1816 * RegOpenKey32W [ADVAPI32.151]
1819 * hkey [I] Handle of open key
1820 * lpszSubKey [I] Address of name of subkey to open
1821 * retkey [O] Address of handle of open key
1824 * Success: ERROR_SUCCESS
1825 * Failure: Error code
1827 DWORD WINAPI
RegOpenKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1829 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1830 return RegOpenKeyEx32W( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
1834 /******************************************************************************
1835 * RegOpenKey32A [ADVAPI32.148]
1837 DWORD WINAPI
RegOpenKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1840 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1841 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1842 ret
= RegOpenKey32W( hkey
, lpszSubKeyW
, retkey
);
1848 /******************************************************************************
1849 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1851 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1853 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1854 return RegOpenKey32A( hkey
, lpszSubKey
, retkey
);
1861 * All those functions convert their respective
1862 * arguments and call RegCreateKeyExW at the end.
1864 * We stay away from the Ex functions as long as possible because there are
1865 * differences in the return values
1868 * RegCreateKeyEx32A \
1869 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1873 /******************************************************************************
1874 * RegCreateKeyEx32W [ADVAPI32.131]
1877 * hkey [I] Handle of an open key
1878 * lpszSubKey [I] Address of subkey name
1879 * dwReserved [I] Reserved - must be 0
1880 * lpszClass [I] Address of class string
1881 * fdwOptions [I] Special options flag
1882 * samDesired [I] Desired security access
1883 * lpSecAttribs [I] Address of key security structure
1884 * retkey [O] Address of buffer for opened handle
1885 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1887 DWORD WINAPI
RegCreateKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
,
1888 DWORD dwReserved
, LPWSTR lpszClass
,
1889 DWORD fdwOptions
, REGSAM samDesired
,
1890 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1891 LPHKEY retkey
, LPDWORD lpDispos
)
1893 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1897 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
1898 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
1899 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
1901 lpNextKey
= lookup_hkey(hkey
);
1903 return ERROR_INVALID_HANDLE
;
1905 /* Check for valid options */
1906 switch(fdwOptions
) {
1907 case REG_OPTION_NON_VOLATILE
:
1908 case REG_OPTION_VOLATILE
:
1909 case REG_OPTION_BACKUP_RESTORE
:
1912 return ERROR_INVALID_PARAMETER
;
1915 /* Sam has to be a combination of the following */
1917 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
1918 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
1919 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
1920 return ERROR_INVALID_PARAMETER
;
1922 if (!lpszSubKey
|| !*lpszSubKey
) {
1924 add_handle(currenthandle
,lpNextKey
,samDesired
);
1925 *retkey
=currenthandle
;
1926 TRACE(reg
, "Returning %x\n", currenthandle
);
1927 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1928 return ERROR_SUCCESS
;
1931 if (lpszSubKey
[0] == '\\') {
1932 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1933 return ERROR_BAD_PATHNAME
;
1936 split_keypath(lpszSubKey
,&wps
,&wpc
);
1938 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1941 lpxkey
=lpNextKey
->nextsub
;
1943 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1945 lpxkey
=lpxkey
->next
;
1954 add_handle(currenthandle
,lpxkey
,samDesired
);
1955 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1956 *retkey
= currenthandle
;
1957 TRACE(reg
, "Returning %x\n", currenthandle
);
1959 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1961 return ERROR_SUCCESS
;
1964 /* Good. Now the hard part */
1966 lplpPrevKey
= &(lpNextKey
->nextsub
);
1967 lpxkey
= *lplpPrevKey
;
1969 lplpPrevKey
= &(lpxkey
->next
);
1970 lpxkey
= *lplpPrevKey
;
1972 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1973 if (!*lplpPrevKey
) {
1975 TRACE(reg
, "Returning OUTOFMEMORY\n");
1976 return ERROR_OUTOFMEMORY
;
1978 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1979 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
1980 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1981 (*lplpPrevKey
)->next
= NULL
;
1982 (*lplpPrevKey
)->nextsub
= NULL
;
1983 (*lplpPrevKey
)->values
= NULL
;
1984 (*lplpPrevKey
)->nrofvalues
= 0;
1985 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1987 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1989 (*lplpPrevKey
)->class = NULL
;
1990 lpNextKey
= *lplpPrevKey
;
1994 add_handle(currenthandle
,lpNextKey
,samDesired
);
1996 /*FIXME: flag handling correct? */
1997 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1999 lpNextKey
->class = strdupW(lpszClass
);
2001 lpNextKey
->class = NULL
;
2002 *retkey
= currenthandle
;
2003 TRACE(reg
, "Returning %x\n", currenthandle
);
2005 *lpDispos
= REG_CREATED_NEW_KEY
;
2007 return ERROR_SUCCESS
;
2011 /******************************************************************************
2012 * RegCreateKeyEx32A [ADVAPI32.130]
2014 DWORD WINAPI
RegCreateKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2015 LPSTR lpszClass
, DWORD fdwOptions
,
2017 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2018 LPHKEY retkey
, LPDWORD lpDispos
)
2020 LPWSTR lpszSubKeyW
, lpszClassW
;
2023 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2024 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2027 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2028 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2030 ret
= RegCreateKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2031 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2034 if(lpszSubKeyW
) free(lpszSubKeyW
);
2035 if(lpszClassW
) free(lpszClassW
);
2041 /******************************************************************************
2042 * RegCreateKey32W [ADVAPI32.132]
2044 DWORD WINAPI
RegCreateKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2047 LPKEYSTRUCT lpNextKey
;
2049 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2051 /* This check is here because the return value is different than the
2052 one from the Ex functions */
2053 lpNextKey
= lookup_hkey(hkey
);
2055 return ERROR_BADKEY
;
2057 return RegCreateKeyEx32W( hkey
, lpszSubKey
, 0, NULL
,
2058 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2063 /******************************************************************************
2064 * RegCreateKey32A [ADVAPI32.129]
2066 DWORD WINAPI
RegCreateKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2071 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2072 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2073 ret
= RegCreateKey32W( hkey
, lpszSubKeyW
, retkey
);
2074 if(lpszSubKeyW
) free(lpszSubKeyW
);
2079 /******************************************************************************
2080 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2082 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2084 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2085 return RegCreateKey32A( hkey
, lpszSubKey
, retkey
);
2090 * Query Value Functions
2091 * Win32 differs between keynames and valuenames.
2092 * multiple values may belong to one key, the special value
2093 * with name NULL is the default value used by the win31
2097 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2098 * RegQueryValue32W -> RegQueryValueEx32W
2102 /******************************************************************************
2103 * RegQueryValueEx32W [ADVAPI32.158]
2104 * Retrieves type and data for a specified name associated with an open key
2107 * hkey [I] Handle of key to query
2108 * lpValueName [I] Name of value to query
2109 * lpdwReserved [I] Reserved - must be NULL
2110 * lpdwType [O] Address of buffer for value type. If NULL, the type
2112 * lpbData [O] Address of data buffer. If NULL, the actual data is
2114 * lpcbData [I/O] Address of data buffer size
2117 * ERROR_SUCCESS: Success
2118 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2120 DWORD WINAPI
RegQueryValueEx32W( HKEY hkey
, LPWSTR lpValueName
,
2121 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2122 LPBYTE lpbData
, LPDWORD lpcbData
)
2127 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%ld)\n", hkey
, debugstr_w(lpValueName
),
2128 lpdwReserved
, lpdwType
, lpbData
, lpcbData
?*lpcbData
:0);
2130 lpkey
= lookup_hkey(hkey
);
2132 return ERROR_INVALID_HANDLE
;
2134 /* Reserved must be NULL (at least for now) */
2136 return ERROR_INVALID_PARAMETER
;
2138 /* An empty name string is equivalent to NULL */
2139 if (lpValueName
&& !*lpValueName
)
2142 if (lpValueName
==NULL
) {
2143 /* Use key's unnamed or default value, if any */
2144 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2145 if (lpkey
->values
[i
].name
==NULL
)
2148 /* Search for the key name */
2149 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2150 if ( lpkey
->values
[i
].name
&&
2151 !lstrcmpi32W(lpValueName
,lpkey
->values
[i
].name
)
2156 if (i
==lpkey
->nrofvalues
) {
2157 TRACE(reg
,"Key not found\n");
2158 if (lpValueName
==NULL
) {
2159 /* Empty keyname not found */
2161 *(WCHAR
*)lpbData
= 0;
2166 TRACE(reg
, "Returning an empty string\n");
2167 return ERROR_SUCCESS
;
2169 return ERROR_FILE_NOT_FOUND
;
2173 *lpdwType
= lpkey
->values
[i
].type
;
2175 if (lpbData
==NULL
) {
2176 /* Data is not required */
2177 if (lpcbData
==NULL
) {
2178 /* And data size is not required */
2179 /* So all that is returned is the type (set above) */
2180 return ERROR_SUCCESS
;
2182 /* Set the size required and return success */
2183 *lpcbData
= lpkey
->values
[i
].len
;
2184 return ERROR_SUCCESS
;
2187 if (*lpcbData
<lpkey
->values
[i
].len
) {
2188 /* The size was specified, but the data is too big for it */
2189 /* Instead of setting it to NULL, fill in with as much as possible */
2190 /* But the docs do not specify how to handle the lpbData here */
2191 /* *(WCHAR*)lpbData= 0; */
2192 memcpy(lpbData
,lpkey
->values
[i
].data
,*lpcbData
);
2193 *lpcbData
= lpkey
->values
[i
].len
;
2194 return ERROR_MORE_DATA
;
2197 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2199 /* Extra debugging output */
2203 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
2206 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)*lpbData
);
2209 TRACE(reg
," Data(binary)\n");
2210 /* Is there a way of printing this in readable form? */
2213 TRACE(reg
, "Unknown data type %ld\n", *lpdwType
);
2217 /* Set the actual size */
2218 *lpcbData
= lpkey
->values
[i
].len
;
2219 return ERROR_SUCCESS
;
2223 /******************************************************************************
2224 * RegQueryValue32W [ADVAPI32.159]
2226 DWORD WINAPI
RegQueryValue32W( HKEY hkey
, LPWSTR lpszSubKey
, LPWSTR lpszData
,
2232 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2233 lpcbData
?*lpcbData
:0);
2235 /* Only open subkey, if we really do descend */
2236 if (lpszSubKey
&& *lpszSubKey
) {
2237 ret
= RegOpenKey32W( hkey
, lpszSubKey
, &xhkey
);
2238 if (ret
!= ERROR_SUCCESS
) {
2239 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2246 ret
= RegQueryValueEx32W( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2254 /******************************************************************************
2255 * RegQueryValueEx32A [ADVAPI32.157]
2257 DWORD WINAPI
RegQueryValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2258 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2259 LPBYTE lpbData
, LPDWORD lpcbData
)
2261 LPWSTR lpszValueNameW
;
2267 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
,debugstr_a(lpszValueName
),
2268 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2270 lpszValueNameW
= lpszValueName
?strdupA2W(lpszValueName
):NULL
;
2272 /* Why would this be set? It is just an output */
2280 /* Only get the size for now */
2281 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
,
2282 &type
, buf
, mylen
);
2284 if (ret
==ERROR_MORE_DATA
) {
2285 buf
= (LPBYTE
)xmalloc(*mylen
);
2287 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2288 myxlen
= 2*(*lpcbData
);
2291 /* Data is not required */
2294 myxlen
= *lpcbData
*2;
2300 /* Now get the data */
2301 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
, &type
,
2306 if (ret
==ERROR_SUCCESS
) {
2308 if (UNICONVMASK
& (1<<(type
))) {
2309 /* convert UNICODE to ASCII */
2310 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2311 *lpcbData
= myxlen
/2;
2313 if (myxlen
>*lpcbData
)
2314 ret
= ERROR_MORE_DATA
;
2316 memcpy(lpbData
,buf
,myxlen
);
2321 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2322 *lpcbData
= myxlen
/2;
2325 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2326 *lpcbData
= myxlen
/2;
2330 if(lpszValueNameW
) free(lpszValueNameW
);
2335 /******************************************************************************
2336 * RegQueryValueEx16 [KERNEL.225]
2338 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2339 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2340 LPBYTE lpbData
, LPDWORD lpcbData
)
2342 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2343 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2344 return RegQueryValueEx32A( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2345 lpbData
, lpcbData
);
2349 /******************************************************************************
2350 * RegQueryValue32A [ADVAPI32.156]
2352 DWORD WINAPI
RegQueryValue32A( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2358 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2359 lpcbData
?*lpcbData
:0);
2361 if (lpszSubKey
&& *lpszSubKey
) {
2362 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2363 if( ret
!= ERROR_SUCCESS
)
2369 ret
= RegQueryValueEx32A( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2372 RegCloseKey( xhkey
);
2377 /******************************************************************************
2378 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2381 * Is this HACK still applicable?
2384 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2385 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2388 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2391 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2392 lpcbData
?*lpcbData
:0);
2395 *lpcbData
&= 0xFFFF;
2396 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2401 * Setting values of Registry keys
2404 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2405 * RegSetValue32W -> RegSetValueEx32W
2409 /******************************************************************************
2410 * RegSetValueEx32W [ADVAPI32.170]
2411 * Sets the data and type of a value under a register key
2414 * hkey [I] Handle of key to set value for
2415 * lpszValueName [I] Name of value to set
2416 * dwReserved [I] Reserved - must be zero
2417 * dwType [I] Flag for value type
2418 * lpbData [I] Address of value data
2419 * cbData [I] Size of value data
2422 * Success: ERROR_SUCCESS
2423 * Failure: Error code
2425 DWORD WINAPI
RegSetValueEx32W( HKEY hkey
, LPWSTR lpszValueName
,
2426 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2432 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2433 dwReserved
, dwType
, lpbData
, cbData
);
2437 TRACE(reg
," Data(sz)=%s\n", debugstr_w((LPCWSTR
)lpbData
));
2440 TRACE(reg
," Data(binary)\n");
2443 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)lpbData
);
2446 TRACE(reg
,"Unknown type: %ld\n", dwType
);
2449 lpkey
= lookup_hkey( hkey
);
2451 return ERROR_INVALID_HANDLE
;
2453 lpkey
->flags
|= REG_OPTION_TAINTED
;
2455 if (lpszValueName
==NULL
) {
2456 /* Sets type and name for key's unnamed or default value */
2457 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2458 if (lpkey
->values
[i
].name
==NULL
)
2461 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2462 if ( lpkey
->values
[i
].name
&&
2463 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2467 if (i
==lpkey
->nrofvalues
) {
2468 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2470 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2472 lpkey
->nrofvalues
++;
2473 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2475 if (lpkey
->values
[i
].name
==NULL
) {
2477 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2479 lpkey
->values
[i
].name
= NULL
;
2481 lpkey
->values
[i
].len
= cbData
;
2482 lpkey
->values
[i
].type
= dwType
;
2483 if (lpkey
->values
[i
].data
!=NULL
)
2484 free(lpkey
->values
[i
].data
);
2485 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2486 lpkey
->values
[i
].lastmodified
= time(NULL
);
2487 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2488 return ERROR_SUCCESS
;
2492 /******************************************************************************
2493 * RegSetValueEx32A [ADVAPI32.169]
2496 DWORD WINAPI
RegSetValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2497 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2501 LPWSTR lpszValueNameW
;
2504 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2505 dwReserved
,dwType
,lpbData
,cbData
);
2507 if ((1<<dwType
) & UNICONVMASK
) {
2508 buf
=(LPBYTE
)strdupA2W(lpbData
);
2509 cbData
=2*strlen(lpbData
)+2;
2513 lpszValueNameW
= strdupA2W(lpszValueName
);
2515 lpszValueNameW
= NULL
;
2516 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2518 free(lpszValueNameW
);
2525 /******************************************************************************
2526 * RegSetValueEx16 [KERNEL.226]
2528 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2529 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2531 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2532 dwReserved
,dwType
,lpbData
,cbData
);
2533 return RegSetValueEx32A( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2538 /******************************************************************************
2539 * RegSetValue32W [ADVAPI32.171]
2541 DWORD WINAPI
RegSetValue32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2542 LPCWSTR lpszData
, DWORD cbData
)
2547 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2548 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2550 if (lpszSubKey
&& *lpszSubKey
) {
2551 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2552 if (ret
!=ERROR_SUCCESS
)
2556 if (dwType
!=REG_SZ
) {
2557 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2560 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2561 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2562 cbData
,debugstr_w(lpszData
),2*lstrlen32W(lpszData
)+2
2564 cbData
=2*lstrlen32W(lpszData
)+2;
2566 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2573 /******************************************************************************
2574 * RegSetValue32A [ADVAPI32.168]
2577 DWORD WINAPI
RegSetValue32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2578 LPCSTR lpszData
, DWORD cbData
)
2583 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2584 if (lpszSubKey
&& *lpszSubKey
) {
2585 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2586 if (ret
!=ERROR_SUCCESS
)
2591 if (dwType
!=REG_SZ
) {
2592 TRACE(reg
,"dwType=%ld!\n",dwType
);
2595 if (cbData
!=strlen(lpszData
)+1)
2596 cbData
=strlen(lpszData
)+1;
2597 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2604 /******************************************************************************
2605 * RegSetValue16 [KERNEL.221] [SHELL.5]
2607 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2608 LPCSTR lpszData
, DWORD cbData
)
2610 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2611 debugstr_a(lpszData
),cbData
);
2612 return RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2620 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2621 * RegEnumKey32W -> RegEnumKeyEx32W
2625 /******************************************************************************
2626 * RegEnumKeyEx32W [ADVAPI32.139]
2629 * hkey [I] Handle to key to enumerate
2630 * iSubKey [I] Index of subkey to enumerate
2631 * lpszName [O] Buffer for subkey name
2632 * lpcchName [O] Size of subkey buffer
2633 * lpdwReserved [I] Reserved
2634 * lpszClass [O] Buffer for class string
2635 * lpcchClass [O] Size of class buffer
2636 * ft [O] Time key last written to
2638 DWORD WINAPI
RegEnumKeyEx32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2639 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2640 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2643 LPKEYSTRUCT lpkey
,lpxkey
;
2645 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2646 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2648 lpkey
= lookup_hkey( hkey
);
2650 return ERROR_INVALID_HANDLE
;
2652 if (!lpkey
->nextsub
)
2653 return ERROR_NO_MORE_ITEMS
;
2654 lpxkey
=lpkey
->nextsub
;
2656 /* Traverse the subkeys */
2657 while (iSubkey
&& lpxkey
) {
2659 lpxkey
=lpxkey
->next
;
2662 if (iSubkey
|| !lpxkey
)
2663 return ERROR_NO_MORE_ITEMS
;
2664 if (lstrlen32W(lpxkey
->keyname
)+1>*lpcchName
)
2665 return ERROR_MORE_DATA
;
2666 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2669 *lpcchName
= lstrlen32W(lpszName
);
2672 /* FIXME: what should we write into it? */
2676 return ERROR_SUCCESS
;
2680 /******************************************************************************
2681 * RegEnumKey32W [ADVAPI32.140]
2683 DWORD WINAPI
RegEnumKey32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2688 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2689 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2693 /******************************************************************************
2694 * RegEnumKeyEx32A [ADVAPI32.138]
2696 DWORD WINAPI
RegEnumKeyEx32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2697 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2698 LPSTR lpszClass
, LPDWORD lpcchClass
,
2701 DWORD ret
,lpcchNameW
,lpcchClassW
;
2702 LPWSTR lpszNameW
,lpszClassW
;
2705 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2706 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2709 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2710 lpcchNameW
= *lpcchName
;
2716 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2717 lpcchClassW
= *lpcchClass
;
2722 ret
=RegEnumKeyEx32W(
2732 if (ret
==ERROR_SUCCESS
) {
2733 lstrcpyWtoA(lpszName
,lpszNameW
);
2734 *lpcchName
=strlen(lpszName
);
2736 lstrcpyWtoA(lpszClass
,lpszClassW
);
2737 *lpcchClass
=strlen(lpszClass
);
2748 /******************************************************************************
2749 * RegEnumKey32A [ADVAPI32.137]
2751 DWORD WINAPI
RegEnumKey32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2756 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2757 return RegEnumKeyEx32A( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2762 /******************************************************************************
2763 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2765 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2768 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2769 return RegEnumKey32A( hkey
, iSubkey
, lpszName
, lpcchName
);
2774 * Enumerate Registry Values
2777 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2781 /******************************************************************************
2782 * RegEnumValue32W [ADVAPI32.142]
2785 * hkey [I] Handle to key to query
2786 * iValue [I] Index of value to query
2787 * lpszValue [O] Value string
2788 * lpcchValue [O] Size of value buffer
2789 * lpdReserved [I] Reserved
2790 * lpdwType [O] Type code
2791 * lpbData [O] Value data
2792 * lpcbData [O] Size of data buffer
2794 * Note: wide character functions that take and/or return "character counts"
2795 * use TCHAR (that is unsigned short or char) not byte counts.
2797 DWORD WINAPI
RegEnumValue32W( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
2798 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2799 LPDWORD lpdwType
, LPBYTE lpbData
,
2805 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
2806 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2808 lpkey
= lookup_hkey( hkey
);
2810 return ERROR_INVALID_HANDLE
;
2812 if (lpkey
->nrofvalues
<= iValue
)
2813 return ERROR_NO_MORE_ITEMS
;
2815 /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2816 val
= lpkey
->values
+ iValue
;
2819 if (lstrlen32W(val
->name
)+1>*lpcchValue
) {
2820 *lpcchValue
= lstrlen32W(val
->name
)+1;
2821 return ERROR_MORE_DATA
;
2823 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2824 *lpcchValue
=lstrlen32W(val
->name
);
2830 /* Can be NULL if the type code is not required */
2832 *lpdwType
= val
->type
;
2835 if (val
->len
>*lpcbData
)
2836 return ERROR_MORE_DATA
;
2837 memcpy(lpbData
,val
->data
,val
->len
);
2838 *lpcbData
= val
->len
;
2840 return ERROR_SUCCESS
;
2844 /******************************************************************************
2845 * RegEnumValue32A [ADVAPI32.141]
2847 DWORD WINAPI
RegEnumValue32A( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2848 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2849 LPDWORD lpdwType
, LPBYTE lpbData
,
2854 DWORD ret
,lpcbDataW
;
2857 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2858 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2860 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2862 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2863 lpcbDataW
= *lpcbData
;
2867 ret
= RegEnumValue32W( hkey
, iValue
, lpszValueW
, lpcchValue
,
2868 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
2873 if (ret
==ERROR_SUCCESS
) {
2874 lstrcpyWtoA(lpszValue
,lpszValueW
);
2876 if ((1<<dwType
) & UNICONVMASK
) {
2877 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2879 if (lpcbDataW
> *lpcbData
)
2880 ret
= ERROR_MORE_DATA
;
2882 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2884 *lpcbData
= lpcbDataW
;
2887 if (lpbDataW
) free(lpbDataW
);
2888 if (lpszValueW
) free(lpszValueW
);
2893 /******************************************************************************
2894 * RegEnumValue16 [KERNEL.223]
2896 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2897 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2898 LPDWORD lpdwType
, LPBYTE lpbData
,
2901 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2902 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2903 return RegEnumValue32A( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
2904 lpdwType
, lpbData
, lpcbData
);
2908 /******************************************************************************
2909 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2910 * Releases the handle of the specified key
2913 * hkey [I] Handle of key to close
2916 * Success: ERROR_SUCCESS
2917 * Failure: Error code
2919 DWORD WINAPI
RegCloseKey( HKEY hkey
)
2921 TRACE(reg
,"(%x)\n",hkey
);
2923 /* The standard handles are allowed to succeed, even though they are not
2925 if (is_standard_hkey(hkey
))
2926 return ERROR_SUCCESS
;
2928 return remove_handle(hkey
);
2933 * Delete registry key
2936 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2940 /******************************************************************************
2941 * RegDeleteKey32W [ADVAPI32.134]
2944 * hkey [I] Handle to open key
2945 * lpszSubKey [I] Name of subkey to delete
2948 * Success: ERROR_SUCCESS
2949 * Failure: Error code
2951 DWORD WINAPI
RegDeleteKey32W( HKEY hkey
, LPWSTR lpszSubKey
)
2953 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2957 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
2959 lpNextKey
= lookup_hkey(hkey
);
2961 return ERROR_INVALID_HANDLE
;
2963 /* Subkey param cannot be NULL */
2964 if (!lpszSubKey
|| !*lpszSubKey
)
2965 return ERROR_BADKEY
;
2967 /* We need to know the previous key in the hier. */
2968 split_keypath(lpszSubKey
,&wps
,&wpc
);
2972 lpxkey
=lpNextKey
->nextsub
;
2974 TRACE(reg
, " Scanning [%s]\n",
2975 debugstr_w(lpxkey
->keyname
));
2976 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2978 lpxkey
=lpxkey
->next
;
2982 TRACE(reg
, " Not found.\n");
2983 /* not found is success */
2984 return ERROR_SUCCESS
;
2989 lpxkey
= lpNextKey
->nextsub
;
2990 lplpPrevKey
= &(lpNextKey
->nextsub
);
2992 TRACE(reg
, " Scanning [%s]\n",
2993 debugstr_w(lpxkey
->keyname
));
2994 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2996 lplpPrevKey
= &(lpxkey
->next
);
2997 lpxkey
= lpxkey
->next
;
3002 WARN(reg
, " Not found.\n");
3003 return ERROR_FILE_NOT_FOUND
;
3006 if (lpxkey
->nextsub
) {
3008 WARN(reg
, " Not empty.\n");
3009 return ERROR_CANTWRITE
;
3011 *lplpPrevKey
= lpxkey
->next
;
3012 free(lpxkey
->keyname
);
3014 free(lpxkey
->class);
3016 free(lpxkey
->values
);
3019 TRACE(reg
, " Done.\n");
3020 return ERROR_SUCCESS
;
3024 /******************************************************************************
3025 * RegDeleteKey32A [ADVAPI32.133]
3027 DWORD WINAPI
RegDeleteKey32A( HKEY hkey
, LPCSTR lpszSubKey
)
3032 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3033 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3034 ret
= RegDeleteKey32W( hkey
, lpszSubKeyW
);
3035 if(lpszSubKeyW
) free(lpszSubKeyW
);
3040 /******************************************************************************
3041 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3043 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3045 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3046 return RegDeleteKey32A( hkey
, lpszSubKey
);
3051 * Delete registry value
3054 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3058 /******************************************************************************
3059 * RegDeleteValue32W [ADVAPI32.136]
3067 DWORD WINAPI
RegDeleteValue32W( HKEY hkey
, LPWSTR lpszValue
)
3073 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3075 lpkey
= lookup_hkey( hkey
);
3077 return ERROR_INVALID_HANDLE
;
3080 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3081 if ( lpkey
->values
[i
].name
&&
3082 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
3086 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3087 if (lpkey
->values
[i
].name
==NULL
)
3091 if (i
== lpkey
->nrofvalues
)
3092 return ERROR_FILE_NOT_FOUND
;
3094 val
= lpkey
->values
+i
;
3095 if (val
->name
) free(val
->name
);
3096 if (val
->data
) free(val
->data
);
3100 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3102 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3104 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3106 lpkey
->nrofvalues
--;
3107 return ERROR_SUCCESS
;
3111 /******************************************************************************
3112 * RegDeleteValue32A [ADVAPI32.135]
3114 DWORD WINAPI
RegDeleteValue32A( HKEY hkey
, LPSTR lpszValue
)
3119 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3120 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3121 ret
= RegDeleteValue32W( hkey
, lpszValueW
);
3122 if(lpszValueW
) free(lpszValueW
);
3127 /******************************************************************************
3128 * RegDeleteValue16 [KERNEL.222]
3130 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3132 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3133 return RegDeleteValue32A( hkey
, lpszValue
);
3137 /******************************************************************************
3138 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3139 * Writes key to registry
3142 * hkey [I] Handle of key to write
3145 * Success: ERROR_SUCCESS
3146 * Failure: Error code
3148 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3153 TRACE(reg
, "(%x)\n", hkey
);
3155 lpkey
= lookup_hkey( hkey
);
3157 return ERROR_INVALID_HANDLE
;
3159 ERR(reg
, "What is the correct filename?\n");
3161 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3164 return ERROR_SUCCESS
;
3166 return ERROR_UNKNOWN
; /* FIXME */
3170 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3173 /******************************************************************************
3174 * RegQueryInfoKey32W [ADVAPI32.153]
3177 * hkey [I] Handle to key to query
3178 * lpszClass [O] Buffer for class string
3179 * lpcchClass [O] Size of class string buffer
3180 * lpdwReserved [I] Reserved
3181 * lpcSubKeys [I] Buffer for number of subkeys
3182 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3183 * lpcchMaxClass [O] Buffer for longest class string length
3184 * lpcValues [O] Buffer for number of value entries
3185 * lpcchMaxValueName [O] Buffer for longest value name length
3186 * lpccbMaxValueData [O] Buffer for longest value data length
3187 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3189 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3190 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3191 * lpcchClass is NULL
3192 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3193 * (it's hard to test validity, so test !NULL instead)
3195 DWORD WINAPI
RegQueryInfoKey32W( HKEY hkey
, LPWSTR lpszClass
,
3196 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3197 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3198 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3199 LPDWORD lpcchMaxValueName
,
3200 LPDWORD lpccbMaxValueData
,
3201 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3203 LPKEYSTRUCT lpkey
,lpxkey
;
3204 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3207 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3208 lpkey
= lookup_hkey(hkey
);
3210 return ERROR_INVALID_HANDLE
;
3212 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3213 return ERROR_INVALID_PARAMETER
;
3215 /* either lpcchClass is valid or this is win95 and lpcchClass
3218 DWORD classLen
= lstrlen32W(lpkey
->class);
3220 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3221 *lpcchClass
=classLen
+1;
3222 return ERROR_MORE_DATA
;
3225 *lpcchClass
=classLen
;
3226 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3234 *lpcchClass
= lstrlen32W(lpkey
->class);
3236 lpxkey
=lpkey
->nextsub
;
3237 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3240 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
3241 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
3242 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
3243 maxclass
=lstrlen32W(lpxkey
->class);
3244 lpxkey
=lpxkey
->next
;
3246 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3247 LPKEYVALUE val
=lpkey
->values
+i
;
3249 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
3250 maxvname
=lstrlen32W(val
->name
);
3251 if (val
->len
>maxvdata
)
3254 if (!maxclass
) maxclass
= 1;
3255 if (!maxvname
) maxvname
= 1;
3257 *lpcValues
= lpkey
->nrofvalues
;
3259 *lpcSubKeys
= nrofkeys
;
3261 *lpcchMaxSubkey
= maxsubkey
;
3263 *lpcchMaxClass
= maxclass
;
3264 if (lpcchMaxValueName
)
3265 *lpcchMaxValueName
= maxvname
;
3266 if (lpccbMaxValueData
)
3267 *lpccbMaxValueData
= maxvdata
;
3268 return ERROR_SUCCESS
;
3272 /******************************************************************************
3273 * RegQueryInfoKey32A [ADVAPI32.152]
3275 DWORD WINAPI
RegQueryInfoKey32A( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3276 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3277 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3278 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3279 LPDWORD lpccbMaxValueData
,
3280 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3282 LPWSTR lpszClassW
= NULL
;
3285 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3288 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3289 } else if (VERSION_GetVersion() == WIN95
) {
3290 /* win95 allows lpcchClass to be null */
3291 /* we don't know how big lpszClass is, would
3292 MAX_PATHNAME_LEN be the correct default? */
3293 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3298 ret
=RegQueryInfoKey32W(
3309 lpcbSecurityDescriptor
,
3312 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3313 lstrcpyWtoA(lpszClass
,lpszClassW
);
3320 /******************************************************************************
3321 * RegConnectRegistry32W [ADVAPI32.128]
3324 * lpMachineName [I] Address of name of remote computer
3325 * hHey [I] Predefined registry handle
3326 * phkResult [I] Address of buffer for remote registry handle
3328 LONG WINAPI
RegConnectRegistry32W( LPCWSTR lpMachineName
, HKEY hKey
,
3331 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3333 if (!lpMachineName
|| !*lpMachineName
) {
3334 /* Use the local machine name */
3335 return RegOpenKey16( hKey
, "", phkResult
);
3338 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3339 return ERROR_BAD_NETPATH
;
3343 /******************************************************************************
3344 * RegConnectRegistry32A [ADVAPI32.127]
3346 LONG WINAPI
RegConnectRegistry32A( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3349 LPWSTR machineW
= strdupA2W(machine
);
3350 ret
= RegConnectRegistry32W( machineW
, hkey
, reskey
);
3356 /******************************************************************************
3357 * RegGetKeySecurity [ADVAPI32.144]
3358 * Retrieves a copy of security descriptor protecting the registry key
3361 * hkey [I] Open handle of key to set
3362 * SecurityInformation [I] Descriptor contents
3363 * pSecurityDescriptor [O] Address of descriptor for key
3364 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3367 * Success: ERROR_SUCCESS
3368 * Failure: Error code
3370 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3371 SECURITY_INFORMATION SecurityInformation
,
3372 LPSECURITY_DESCRIPTOR pSecurityDescriptor
,
3373 LPDWORD lpcbSecurityDescriptor
)
3377 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3378 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3380 lpkey
= lookup_hkey( hkey
);
3382 return ERROR_INVALID_HANDLE
;
3384 /* FIXME: Check for valid SecurityInformation values */
3386 if (*lpcbSecurityDescriptor
< sizeof(*pSecurityDescriptor
))
3387 return ERROR_INSUFFICIENT_BUFFER
;
3389 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3390 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3392 return ERROR_SUCCESS
;
3396 /******************************************************************************
3397 * RegLoadKey32W [ADVAPI32.???]
3400 * hkey [I] Handle of open key
3401 * lpszSubKey [I] Address of name of subkey
3402 * lpszFile [I] Address of filename for registry information
3404 LONG WINAPI
RegLoadKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3407 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3409 /* Do this check before the hkey check */
3410 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3411 return ERROR_INVALID_PARAMETER
;
3413 lpkey
= lookup_hkey( hkey
);
3415 return ERROR_INVALID_HANDLE
;
3417 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3418 debugstr_w(lpszFile
));
3420 return ERROR_SUCCESS
;
3424 /******************************************************************************
3425 * RegLoadKey32A [ADVAPI32.???]
3427 LONG WINAPI
RegLoadKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3430 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3431 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3432 ret
= RegLoadKey32W( hkey
, lpszSubKeyW
, lpszFileW
);
3433 if(lpszFileW
) free(lpszFileW
);
3434 if(lpszSubKeyW
) free(lpszSubKeyW
);
3439 /******************************************************************************
3440 * RegNotifyChangeKeyValue [ADVAPI32.???]
3443 * hkey [I] Handle of key to watch
3444 * fWatchSubTree [I] Flag for subkey notification
3445 * fdwNotifyFilter [I] Changes to be reported
3446 * hEvent [I] Handle of signaled event
3447 * fAsync [I] Flag for asynchronous reporting
3449 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL32 fWatchSubTree
,
3450 DWORD fdwNotifyFilter
, HANDLE32 hEvent
,
3454 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3457 lpkey
= lookup_hkey( hkey
);
3459 return ERROR_INVALID_HANDLE
;
3461 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3464 return ERROR_SUCCESS
;
3468 /******************************************************************************
3469 * RegUnLoadKey32W [ADVAPI32.173]
3472 * hkey [I] Handle of open key
3473 * lpSubKey [I] Address of name of subkey to unload
3475 LONG WINAPI
RegUnLoadKey32W( HKEY hkey
, LPCWSTR lpSubKey
)
3477 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3478 return ERROR_SUCCESS
;
3482 /******************************************************************************
3483 * RegUnLoadKey32A [ADVAPI32.172]
3485 LONG WINAPI
RegUnLoadKey32A( HKEY hkey
, LPCSTR lpSubKey
)
3488 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3489 ret
= RegUnLoadKey32W( hkey
, lpSubKeyW
);
3490 if(lpSubKeyW
) free(lpSubKeyW
);
3495 /******************************************************************************
3496 * RegSetKeySecurity [ADVAPI32.167]
3499 * hkey [I] Open handle of key to set
3500 * SecurityInfo [I] Descriptor contents
3501 * pSecurityDesc [I] Address of descriptor for key
3503 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3504 LPSECURITY_DESCRIPTOR pSecurityDesc
)
3508 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3510 /* It seems to perform this check before the hkey check */
3511 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3512 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3513 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3514 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3517 return ERROR_INVALID_PARAMETER
;
3520 return ERROR_INVALID_PARAMETER
;
3522 lpkey
= lookup_hkey( hkey
);
3524 return ERROR_INVALID_HANDLE
;
3526 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3528 return ERROR_SUCCESS
;
3532 /******************************************************************************
3533 * RegSaveKey32W [ADVAPI32.166]
3536 * hkey [I] Handle of key where save begins
3537 * lpFile [I] Address of filename to save to
3538 * sa [I] Address of security structure
3540 LONG WINAPI
RegSaveKey32W( HKEY hkey
, LPCWSTR lpFile
,
3541 LPSECURITY_ATTRIBUTES sa
)
3545 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3547 /* It appears to do this check before the hkey check */
3548 if (!lpFile
|| !*lpFile
)
3549 return ERROR_INVALID_PARAMETER
;
3551 lpkey
= lookup_hkey( hkey
);
3553 return ERROR_INVALID_HANDLE
;
3555 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3557 return ERROR_SUCCESS
;
3561 /******************************************************************************
3562 * RegSaveKey32A [ADVAPI32.165]
3564 LONG WINAPI
RegSaveKey32A( HKEY hkey
, LPCSTR lpFile
,
3565 LPSECURITY_ATTRIBUTES sa
)
3568 LPWSTR lpFileW
= strdupA2W(lpFile
);
3569 ret
= RegSaveKey32W( hkey
, lpFileW
, sa
);
3575 /******************************************************************************
3576 * RegRestoreKey32W [ADVAPI32.164]
3579 * hkey [I] Handle of key where restore begins
3580 * lpFile [I] Address of filename containing saved tree
3581 * dwFlags [I] Optional flags
3583 LONG WINAPI
RegRestoreKey32W( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3587 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3589 /* It seems to do this check before the hkey check */
3590 if (!lpFile
|| !*lpFile
)
3591 return ERROR_INVALID_PARAMETER
;
3593 lpkey
= lookup_hkey( hkey
);
3595 return ERROR_INVALID_HANDLE
;
3597 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3599 /* Check for file existence */
3601 return ERROR_SUCCESS
;
3605 /******************************************************************************
3606 * RegRestoreKey32A [ADVAPI32.163]
3608 LONG WINAPI
RegRestoreKey32A( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3611 LPWSTR lpFileW
= strdupA2W(lpFile
);
3612 ret
= RegRestoreKey32W( hkey
, lpFileW
, dwFlags
);
3613 if(lpFileW
) free(lpFileW
);
3618 /******************************************************************************
3619 * RegReplaceKey32W [ADVAPI32.162]
3622 * hkey [I] Handle of open key
3623 * lpSubKey [I] Address of name of subkey
3624 * lpNewFile [I] Address of filename for file with new data
3625 * lpOldFile [I] Address of filename for backup file
3627 LONG WINAPI
RegReplaceKey32W( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3632 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3633 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3635 lpkey
= lookup_hkey( hkey
);
3637 return ERROR_INVALID_HANDLE
;
3639 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3640 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3642 return ERROR_SUCCESS
;
3646 /******************************************************************************
3647 * RegReplaceKey32A [ADVAPI32.161]
3649 LONG WINAPI
RegReplaceKey32A( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3653 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3654 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3655 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3656 ret
= RegReplaceKey32W( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);