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>
42 static void REGISTRY_Init();
43 /* FIXME: following defines should be configured global ... */
45 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
46 #define WINE_PREFIX "/.wine"
47 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
48 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
50 /* relative in ~user/.wine/ : */
51 #define SAVE_CURRENT_USER "user.reg"
52 #define SAVE_LOCAL_MACHINE "system.reg"
54 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
55 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57 /* one value of a key */
58 typedef struct tagKEYVALUE
60 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
61 DWORD type
; /* type of value */
62 DWORD len
; /* length of data in BYTEs */
63 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
64 LPBYTE data
; /* content, may be strings, binaries, etc. */
65 } KEYVALUE
,*LPKEYVALUE
;
68 typedef struct tagKEYSTRUCT
70 LPWSTR keyname
; /* name of THIS key (UNICODE) */
71 DWORD flags
; /* flags. */
74 DWORD nrofvalues
; /* nr of values in THIS key */
75 LPKEYVALUE values
; /* values in THIS key */
76 /* key management pointers */
77 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
78 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
79 } KEYSTRUCT
, *LPKEYSTRUCT
;
82 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
83 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
84 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
85 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
87 /* dynamic, not saved */
88 static KEYSTRUCT
*key_performance_data
=NULL
;
89 static KEYSTRUCT
*key_current_config
=NULL
;
90 static KEYSTRUCT
*key_dyn_data
=NULL
;
92 /* what valuetypes do we need to convert? */
93 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
96 static struct openhandle
{
101 static int nrofopenhandles
=0;
102 /* Starts after 1 because 0,1 are reserved for Win16 */
103 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
104 HKEYs for remote registry access */
105 static int currenthandle
=2;
110 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
111 * If so, can we remove them?
113 * No, the memory handling functions are called very often in here,
114 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
115 * loading 100 times slower. -MM
117 static LPWSTR
strdupA2W(LPCSTR src
)
120 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
121 lstrcpyAtoW(dest
,src
);
127 static LPWSTR
strdupW(LPCWSTR a
) {
132 len
=sizeof(WCHAR
)*(lstrlen32W(a
)+1);
133 b
=(LPWSTR
)xmalloc(len
);
140 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
143 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
145 lstrcpynAtoW(dest
,src
,nchars
+1);
151 /******************************************************************************
152 * is_standard_hkey [Internal]
153 * Determines if a hkey is a standard key
155 static BOOL32
is_standard_hkey( HKEY hkey
)
160 case HKEY_CLASSES_ROOT
:
161 case HKEY_CURRENT_CONFIG
:
162 case HKEY_CURRENT_USER
:
163 case HKEY_LOCAL_MACHINE
:
165 case HKEY_PERFORMANCE_DATA
:
173 /******************************************************************************
174 * add_handle [Internal]
176 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
180 TRACE(reg
,"(%x,%p,%lx)\n",hkey
,lpkey
,accessmask
);
181 /* Check for duplicates */
182 for (i
=0;i
<nrofopenhandles
;i
++) {
183 if (openhandles
[i
].lpkey
==lpkey
) {
184 /* This is not really an error - the user is allowed to create
185 two (or more) handles to the same key */
186 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
188 if (openhandles
[i
].hkey
==hkey
) {
189 WARN(reg
, "Adding handle %x twice\n",hkey
);
192 openhandles
=xrealloc( openhandles
,
193 sizeof(struct openhandle
)*(nrofopenhandles
+1));
195 openhandles
[i
].lpkey
= lpkey
;
196 openhandles
[i
].hkey
= hkey
;
197 openhandles
[i
].accessmask
= accessmask
;
202 /******************************************************************************
203 * get_handle [Internal]
206 * Success: Pointer to key
209 static LPKEYSTRUCT
get_handle( HKEY hkey
)
213 for (i
=0; i
<nrofopenhandles
; i
++)
214 if (openhandles
[i
].hkey
== hkey
)
215 return openhandles
[i
].lpkey
;
216 WARN(reg
, "Could not find handle %x\n",hkey
);
221 /******************************************************************************
222 * remove_handle [Internal]
225 * hkey [I] Handle of key to remove
228 * Success: ERROR_SUCCESS
229 * Failure: ERROR_INVALID_HANDLE
231 static DWORD
remove_handle( HKEY hkey
)
235 for (i
=0;i
<nrofopenhandles
;i
++)
236 if (openhandles
[i
].hkey
==hkey
)
239 if (i
== nrofopenhandles
) {
240 WARN(reg
, "Could not find handle %x\n",hkey
);
241 return ERROR_INVALID_HANDLE
;
244 memcpy( openhandles
+i
,
246 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
248 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
250 return ERROR_SUCCESS
;
253 /******************************************************************************
254 * lookup_hkey [Internal]
256 * Just as the name says. Creates the root keys on demand, so we can call the
257 * Reg* functions at any time.
260 * Success: Pointer to key structure
263 #define ADD_ROOT_KEY(xx) \
264 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
265 memset(xx,'\0',sizeof(KEYSTRUCT));\
266 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
268 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
271 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
272 * some programs. Do not remove those cases. -MM
276 case HKEY_CLASSES_ROOT
: {
277 if (!key_classes_root
) {
280 /* calls lookup_hkey recursively, TWICE */
281 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
282 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
285 key_classes_root
= lookup_hkey(cl_r_hkey
);
287 return key_classes_root
;
289 case HKEY_CURRENT_USER
:
290 if (!key_current_user
) {
294 pwd
=getpwuid(getuid());
295 /* calls lookup_hkey recursively, TWICE */
296 if (pwd
&& pwd
->pw_name
) {
297 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
298 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
301 key_current_user
= lookup_hkey(c_u_hkey
);
303 /* nothing found, use standalone */
304 ADD_ROOT_KEY(key_current_user
);
307 return key_current_user
;
308 case HKEY_LOCAL_MACHINE
:
309 if (!key_local_machine
) {
310 ADD_ROOT_KEY(key_local_machine
);
313 return key_local_machine
;
316 ADD_ROOT_KEY(key_users
);
319 case HKEY_PERFORMANCE_DATA
:
320 if (!key_performance_data
) {
321 ADD_ROOT_KEY(key_performance_data
);
323 return key_performance_data
;
326 ADD_ROOT_KEY(key_dyn_data
);
329 case HKEY_CURRENT_CONFIG
:
330 if (!key_current_config
) {
331 ADD_ROOT_KEY(key_current_config
);
333 return key_current_config
;
335 return get_handle(hkey
);
340 /* so we don't accidently access them ... */
341 #define key_current_config NULL NULL
342 #define key_current_user NULL NULL
343 #define key_users NULL NULL
344 #define key_local_machine NULL NULL
345 #define key_classes_root NULL NULL
346 #define key_dyn_data NULL NULL
347 #define key_performance_data NULL NULL
349 /******************************************************************************
350 * split_keypath [Internal]
351 * splits the unicode string 'wp' into an array of strings.
352 * the array is allocated by this function.
353 * Free the array using FREE_KEY_PATH
356 * wp [I] String to split up
357 * wpv [O] Array of pointers to strings
358 * wpc [O] Number of components
360 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
365 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
367 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
369 /* We know we have at least one substring */
372 /* Replace each backslash with NULL, and increment the count */
373 for (i
=0;ws
[i
];i
++) {
382 /* Allocate the space for the array of pointers, leaving room for the
384 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
387 /* Assign each pointer to the appropriate character in the string */
392 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
397 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
402 /******************************************************************************
403 * REGISTRY_Init [Internal]
404 * Registry initialisation, allocates some default keys.
406 static void REGISTRY_Init() {
410 TRACE(reg
,"(void)\n");
412 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
415 /* This was an Open, but since it is called before the real registries
416 are loaded, it was changed to a Create - MTB 980507*/
417 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
418 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
421 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
425 * string RegisteredOwner
426 * string RegisteredOrganization
429 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
434 if (-1!=gethostname(buf
,200)) {
435 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
436 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
442 /************************ SAVE Registry Function ****************************/
444 #define REGISTRY_SAVE_VERSION 0x00000001
446 /* Registry saveformat:
447 * If you change it, increase above number by 1, which will flush
448 * old registry database files.
451 * "WINE REGISTRY Version %d"
455 * valuename=lastmodified,type,data
459 * keyname,valuename,stringdata:
460 * the usual ascii characters from 0x00-0xff (well, not 0x00)
461 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
462 * ( "=\\\t" escaped in \uXXXX form.)
466 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
468 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
469 * SaveOnlyUpdatedKeys=yes
472 /******************************************************************************
473 * _save_check_tainted [Internal]
475 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
481 if (lpkey
->flags
& REG_OPTION_TAINTED
)
486 if (_save_check_tainted(lpkey
->nextsub
)) {
487 lpkey
->flags
|= REG_OPTION_TAINTED
;
495 /******************************************************************************
496 * _save_USTRING [Internal]
498 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
512 if (escapeeq
&& *s
=='=')
515 fputc(*s
,F
); /* if \\ then put it twice. */
517 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
524 /******************************************************************************
525 * _savesubkey [Internal]
527 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
534 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
535 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
537 for (tabs
=level
;tabs
--;)
539 _save_USTRING(F
,lpxkey
->keyname
,1);
541 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
542 LPKEYVALUE val
=lpxkey
->values
+i
;
544 for (tabs
=level
+1;tabs
--;)
546 _save_USTRING(F
,val
->name
,0);
548 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
549 if ((1<<val
->type
) & UNICONVMASK
)
550 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
552 for (j
=0;j
<val
->len
;j
++)
553 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
556 /* descend recursively */
557 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
566 /******************************************************************************
567 * _savesubreg [Internal]
569 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
571 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
572 _save_check_tainted(lpkey
->nextsub
);
573 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
577 /******************************************************************************
578 * _savereg [Internal]
580 static BOOL32
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
586 WARN(reg
,"Couldn't open %s for writing: %s\n",
591 if (!_savesubreg(F
,lpkey
,all
)) {
594 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
602 /******************************************************************************
603 * SHELL_SaveRegistry [Internal]
605 void SHELL_SaveRegistry( void )
613 TRACE(reg
,"(void)\n");
616 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
622 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
634 if (lstrcmpi32A(buf
,"yes"))
636 pwd
=getpwuid(getuid());
637 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
641 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
642 strlen(SAVE_CURRENT_USER
) + 2 );
643 strcpy(fn
,pwd
->pw_dir
);
644 strcat(fn
,WINE_PREFIX
);
645 /* create the directory. don't care about errorcodes. */
646 mkdir(fn
,0755); /* drwxr-xr-x */
647 strcat(fn
,"/"SAVE_CURRENT_USER
);
648 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
649 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
650 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
651 if (-1==rename(tmp
,fn
)) {
652 perror("rename tmp registry");
658 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
659 strcpy(fn
,pwd
->pw_dir
);
660 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
661 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
662 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
663 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
664 if (-1==rename(tmp
,fn
)) {
665 perror("rename tmp registry");
672 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
676 /************************ LOAD Registry Function ****************************/
680 /******************************************************************************
681 * _find_or_add_key [Internal]
683 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
685 LPKEYSTRUCT lpxkey
,*lplpkey
;
687 if ((!keyname
) || (keyname
[0]==0)) {
691 lplpkey
= &(lpkey
->nextsub
);
694 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
695 !lstrcmpi32W(lpxkey
->keyname
,keyname
)
698 lplpkey
= &(lpxkey
->next
);
702 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
704 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
705 lpxkey
->keyname
= keyname
;
711 /******************************************************************************
712 * _find_or_add_value [Internal]
714 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
715 LPBYTE data
, DWORD len
, DWORD lastmodified
)
720 if (name
&& !*name
) {/* empty string equals default (NULL) value */
725 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
731 if ( val
->name
!=NULL
&&
732 val
->name
[0]==name
[0] &&
733 !lstrcmpi32W(val
->name
,name
)
738 if (i
==lpkey
->nrofvalues
) {
739 lpkey
->values
= xrealloc(
741 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
744 memset(val
,'\0',sizeof(KEYVALUE
));
750 if (val
->lastmodified
<lastmodified
) {
751 val
->lastmodified
=lastmodified
;
762 /******************************************************************************
763 * _wine_read_line [Internal]
765 * reads a line including dynamically enlarging the readbuffer and throwing
768 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
778 s
=fgets(curread
,mylen
,F
);
781 if (NULL
==(s
=strchr(curread
,'\n'))) {
782 /* buffer wasn't large enough */
783 curoff
= strlen(*buf
);
784 *buf
= xrealloc(*buf
,*len
*2);
785 curread
= *buf
+ curoff
;
786 mylen
= *len
; /* we filled up the buffer and
787 * got new '*len' bytes to fill
795 /* throw away comments */
796 if (**buf
=='#' || **buf
==';') {
801 if (s
) /* got end of line */
808 /******************************************************************************
809 * _wine_read_USTRING [Internal]
811 * converts a char* into a UNICODE string (up to a special char)
812 * and returns the position exactly after that string
814 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
819 /* read up to "=" or "\0" or "\n" */
822 /* empty string is the win3.1 default value(NULL)*/
826 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
828 while (*s
&& (*s
!='\n') && (*s
!='=')) {
830 *ws
++=*((unsigned char*)s
++);
839 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
847 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
848 if (!sscanf(xbuf
,"%x",&wc
))
849 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
851 *ws
++ =(unsigned short)wc
;
858 *str
= strdupW(*str
);
866 /******************************************************************************
867 * _wine_loadsubkey [Internal]
870 * It seems like this is returning a boolean. Should it?
876 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
877 int *buflen
, DWORD optflag
)
884 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
887 lpkey
->flags
|= optflag
;
889 /* Good. We already got a line here ... so parse it */
899 WARN(reg
,"Got a subhierarchy without resp. key?\n");
902 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
906 /* let the caller handle this line */
907 if (i
<level
|| **buf
=='\0')
910 /* it can be: a value or a keyname. Parse the name first */
911 s
=_wine_read_USTRING(s
,&name
);
913 /* switch() default: hack to avoid gotos */
917 lpxkey
=_find_or_add_key(lpkey
,name
);
920 int len
,lastmodified
,type
;
923 WARN(reg
,"Unexpected character: %c\n",*s
);
927 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
928 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
934 if ((1<<type
) & UNICONVMASK
) {
935 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
937 len
= lstrlen32W((LPWSTR
)data
)*2+2;
942 data
= (LPBYTE
)xmalloc(len
+1);
943 for (i
=0;i
<len
;i
++) {
945 if (*s
>='0' && *s
<='9')
947 if (*s
>='a' && *s
<='f')
948 data
[i
]=(*s
-'a'+'\xa')<<4;
949 if (*s
>='A' && *s
<='F')
950 data
[i
]=(*s
-'A'+'\xa')<<4;
952 if (*s
>='0' && *s
<='9')
954 if (*s
>='a' && *s
<='f')
955 data
[i
]|=*s
-'a'+'\xa';
956 if (*s
>='A' && *s
<='F')
957 data
[i
]|=*s
-'A'+'\xa';
961 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
964 /* read the next line */
965 if (!_wine_read_line(F
,buf
,buflen
))
972 /******************************************************************************
973 * _wine_loadsubreg [Internal]
975 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
981 buf
=xmalloc(10);buflen
=10;
982 if (!_wine_read_line(F
,&buf
,&buflen
)) {
986 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
990 if (ver
!=REGISTRY_SAVE_VERSION
) {
991 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
995 if (!_wine_read_line(F
,&buf
,&buflen
)) {
999 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1008 /******************************************************************************
1009 * _wine_loadreg [Internal]
1011 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1015 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1019 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1022 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1031 /******************************************************************************
1032 * _copy_registry [Internal]
1034 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1042 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1044 for (j
=0;j
<from
->nrofvalues
;j
++) {
1048 valfrom
= from
->values
+j
;
1050 if (name
) name
=strdupW(name
);
1051 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1052 memcpy(data
,valfrom
->data
,valfrom
->len
);
1060 valfrom
->lastmodified
1063 _copy_registry(from
,lpxkey
);
1069 /* WINDOWS 95 REGISTRY LOADER */
1071 * Structure of a win95 registry database.
1073 * 0 : "CREG" - magic
1075 * 8 : DWORD offset_of_RGDB_part
1076 * 0C..0F: ? (someone fill in please)
1077 * 10: WORD number of RGDB blocks
1079 * 14: WORD always 0000?
1080 * 16: WORD always 0001?
1081 * 18..1F: ? (someone fill in please)
1085 * 0 : "RGKN" - magic
1086 * 4 : DWORD offset to first RGDB section
1087 * 8 : DWORD offset to the root record
1088 * C..0x1B: ? (fill in)
1089 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1091 * Disk Key Entry Structure:
1092 * 00: DWORD - Free entry indicator(?)
1093 * 04: DWORD - Hash = sum of bytes of keyname
1094 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1095 * 0C: DWORD - disk address of PreviousLevel Key.
1096 * 10: DWORD - disk address of Next Sublevel Key.
1097 * 14: DWORD - disk address of Next Key (on same level).
1098 * DKEP>18: WORD - Nr, Low Significant part.
1099 * 1A: WORD - Nr, High Significant part.
1101 * The disk address always points to the nr part of the previous key entry
1102 * of the referenced key. Don't ask me why, or even if I got this correct
1103 * from staring at 1kg of hexdumps. (DKEP)
1105 * The High significant part of the structure seems to equal the number
1106 * of the RGDB section. The low significant part is a unique ID within
1109 * There are two minor corrections to the position of that structure.
1110 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1111 * the DKE reread from there.
1112 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1113 * CPS - I have not experienced the above phenomenon in my registry files
1116 * 00: "RGDB" - magic
1117 * 04: DWORD offset to next RGDB section
1119 * 0C: WORD always 000d?
1120 * 0E: WORD RGDB block number
1121 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1123 * 20.....: disk keys
1126 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1127 * 08: WORD nrLS - low significant part of NR
1128 * 0A: WORD nrHS - high significant part of NR
1129 * 0C: DWORD bytesused - bytes used in this structure.
1130 * 10: WORD name_len - length of name in bytes. without \0
1131 * 12: WORD nr_of_values - number of values.
1132 * 14: char name[name_len] - name string. No \0.
1133 * 14+name_len: disk values
1134 * nextkeyoffset: ... next disk key
1137 * 00: DWORD type - value type (hmm, could be WORD too)
1138 * 04: DWORD - unknown, usually 0
1139 * 08: WORD namelen - length of Name. 0 means name=NULL
1140 * 0C: WORD datalen - length of Data.
1141 * 10: char name[namelen] - name, no \0
1142 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1143 * 10+namelen+datalen: next values or disk key
1145 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1146 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1147 * structure) and reading another RGDB_section.
1148 * repeat until end of file.
1150 * An interesting relationship exists in RGDB_section. The value at offset
1151 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1152 * idea at the moment what this means. (Kevin Cozens)
1154 * FIXME: this description needs some serious help, yes.
1157 struct _w95keyvalue
{
1159 unsigned short datalen
;
1161 unsigned char *data
;
1169 struct _w95keyvalue
*values
;
1170 struct _w95key
*prevlvl
;
1171 struct _w95key
*nextsub
;
1172 struct _w95key
*next
;
1186 /******************************************************************************
1187 * _w95_processKey [Internal]
1189 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1190 int nrLS
, int nrMS
, struct _w95_info
*info
)
1193 /* Disk Key Header structure (RGDB part) */
1195 unsigned long nextkeyoff
;
1196 unsigned short nrLS
;
1197 unsigned short nrMS
;
1198 unsigned long bytesused
;
1199 unsigned short keynamelen
;
1200 unsigned short values
;
1203 /* disk key values or nothing */
1205 /* Disk Key Value structure */
1209 unsigned short valnamelen
;
1210 unsigned short valdatalen
;
1211 /* valname, valdata */
1217 char *rgdbdata
= info
->rgdbbuffer
;
1218 int nbytes
= info
->rgdbsize
;
1219 char *curdata
= rgdbdata
;
1220 char *end
= rgdbdata
+ nbytes
;
1222 char *next
= rgdbdata
;
1228 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1230 memcpy(&off_next_rgdb
,curdata
+4,4);
1231 next
= curdata
+ off_next_rgdb
;
1232 nrgdb
= (int) *((short *)curdata
+ 7);
1234 } while (nrgdb
!= nrMS
&& (next
< end
));
1236 /* curdata now points to the start of the right RGDB section */
1239 #define XREAD(whereto,len) \
1240 if ((curdata + len) <end) {\
1241 memcpy(whereto,curdata,len);\
1246 while (curdata
< next
) {
1247 struct dkh
*xdkh
= curdata
;
1249 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1250 if (xdkh
->nrLS
== nrLS
) {
1251 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1252 curdata
+= sizeof(dkh
);
1255 curdata
+= xdkh
->nextkeyoff
;
1258 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1260 if (nrgdb
!= dkh
.nrMS
)
1263 assert((dkh
.keynamelen
<2) || curdata
[0]);
1264 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1265 curdata
+= dkh
.keynamelen
;
1267 for (i
=0;i
< dkh
.values
; i
++) {
1273 XREAD(&dkv
,sizeof(dkv
));
1275 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1276 curdata
+= dkv
.valnamelen
;
1278 if ((1 << dkv
.type
) & UNICONVMASK
) {
1279 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1280 len
= 2*(dkv
.valdatalen
+ 1);
1282 /* I don't think we want to NULL terminate all data */
1283 data
= xmalloc(dkv
.valdatalen
);
1284 memcpy (data
, curdata
, dkv
.valdatalen
);
1285 len
= dkv
.valdatalen
;
1288 curdata
+= dkv
.valdatalen
;
1302 /******************************************************************************
1303 * _w95_walkrgkn [Internal]
1305 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1306 struct _w95_info
*info
)
1309 /* Disk Key Entry structure (RGKN part) */
1313 unsigned long x3
;/*usually 0xFFFFFFFF */
1314 unsigned long prevlvl
;
1315 unsigned long nextsub
;
1317 unsigned short nrLS
;
1318 unsigned short nrMS
;
1319 } *dke
= (struct dke
*)off
;
1323 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1326 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1327 /* XXX <-- This is a hack*/
1332 if (dke
->nextsub
!= -1 &&
1333 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1334 && (dke
->nextsub
> 0x20)) {
1336 _w95_walkrgkn(lpxkey
,
1337 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1341 if (dke
->next
!= -1 &&
1342 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1343 (dke
->next
> 0x20)) {
1344 _w95_walkrgkn(prevkey
,
1345 info
->rgknbuffer
+ dke
->next
- 0x20,
1353 /******************************************************************************
1354 * _w95_loadreg [Internal]
1356 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1360 unsigned long where
,version
,rgdbsection
,end
;
1361 struct _w95_info info
;
1363 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1365 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1366 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1367 if (hfd
==HFILE_ERROR32
)
1370 if (4!=_lread32(hfd
,magic
,4))
1372 if (strcmp(magic
,"CREG")) {
1373 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1376 if (4!=_lread32(hfd
,&version
,4))
1378 if (4!=_lread32(hfd
,&rgdbsection
,4))
1380 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1382 if (4!=_lread32(hfd
,magic
,4))
1384 if (strcmp(magic
,"RGKN")) {
1385 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1389 /* STEP 1: Keylink structures */
1390 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1395 info
.rgknsize
= end
- where
;
1396 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1397 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1400 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1403 end
= hfdinfo
.nFileSizeLow
;
1404 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1406 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1409 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1410 info
.rgdbsize
= end
- rgdbsection
;
1412 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1416 _w95_walkrgkn(lpkey
, NULL
, &info
);
1418 free (info
.rgdbbuffer
);
1419 free (info
.rgknbuffer
);
1423 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1426 reghack - windows 3.11 registry data format demo program.
1428 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1429 a combined hash table and tree description, and finally a text table.
1431 The header is obvious from the struct header. The taboff1 and taboff2
1432 fields are always 0x20, and their usage is unknown.
1434 The 8-byte entry table has various entry types.
1436 tabent[0] is a root index. The second word has the index of the root of
1438 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1439 the index of the key/value that has that hash. Data with the same
1440 hash value are on a circular list. The other three words in the
1441 hash entry are always zero.
1442 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1443 entry: dirent and keyent/valent. They are identified by context.
1444 tabent[freeidx] is the first free entry. The first word in a free entry
1445 is the index of the next free entry. The last has 0 as a link.
1446 The other three words in the free list are probably irrelevant.
1448 Entries in text table are preceeded by a word at offset-2. This word
1449 has the value (2*index)+1, where index is the referring keyent/valent
1450 entry in the table. I have no suggestion for the 2* and the +1.
1451 Following the word, there are N bytes of data, as per the keyent/valent
1452 entry length. The offset of the keyent/valent entry is from the start
1453 of the text table to the first data byte.
1455 This information is not available from Microsoft. The data format is
1456 deduced from the reg.dat file by me. Mistakes may
1457 have been made. I claim no rights and give no guarantees for this program.
1459 Tor Sjøwall, tor@sn.no
1462 /* reg.dat header format */
1463 struct _w31_header
{
1464 char cookie
[8]; /* 'SHCC3.10' */
1465 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1466 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1467 unsigned long tabcnt
; /* number of entries in index table */
1468 unsigned long textoff
; /* offset of text part */
1469 unsigned long textsize
; /* byte size of text part */
1470 unsigned short hashsize
; /* hash size */
1471 unsigned short freeidx
; /* free index */
1474 /* generic format of table entries */
1475 struct _w31_tabent
{
1476 unsigned short w0
, w1
, w2
, w3
;
1479 /* directory tabent: */
1480 struct _w31_dirent
{
1481 unsigned short sibling_idx
; /* table index of sibling dirent */
1482 unsigned short child_idx
; /* table index of child dirent */
1483 unsigned short key_idx
; /* table index of key keyent */
1484 unsigned short value_idx
; /* table index of value valent */
1488 struct _w31_keyent
{
1489 unsigned short hash_idx
; /* hash chain index for string */
1490 unsigned short refcnt
; /* reference count */
1491 unsigned short length
; /* length of string */
1492 unsigned short string_off
; /* offset of string in text table */
1496 struct _w31_valent
{
1497 unsigned short hash_idx
; /* hash chain index for string */
1498 unsigned short refcnt
; /* reference count */
1499 unsigned short length
; /* length of string */
1500 unsigned short string_off
; /* offset of string in text table */
1503 /* recursive helper function to display a directory tree */
1505 __w31_dumptree( unsigned short idx
,
1507 struct _w31_tabent
*tab
,
1508 struct _w31_header
*head
,
1510 time_t lastmodified
,
1513 struct _w31_dirent
*dir
;
1514 struct _w31_keyent
*key
;
1515 struct _w31_valent
*val
;
1516 LPKEYSTRUCT xlpkey
= NULL
;
1518 static char tail
[400];
1521 dir
=(struct _w31_dirent
*)&tab
[idx
];
1524 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1526 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1527 tail
[key
->length
]='\0';
1528 /* all toplevel entries AND the entries in the
1529 * toplevel subdirectory belong to \SOFTWARE\Classes
1531 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1532 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1533 idx
=dir
->sibling_idx
;
1536 name
=strdupA2W(tail
);
1538 xlpkey
=_find_or_add_key(lpkey
,name
);
1540 /* only add if leaf node or valued node */
1541 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1542 if (dir
->value_idx
) {
1543 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1544 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1545 tail
[val
->length
]='\0';
1546 value
=strdupA2W(tail
);
1547 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1551 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1553 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1554 idx
=dir
->sibling_idx
;
1559 /******************************************************************************
1560 * _w31_loadreg [Internal]
1562 void _w31_loadreg() {
1564 struct _w31_header head
;
1565 struct _w31_tabent
*tab
;
1569 BY_HANDLE_FILE_INFORMATION hfinfo
;
1570 time_t lastmodified
;
1573 TRACE(reg
,"(void)\n");
1575 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1576 if (hf
==HFILE_ERROR32
)
1579 /* read & dump header */
1580 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1581 ERR(reg
, "reg.dat is too short.\n");
1585 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1586 ERR(reg
, "reg.dat has bad signature.\n");
1591 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1592 /* read and dump index table */
1594 if (len
!=_lread32(hf
,tab
,len
)) {
1595 ERR(reg
,"couldn't read %d bytes.\n",len
);
1602 txt
= xmalloc(head
.textsize
);
1603 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1604 ERR(reg
,"couldn't seek to textblock.\n");
1610 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1611 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1618 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1619 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1625 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1626 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1627 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1635 /**********************************************************************************
1636 * SHELL_LoadRegistry [Internal]
1638 void SHELL_LoadRegistry( void )
1645 TRACE(reg
,"(void)\n");
1647 /* Load windows 3.1 entries */
1649 /* Load windows 95 entries */
1650 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1651 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1652 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1654 /* the global user default is loaded under HKEY_USERS\\.Default */
1655 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1656 lpkey
= lookup_hkey(hkey
);
1658 WARN(reg
,"Could not create global user default key\n");
1659 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1661 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1662 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1665 /* the global machine defaults */
1666 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1668 /* load the user saved registries */
1670 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1672 pwd
=getpwuid(getuid());
1673 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1674 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1675 strcpy(fn
,pwd
->pw_dir
);
1676 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1677 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1679 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1680 strcpy(fn
,pwd
->pw_dir
);
1681 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1682 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1685 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1686 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1687 DWORD junk
,type
,len
;
1691 if (( RegQueryValueEx32A(
1698 )!=ERROR_SUCCESS
) ||
1701 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1707 /********************* API FUNCTIONS ***************************************/
1711 * All functions are stubs to RegOpenKeyEx32W where all the
1715 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1716 * RegOpenKey32W -> RegOpenKeyEx32W
1720 /******************************************************************************
1721 * RegOpenKeyEx32W [ADVAPI32.150]
1722 * Opens the specified key
1724 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1727 * hkey [I] Handle of open key
1728 * lpszSubKey [I] Name of subkey to open
1729 * dwReserved [I] Reserved - must be zero
1730 * samDesired [I] Security access mask
1731 * retkey [O] Address of handle of open key
1734 * Success: ERROR_SUCCESS
1735 * Failure: Error code
1737 DWORD WINAPI
RegOpenKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1738 REGSAM samDesired
, LPHKEY retkey
)
1740 LPKEYSTRUCT lpNextKey
,lpxkey
;
1744 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1747 lpNextKey
= lookup_hkey( hkey
);
1749 return ERROR_INVALID_HANDLE
;
1751 if (!lpszSubKey
|| !*lpszSubKey
) {
1752 /* Either NULL or pointer to empty string, so return a new handle
1753 to the original hkey */
1755 add_handle(currenthandle
,lpNextKey
,samDesired
);
1756 *retkey
=currenthandle
;
1757 return ERROR_SUCCESS
;
1760 if (lpszSubKey
[0] == '\\') {
1761 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1762 return ERROR_BAD_PATHNAME
;
1765 split_keypath(lpszSubKey
,&wps
,&wpc
);
1767 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1771 lpxkey
=lpNextKey
->nextsub
;
1773 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
)) {
1776 lpxkey
=lpxkey
->next
;
1780 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1782 return ERROR_FILE_NOT_FOUND
;
1789 add_handle(currenthandle
,lpxkey
,samDesired
);
1790 *retkey
= currenthandle
;
1791 TRACE(reg
," Returning %x\n", currenthandle
);
1793 return ERROR_SUCCESS
;
1797 /******************************************************************************
1798 * RegOpenKeyEx32A [ADVAPI32.149]
1800 DWORD WINAPI
RegOpenKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1801 REGSAM samDesired
, LPHKEY retkey
)
1803 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1806 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1808 ret
= RegOpenKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
1814 /******************************************************************************
1815 * RegOpenKey32W [ADVAPI32.151]
1818 * hkey [I] Handle of open key
1819 * lpszSubKey [I] Address of name of subkey to open
1820 * retkey [O] Address of handle of open key
1823 * Success: ERROR_SUCCESS
1824 * Failure: Error code
1826 DWORD WINAPI
RegOpenKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1828 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1829 return RegOpenKeyEx32W( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
1833 /******************************************************************************
1834 * RegOpenKey32A [ADVAPI32.148]
1836 DWORD WINAPI
RegOpenKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1839 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
1840 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1841 ret
= RegOpenKey32W( hkey
, lpszSubKeyW
, retkey
);
1847 /******************************************************************************
1848 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1850 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1852 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1853 return RegOpenKey32A( hkey
, lpszSubKey
, retkey
);
1860 * All those functions convert their respective
1861 * arguments and call RegCreateKeyExW at the end.
1863 * We stay away from the Ex functions as long as possible because there are
1864 * differences in the return values
1867 * RegCreateKeyEx32A \
1868 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1872 /******************************************************************************
1873 * RegCreateKeyEx32W [ADVAPI32.131]
1876 * hkey [I] Handle of an open key
1877 * lpszSubKey [I] Address of subkey name
1878 * dwReserved [I] Reserved - must be 0
1879 * lpszClass [I] Address of class string
1880 * fdwOptions [I] Special options flag
1881 * samDesired [I] Desired security access
1882 * lpSecAttribs [I] Address of key security structure
1883 * retkey [O] Address of buffer for opened handle
1884 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1886 DWORD WINAPI
RegCreateKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
,
1887 DWORD dwReserved
, LPWSTR lpszClass
,
1888 DWORD fdwOptions
, REGSAM samDesired
,
1889 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1890 LPHKEY retkey
, LPDWORD lpDispos
)
1892 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1896 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
1897 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
1898 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
1900 lpNextKey
= lookup_hkey(hkey
);
1902 return ERROR_INVALID_HANDLE
;
1904 /* Check for valid options */
1905 switch(fdwOptions
) {
1906 case REG_OPTION_NON_VOLATILE
:
1907 case REG_OPTION_VOLATILE
:
1908 case REG_OPTION_BACKUP_RESTORE
:
1911 return ERROR_INVALID_PARAMETER
;
1914 /* Sam has to be a combination of the following */
1916 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
1917 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
1918 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
1919 return ERROR_INVALID_PARAMETER
;
1921 if (!lpszSubKey
|| !*lpszSubKey
) {
1923 add_handle(currenthandle
,lpNextKey
,samDesired
);
1924 *retkey
=currenthandle
;
1925 TRACE(reg
, "Returning %x\n", currenthandle
);
1926 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1927 return ERROR_SUCCESS
;
1930 if (lpszSubKey
[0] == '\\') {
1931 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1932 return ERROR_BAD_PATHNAME
;
1935 split_keypath(lpszSubKey
,&wps
,&wpc
);
1937 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1940 lpxkey
=lpNextKey
->nextsub
;
1942 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1944 lpxkey
=lpxkey
->next
;
1953 add_handle(currenthandle
,lpxkey
,samDesired
);
1954 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1955 *retkey
= currenthandle
;
1956 TRACE(reg
, "Returning %x\n", currenthandle
);
1958 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1960 return ERROR_SUCCESS
;
1963 /* Good. Now the hard part */
1965 lplpPrevKey
= &(lpNextKey
->nextsub
);
1966 lpxkey
= *lplpPrevKey
;
1968 lplpPrevKey
= &(lpxkey
->next
);
1969 lpxkey
= *lplpPrevKey
;
1971 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1972 if (!*lplpPrevKey
) {
1974 TRACE(reg
, "Returning OUTOFMEMORY\n");
1975 return ERROR_OUTOFMEMORY
;
1977 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1978 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
1979 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1980 (*lplpPrevKey
)->next
= NULL
;
1981 (*lplpPrevKey
)->nextsub
= NULL
;
1982 (*lplpPrevKey
)->values
= NULL
;
1983 (*lplpPrevKey
)->nrofvalues
= 0;
1984 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1986 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1988 (*lplpPrevKey
)->class = NULL
;
1989 lpNextKey
= *lplpPrevKey
;
1993 add_handle(currenthandle
,lpNextKey
,samDesired
);
1995 /*FIXME: flag handling correct? */
1996 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1998 lpNextKey
->class = strdupW(lpszClass
);
2000 lpNextKey
->class = NULL
;
2001 *retkey
= currenthandle
;
2002 TRACE(reg
, "Returning %x\n", currenthandle
);
2004 *lpDispos
= REG_CREATED_NEW_KEY
;
2006 return ERROR_SUCCESS
;
2010 /******************************************************************************
2011 * RegCreateKeyEx32A [ADVAPI32.130]
2013 DWORD WINAPI
RegCreateKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2014 LPSTR lpszClass
, DWORD fdwOptions
,
2016 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2017 LPHKEY retkey
, LPDWORD lpDispos
)
2019 LPWSTR lpszSubKeyW
, lpszClassW
;
2022 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2023 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2026 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2027 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2029 ret
= RegCreateKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2030 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2033 if(lpszSubKeyW
) free(lpszSubKeyW
);
2034 if(lpszClassW
) free(lpszClassW
);
2040 /******************************************************************************
2041 * RegCreateKey32W [ADVAPI32.132]
2043 DWORD WINAPI
RegCreateKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2046 LPKEYSTRUCT lpNextKey
;
2048 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2050 /* This check is here because the return value is different than the
2051 one from the Ex functions */
2052 lpNextKey
= lookup_hkey(hkey
);
2054 return ERROR_BADKEY
;
2056 return RegCreateKeyEx32W( hkey
, lpszSubKey
, 0, NULL
,
2057 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2062 /******************************************************************************
2063 * RegCreateKey32A [ADVAPI32.129]
2065 DWORD WINAPI
RegCreateKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2070 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2071 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2072 ret
= RegCreateKey32W( hkey
, lpszSubKeyW
, retkey
);
2073 if(lpszSubKeyW
) free(lpszSubKeyW
);
2078 /******************************************************************************
2079 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2081 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2083 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2084 return RegCreateKey32A( hkey
, lpszSubKey
, retkey
);
2089 * Query Value Functions
2090 * Win32 differs between keynames and valuenames.
2091 * multiple values may belong to one key, the special value
2092 * with name NULL is the default value used by the win31
2096 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2097 * RegQueryValue32W -> RegQueryValueEx32W
2101 /******************************************************************************
2102 * RegQueryValueEx32W [ADVAPI32.158]
2103 * Retrieves type and data for a specified name associated with an open key
2106 * hkey [I] Handle of key to query
2107 * lpValueName [I] Name of value to query
2108 * lpdwReserved [I] Reserved - must be NULL
2109 * lpdwType [O] Address of buffer for value type. If NULL, the type
2111 * lpbData [O] Address of data buffer. If NULL, the actual data is
2113 * lpcbData [I/O] Address of data buffer size
2116 * ERROR_SUCCESS: Success
2117 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2119 DWORD WINAPI
RegQueryValueEx32W( HKEY hkey
, LPWSTR lpValueName
,
2120 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2121 LPBYTE lpbData
, LPDWORD lpcbData
)
2126 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
, debugstr_w(lpValueName
),
2127 lpdwReserved
, lpdwType
, lpbData
, lpcbData
?*lpcbData
:0);
2129 lpkey
= lookup_hkey(hkey
);
2131 return ERROR_INVALID_HANDLE
;
2133 /* Reserved must be NULL (at least for now) */
2135 return ERROR_INVALID_PARAMETER
;
2137 /* An empty name string is equivalent to NULL */
2138 if (lpValueName
&& !*lpValueName
)
2141 if (lpValueName
==NULL
) {
2142 /* Use key's unnamed or default value, if any */
2143 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2144 if (lpkey
->values
[i
].name
==NULL
)
2147 /* Search for the key name */
2148 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2149 if ( lpkey
->values
[i
].name
&&
2150 !lstrcmpi32W(lpValueName
,lpkey
->values
[i
].name
)
2155 if (i
==lpkey
->nrofvalues
) {
2156 TRACE(reg
,"Key not found\n");
2157 if (lpValueName
==NULL
) {
2158 /* Empty keyname not found */
2160 *(WCHAR
*)lpbData
= 0;
2165 TRACE(reg
, "Returning an empty string\n");
2166 return ERROR_SUCCESS
;
2168 return ERROR_BAD_PATHNAME
;
2172 *lpdwType
= lpkey
->values
[i
].type
;
2174 if (lpbData
==NULL
) {
2175 /* Data is not required */
2176 if (lpcbData
==NULL
) {
2177 /* And data size is not required */
2178 /* So all that is returned is the type (set above) */
2179 return ERROR_SUCCESS
;
2181 /* Set the size required and return success */
2182 *lpcbData
= lpkey
->values
[i
].len
;
2183 return ERROR_SUCCESS
;
2186 if (*lpcbData
<lpkey
->values
[i
].len
) {
2187 /* The size was specified, but the data is too big for it */
2188 /* Instead of setting it to NULL, fill in with as much as possible */
2189 /* But the docs do not specify how to handle the lpbData here */
2190 /* *(WCHAR*)lpbData= 0; */
2191 memcpy(lpbData
,lpkey
->values
[i
].data
,*lpcbData
);
2192 *lpcbData
= lpkey
->values
[i
].len
;
2193 return ERROR_MORE_DATA
;
2196 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2198 /* Extra debugging output */
2202 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
2205 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)*lpbData
);
2208 TRACE(reg
," Data(binary)\n");
2209 /* Is there a way of printing this in readable form? */
2212 TRACE(reg
, "Unknown data type %ld\n", *lpdwType
);
2216 /* Set the actual size */
2217 *lpcbData
= lpkey
->values
[i
].len
;
2218 return ERROR_SUCCESS
;
2222 /******************************************************************************
2223 * RegQueryValue32W [ADVAPI32.159]
2225 DWORD WINAPI
RegQueryValue32W( HKEY hkey
, LPWSTR lpszSubKey
, LPWSTR lpszData
,
2231 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2232 lpcbData
?*lpcbData
:0);
2234 /* Only open subkey, if we really do descend */
2235 if (lpszSubKey
&& *lpszSubKey
) {
2236 ret
= RegOpenKey32W( hkey
, lpszSubKey
, &xhkey
);
2237 if (ret
!= ERROR_SUCCESS
) {
2238 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2245 ret
= RegQueryValueEx32W( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2253 /******************************************************************************
2254 * RegQueryValueEx32A [ADVAPI32.157]
2256 DWORD WINAPI
RegQueryValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2257 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2258 LPBYTE lpbData
, LPDWORD lpcbData
)
2260 LPWSTR lpszValueNameW
;
2266 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
,debugstr_a(lpszValueName
),
2267 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2269 lpszValueNameW
= lpszValueName
?strdupA2W(lpszValueName
):NULL
;
2271 /* Why would this be set? It is just an output */
2279 /* Only get the size for now */
2280 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
,
2281 &type
, buf
, mylen
);
2283 if (ret
==ERROR_MORE_DATA
) {
2284 buf
= (LPBYTE
)xmalloc(*mylen
);
2286 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2287 myxlen
= 2*(*lpcbData
);
2290 /* Data is not required */
2293 myxlen
= *lpcbData
*2;
2299 /* Now get the data */
2300 ret
= RegQueryValueEx32W( hkey
, lpszValueNameW
, lpdwReserved
, &type
,
2305 if (ret
==ERROR_SUCCESS
) {
2307 if (UNICONVMASK
& (1<<(type
))) {
2308 /* convert UNICODE to ASCII */
2309 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2310 *lpcbData
= myxlen
/2;
2312 if (myxlen
>*lpcbData
)
2313 ret
= ERROR_MORE_DATA
;
2315 memcpy(lpbData
,buf
,myxlen
);
2320 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2321 *lpcbData
= myxlen
/2;
2324 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2325 *lpcbData
= myxlen
/2;
2329 if(lpszValueNameW
) free(lpszValueNameW
);
2334 /******************************************************************************
2335 * RegQueryValueEx16 [KERNEL.225]
2337 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2338 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2339 LPBYTE lpbData
, LPDWORD lpcbData
)
2341 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2342 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2343 return RegQueryValueEx32A( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2344 lpbData
, lpcbData
);
2348 /******************************************************************************
2349 * RegQueryValue32A [ADVAPI32.156]
2351 DWORD WINAPI
RegQueryValue32A( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2357 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2358 lpcbData
?*lpcbData
:0);
2360 if (lpszSubKey
&& *lpszSubKey
) {
2361 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2362 if( ret
!= ERROR_SUCCESS
)
2368 ret
= RegQueryValueEx32A( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2371 RegCloseKey( xhkey
);
2376 /******************************************************************************
2377 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2380 * Is this HACK still applicable?
2383 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2384 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2387 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2390 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2391 lpcbData
?*lpcbData
:0);
2394 *lpcbData
&= 0xFFFF;
2395 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2400 * Setting values of Registry keys
2403 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2404 * RegSetValue32W -> RegSetValueEx32W
2408 /******************************************************************************
2409 * RegSetValueEx32W [ADVAPI32.170]
2410 * Sets the data and type of a value under a register key
2413 * hkey [I] Handle of key to set value for
2414 * lpszValueName [I] Name of value to set
2415 * dwReserved [I] Reserved - must be zero
2416 * dwType [I] Flag for value type
2417 * lpbData [I] Address of value data
2418 * cbData [I] Size of value data
2421 * Success: ERROR_SUCCESS
2422 * Failure: Error code
2424 DWORD WINAPI
RegSetValueEx32W( HKEY hkey
, LPWSTR lpszValueName
,
2425 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2431 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2432 dwReserved
, dwType
, lpbData
, cbData
);
2436 TRACE(reg
," Data(sz)=%s\n", debugstr_w((LPCWSTR
)lpbData
));
2439 TRACE(reg
," Data(binary)\n");
2442 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)lpbData
);
2445 TRACE(reg
,"Unknown type: %ld\n", dwType
);
2448 lpkey
= lookup_hkey( hkey
);
2450 return ERROR_INVALID_HANDLE
;
2452 lpkey
->flags
|= REG_OPTION_TAINTED
;
2454 if (lpszValueName
==NULL
) {
2455 /* Sets type and name for key's unnamed or default value */
2456 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2457 if (lpkey
->values
[i
].name
==NULL
)
2460 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2461 if ( lpkey
->values
[i
].name
&&
2462 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2466 if (i
==lpkey
->nrofvalues
) {
2467 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2469 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2471 lpkey
->nrofvalues
++;
2472 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2474 if (lpkey
->values
[i
].name
==NULL
)
2476 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2478 lpkey
->values
[i
].name
= NULL
;
2479 lpkey
->values
[i
].len
= cbData
;
2480 lpkey
->values
[i
].type
= dwType
;
2481 if (lpkey
->values
[i
].data
!=NULL
)
2482 free(lpkey
->values
[i
].data
);
2483 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2484 lpkey
->values
[i
].lastmodified
= time(NULL
);
2485 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2486 return ERROR_SUCCESS
;
2490 /******************************************************************************
2491 * RegSetValueEx32A [ADVAPI32.169]
2494 DWORD WINAPI
RegSetValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2495 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2499 LPWSTR lpszValueNameW
;
2502 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2503 dwReserved
,dwType
,lpbData
,cbData
);
2505 if ((1<<dwType
) & UNICONVMASK
) {
2506 buf
=(LPBYTE
)strdupA2W(lpbData
);
2507 cbData
=2*strlen(lpbData
)+2;
2511 lpszValueNameW
= strdupA2W(lpszValueName
);
2513 lpszValueNameW
= NULL
;
2514 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2516 free(lpszValueNameW
);
2523 /******************************************************************************
2524 * RegSetValueEx16 [KERNEL.226]
2526 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2527 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2529 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2530 dwReserved
,dwType
,lpbData
,cbData
);
2531 return RegSetValueEx32A( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2536 /******************************************************************************
2537 * RegSetValue32W [ADVAPI32.171]
2539 DWORD WINAPI
RegSetValue32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2540 LPCWSTR lpszData
, DWORD cbData
)
2545 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2546 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2548 if (lpszSubKey
&& *lpszSubKey
) {
2549 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2550 if (ret
!=ERROR_SUCCESS
)
2554 if (dwType
!=REG_SZ
) {
2555 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2558 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2559 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2560 cbData
,debugstr_w(lpszData
),2*lstrlen32W(lpszData
)+2
2562 cbData
=2*lstrlen32W(lpszData
)+2;
2564 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2571 /******************************************************************************
2572 * RegSetValue32A [ADVAPI32.168]
2575 DWORD WINAPI
RegSetValue32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2576 LPCSTR lpszData
, DWORD cbData
)
2581 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2582 if (lpszSubKey
&& *lpszSubKey
) {
2583 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2584 if (ret
!=ERROR_SUCCESS
)
2589 if (dwType
!=REG_SZ
) {
2590 TRACE(reg
,"dwType=%ld!\n",dwType
);
2593 if (cbData
!=strlen(lpszData
)+1)
2594 cbData
=strlen(lpszData
)+1;
2595 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2602 /******************************************************************************
2603 * RegSetValue16 [KERNEL.221] [SHELL.5]
2605 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2606 LPCSTR lpszData
, DWORD cbData
)
2608 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2609 debugstr_a(lpszData
),cbData
);
2610 return RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2618 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2619 * RegEnumKey32W -> RegEnumKeyEx32W
2623 /******************************************************************************
2624 * RegEnumKeyEx32W [ADVAPI32.139]
2627 * hkey [I] Handle to key to enumerate
2628 * iSubKey [I] Index of subkey to enumerate
2629 * lpszName [O] Buffer for subkey name
2630 * lpcchName [O] Size of subkey buffer
2631 * lpdwReserved [I] Reserved
2632 * lpszClass [O] Buffer for class string
2633 * lpcchClass [O] Size of class buffer
2634 * ft [O] Time key last written to
2636 DWORD WINAPI
RegEnumKeyEx32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2637 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2638 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2641 LPKEYSTRUCT lpkey
,lpxkey
;
2643 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2644 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2646 lpkey
= lookup_hkey( hkey
);
2648 return ERROR_INVALID_HANDLE
;
2650 if (!lpkey
->nextsub
)
2651 return ERROR_NO_MORE_ITEMS
;
2652 lpxkey
=lpkey
->nextsub
;
2654 /* Traverse the subkeys */
2655 while (iSubkey
&& lpxkey
) {
2657 lpxkey
=lpxkey
->next
;
2660 if (iSubkey
|| !lpxkey
)
2661 return ERROR_NO_MORE_ITEMS
;
2662 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2663 return ERROR_MORE_DATA
;
2664 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2667 *lpcchName
= lstrlen32W(lpszName
);
2670 /* FIXME: what should we write into it? */
2674 return ERROR_SUCCESS
;
2678 /******************************************************************************
2679 * RegEnumKey32W [ADVAPI32.140]
2681 DWORD WINAPI
RegEnumKey32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2686 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2687 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2691 /******************************************************************************
2692 * RegEnumKeyEx32A [ADVAPI32.138]
2694 DWORD WINAPI
RegEnumKeyEx32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2695 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2696 LPSTR lpszClass
, LPDWORD lpcchClass
,
2699 DWORD ret
,lpcchNameW
,lpcchClassW
;
2700 LPWSTR lpszNameW
,lpszClassW
;
2703 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2704 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2707 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2708 lpcchNameW
= *lpcchName
*2;
2714 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2715 lpcchClassW
= *lpcchClass
*2;
2720 ret
=RegEnumKeyEx32W(
2730 if (ret
==ERROR_SUCCESS
) {
2731 lstrcpyWtoA(lpszName
,lpszNameW
);
2732 *lpcchName
=strlen(lpszName
);
2734 lstrcpyWtoA(lpszClass
,lpszClassW
);
2735 *lpcchClass
=strlen(lpszClass
);
2746 /******************************************************************************
2747 * RegEnumKey32A [ADVAPI32.137]
2749 DWORD WINAPI
RegEnumKey32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2754 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2755 return RegEnumKeyEx32A( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2760 /******************************************************************************
2761 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2763 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2766 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2767 return RegEnumKey32A( hkey
, iSubkey
, lpszName
, lpcchName
);
2772 * Enumerate Registry Values
2775 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2779 /******************************************************************************
2780 * RegEnumValue32W [ADVAPI32.142]
2783 * hkey [I] Handle to key to query
2784 * iValue [I] Index of value to query
2785 * lpszValue [O] Value string
2786 * lpcchValue [O] Size of value buffer
2787 * lpdReserved [I] Reserved
2788 * lpdwType [O] Type code
2789 * lpbData [O] Value data
2790 * lpcbData [O] Size of data buffer
2792 DWORD WINAPI
RegEnumValue32W( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
2793 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2794 LPDWORD lpdwType
, LPBYTE lpbData
,
2800 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
2801 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2803 lpkey
= lookup_hkey( hkey
);
2805 return ERROR_INVALID_HANDLE
;
2807 if (lpkey
->nrofvalues
<= iValue
)
2808 return ERROR_NO_MORE_ITEMS
;
2810 /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2811 val
= lpkey
->values
+ iValue
;
2814 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2815 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2816 return ERROR_MORE_DATA
;
2818 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2819 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2825 /* Can be NULL if the type code is not required */
2827 *lpdwType
= val
->type
;
2830 if (val
->len
>*lpcbData
)
2831 return ERROR_MORE_DATA
;
2832 memcpy(lpbData
,val
->data
,val
->len
);
2833 *lpcbData
= val
->len
;
2835 return ERROR_SUCCESS
;
2839 /******************************************************************************
2840 * RegEnumValue32A [ADVAPI32.141]
2842 DWORD WINAPI
RegEnumValue32A( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2843 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2844 LPDWORD lpdwType
, LPBYTE lpbData
,
2849 DWORD ret
,lpcbDataW
;
2852 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2853 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2855 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2857 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2858 lpcbDataW
= *lpcbData
*2;
2862 ret
= RegEnumValue32W( hkey
, iValue
, lpszValueW
, lpcchValue
,
2863 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
2868 if (ret
==ERROR_SUCCESS
) {
2869 lstrcpyWtoA(lpszValue
,lpszValueW
);
2871 if ((1<<dwType
) & UNICONVMASK
) {
2872 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2874 if (lpcbDataW
> *lpcbData
)
2875 ret
= ERROR_MORE_DATA
;
2877 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2879 *lpcbData
= lpcbDataW
;
2882 if (lpbDataW
) free(lpbDataW
);
2883 if (lpszValueW
) free(lpszValueW
);
2888 /******************************************************************************
2889 * RegEnumValue16 [KERNEL.223]
2891 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2892 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2893 LPDWORD lpdwType
, LPBYTE lpbData
,
2896 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2897 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2898 return RegEnumValue32A( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
2899 lpdwType
, lpbData
, lpcbData
);
2903 /******************************************************************************
2904 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2905 * Releases the handle of the specified key
2908 * hkey [I] Handle of key to close
2911 * Success: ERROR_SUCCESS
2912 * Failure: Error code
2914 DWORD WINAPI
RegCloseKey( HKEY hkey
)
2916 TRACE(reg
,"(%x)\n",hkey
);
2918 /* The standard handles are allowed to succeed, even though they are not
2920 if (is_standard_hkey(hkey
))
2921 return ERROR_SUCCESS
;
2923 return remove_handle(hkey
);
2928 * Delete registry key
2931 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2935 /******************************************************************************
2936 * RegDeleteKey32W [ADVAPI32.134]
2939 * hkey [I] Handle to open key
2940 * lpszSubKey [I] Name of subkey to delete
2943 * Success: ERROR_SUCCESS
2944 * Failure: Error code
2946 DWORD WINAPI
RegDeleteKey32W( HKEY hkey
, LPWSTR lpszSubKey
)
2948 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2952 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
2954 lpNextKey
= lookup_hkey(hkey
);
2956 return ERROR_INVALID_HANDLE
;
2958 /* Subkey param cannot be NULL */
2959 if (!lpszSubKey
|| !*lpszSubKey
)
2960 return ERROR_BADKEY
;
2962 /* We need to know the previous key in the hier. */
2963 split_keypath(lpszSubKey
,&wps
,&wpc
);
2967 lpxkey
=lpNextKey
->nextsub
;
2969 TRACE(reg
, " Scanning [%s]\n",
2970 debugstr_w(lpxkey
->keyname
));
2971 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2973 lpxkey
=lpxkey
->next
;
2977 TRACE(reg
, " Not found.\n");
2978 /* not found is success */
2979 return ERROR_SUCCESS
;
2984 lpxkey
= lpNextKey
->nextsub
;
2985 lplpPrevKey
= &(lpNextKey
->nextsub
);
2987 TRACE(reg
, " Scanning [%s]\n",
2988 debugstr_w(lpxkey
->keyname
));
2989 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2991 lplpPrevKey
= &(lpxkey
->next
);
2992 lpxkey
= lpxkey
->next
;
2997 WARN(reg
, " Not found.\n");
2998 return ERROR_FILE_NOT_FOUND
;
3001 if (lpxkey
->nextsub
) {
3003 WARN(reg
, " Not empty.\n");
3004 return ERROR_CANTWRITE
;
3006 *lplpPrevKey
= lpxkey
->next
;
3007 free(lpxkey
->keyname
);
3009 free(lpxkey
->class);
3011 free(lpxkey
->values
);
3014 TRACE(reg
, " Done.\n");
3015 return ERROR_SUCCESS
;
3019 /******************************************************************************
3020 * RegDeleteKey32A [ADVAPI32.133]
3022 DWORD WINAPI
RegDeleteKey32A( HKEY hkey
, LPCSTR lpszSubKey
)
3027 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3028 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3029 ret
= RegDeleteKey32W( hkey
, lpszSubKeyW
);
3030 if(lpszSubKeyW
) free(lpszSubKeyW
);
3035 /******************************************************************************
3036 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3038 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3040 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3041 return RegDeleteKey32A( hkey
, lpszSubKey
);
3046 * Delete registry value
3049 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3053 /******************************************************************************
3054 * RegDeleteValue32W [ADVAPI32.136]
3062 DWORD WINAPI
RegDeleteValue32W( HKEY hkey
, LPWSTR lpszValue
)
3068 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3070 lpkey
= lookup_hkey( hkey
);
3072 return ERROR_INVALID_HANDLE
;
3075 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3076 if ( lpkey
->values
[i
].name
&&
3077 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
3081 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3082 if (lpkey
->values
[i
].name
==NULL
)
3086 if (i
== lpkey
->nrofvalues
)
3087 return ERROR_FILE_NOT_FOUND
;
3089 val
= lpkey
->values
+i
;
3090 if (val
->name
) free(val
->name
);
3091 if (val
->data
) free(val
->data
);
3095 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3097 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3099 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3101 lpkey
->nrofvalues
--;
3102 return ERROR_SUCCESS
;
3106 /******************************************************************************
3107 * RegDeleteValue32A [ADVAPI32.135]
3109 DWORD WINAPI
RegDeleteValue32A( HKEY hkey
, LPSTR lpszValue
)
3114 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3115 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3116 ret
= RegDeleteValue32W( hkey
, lpszValueW
);
3117 if(lpszValueW
) free(lpszValueW
);
3122 /******************************************************************************
3123 * RegDeleteValue16 [KERNEL.222]
3125 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3127 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3128 return RegDeleteValue32A( hkey
, lpszValue
);
3132 /******************************************************************************
3133 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3134 * Writes key to registry
3137 * hkey [I] Handle of key to write
3140 * Success: ERROR_SUCCESS
3141 * Failure: Error code
3143 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3148 TRACE(reg
, "(%x)\n", hkey
);
3150 lpkey
= lookup_hkey( hkey
);
3152 return ERROR_INVALID_HANDLE
;
3154 ERR(reg
, "What is the correct filename?\n");
3156 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3159 return ERROR_SUCCESS
;
3161 return ERROR_UNKNOWN
; /* FIXME */
3165 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3168 /******************************************************************************
3169 * RegQueryInfoKey32W [ADVAPI32.153]
3172 * hkey [I] Handle to key to query
3173 * lpszClass [O] Buffer for class string
3174 * lpcchClass [O] Size of class string buffer
3175 * lpdwReserved [I] Reserved
3176 * lpcSubKeys [I] Buffer for number of subkeys
3177 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3178 * lpcchMaxClass [O] Buffer for longest class string length
3179 * lpcValues [O] Buffer for number of value entries
3180 * lpcchMaxValueName [O] Buffer for longest value name length
3181 * lpccbMaxValueData [O] Buffer for longest value data length
3182 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3185 DWORD WINAPI
RegQueryInfoKey32W( HKEY hkey
, LPWSTR lpszClass
,
3186 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3187 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3188 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3189 LPDWORD lpcchMaxValueName
,
3190 LPDWORD lpccbMaxValueData
,
3191 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3193 LPKEYSTRUCT lpkey
,lpxkey
;
3194 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3197 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3198 lpkey
= lookup_hkey(hkey
);
3200 return ERROR_INVALID_HANDLE
;
3203 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
3204 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3205 return ERROR_MORE_DATA
;
3207 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3208 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
3215 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
3217 lpxkey
=lpkey
->nextsub
;
3218 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3221 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
3222 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
3223 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
3224 maxclass
=lstrlen32W(lpxkey
->class);
3225 lpxkey
=lpxkey
->next
;
3227 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3228 LPKEYVALUE val
=lpkey
->values
+i
;
3230 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
3231 maxvname
=lstrlen32W(val
->name
);
3232 if (val
->len
>maxvdata
)
3235 if (!maxclass
) maxclass
= 1;
3236 if (!maxvname
) maxvname
= 1;
3238 *lpcValues
= lpkey
->nrofvalues
;
3240 *lpcSubKeys
= nrofkeys
;
3242 *lpcchMaxSubkey
= maxsubkey
*2;
3244 *lpcchMaxClass
= maxclass
*2;
3245 if (lpcchMaxValueName
)
3246 *lpcchMaxValueName
= maxvname
;
3247 if (lpccbMaxValueData
)
3248 *lpccbMaxValueData
= maxvdata
;
3249 return ERROR_SUCCESS
;
3253 /******************************************************************************
3254 * RegQueryInfoKey32A [ADVAPI32.152]
3256 DWORD WINAPI
RegQueryInfoKey32A( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3257 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3258 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3259 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3260 LPDWORD lpccbMaxValueData
,
3261 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3266 TRACE(reg
,"(%x,......)\n",hkey
);
3269 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
3273 ret
=RegQueryInfoKey32W(
3284 lpcbSecurityDescriptor
,
3287 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3288 lstrcpyWtoA(lpszClass
,lpszClassW
);
3295 if (lpcchMaxValueName
)
3296 *lpcchMaxValueName
/=2;
3303 /******************************************************************************
3304 * RegConnectRegistry32W [ADVAPI32.128]
3307 * lpMachineName [I] Address of name of remote computer
3308 * hHey [I] Predefined registry handle
3309 * phkResult [I] Address of buffer for remote registry handle
3311 LONG WINAPI
RegConnectRegistry32W( LPCWSTR lpMachineName
, HKEY hKey
,
3314 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3316 if (!lpMachineName
|| !*lpMachineName
) {
3317 /* Use the local machine name */
3318 return RegOpenKey16( hKey
, "", phkResult
);
3321 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3322 return ERROR_BAD_NETPATH
;
3326 /******************************************************************************
3327 * RegConnectRegistry32A [ADVAPI32.127]
3329 LONG WINAPI
RegConnectRegistry32A( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3332 LPWSTR machineW
= strdupA2W(machine
);
3333 ret
= RegConnectRegistry32W( machineW
, hkey
, reskey
);
3339 /******************************************************************************
3340 * RegGetKeySecurity [ADVAPI32.144]
3341 * Retrieves a copy of security descriptor protecting the registry key
3344 * hkey [I] Open handle of key to set
3345 * SecurityInformation [I] Descriptor contents
3346 * pSecurityDescriptor [O] Address of descriptor for key
3347 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3350 * Success: ERROR_SUCCESS
3351 * Failure: Error code
3353 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3354 SECURITY_INFORMATION SecurityInformation
,
3355 LPSECURITY_DESCRIPTOR pSecurityDescriptor
,
3356 LPDWORD lpcbSecurityDescriptor
)
3360 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3361 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3363 lpkey
= lookup_hkey( hkey
);
3365 return ERROR_INVALID_HANDLE
;
3367 /* FIXME: Check for valid SecurityInformation values */
3369 if (*lpcbSecurityDescriptor
< sizeof(*pSecurityDescriptor
))
3370 return ERROR_INSUFFICIENT_BUFFER
;
3372 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3373 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3375 return ERROR_SUCCESS
;
3379 /******************************************************************************
3380 * RegLoadKey32W [ADVAPI32.???]
3383 * hkey [I] Handle of open key
3384 * lpszSubKey [I] Address of name of subkey
3385 * lpszFile [I] Address of filename for registry information
3387 LONG WINAPI
RegLoadKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3390 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3392 /* Do this check before the hkey check */
3393 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3394 return ERROR_INVALID_PARAMETER
;
3396 lpkey
= lookup_hkey( hkey
);
3398 return ERROR_INVALID_HANDLE
;
3400 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3401 debugstr_w(lpszFile
));
3403 return ERROR_SUCCESS
;
3407 /******************************************************************************
3408 * RegLoadKey32A [ADVAPI32.???]
3410 LONG WINAPI
RegLoadKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3413 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3414 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3415 ret
= RegLoadKey32W( hkey
, lpszSubKeyW
, lpszFileW
);
3416 if(lpszFileW
) free(lpszFileW
);
3417 if(lpszSubKeyW
) free(lpszSubKeyW
);
3422 /******************************************************************************
3423 * RegNotifyChangeKeyValue [ADVAPI32.???]
3426 * hkey [I] Handle of key to watch
3427 * fWatchSubTree [I] Flag for subkey notification
3428 * fdwNotifyFilter [I] Changes to be reported
3429 * hEvent [I] Handle of signaled event
3430 * fAsync [I] Flag for asynchronous reporting
3432 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL32 fWatchSubTree
,
3433 DWORD fdwNotifyFilter
, HANDLE32 hEvent
,
3437 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3440 lpkey
= lookup_hkey( hkey
);
3442 return ERROR_INVALID_HANDLE
;
3444 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3447 return ERROR_SUCCESS
;
3451 /******************************************************************************
3452 * RegUnLoadKey32W [ADVAPI32.173]
3455 * hkey [I] Handle of open key
3456 * lpSubKey [I] Address of name of subkey to unload
3458 LONG WINAPI
RegUnLoadKey32W( HKEY hkey
, LPCWSTR lpSubKey
)
3460 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3461 return ERROR_SUCCESS
;
3465 /******************************************************************************
3466 * RegUnLoadKey32A [ADVAPI32.172]
3468 LONG WINAPI
RegUnLoadKey32A( HKEY hkey
, LPCSTR lpSubKey
)
3471 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3472 ret
= RegUnLoadKey32W( hkey
, lpSubKeyW
);
3473 if(lpSubKeyW
) free(lpSubKeyW
);
3478 /******************************************************************************
3479 * RegSetKeySecurity [ADVAPI32.167]
3482 * hkey [I] Open handle of key to set
3483 * SecurityInfo [I] Descriptor contents
3484 * pSecurityDesc [I] Address of descriptor for key
3486 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3487 LPSECURITY_DESCRIPTOR pSecurityDesc
)
3491 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3493 /* It seems to perform this check before the hkey check */
3494 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3495 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3496 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3497 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3500 return ERROR_INVALID_PARAMETER
;
3503 return ERROR_INVALID_PARAMETER
;
3505 lpkey
= lookup_hkey( hkey
);
3507 return ERROR_INVALID_HANDLE
;
3509 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3511 return ERROR_SUCCESS
;
3515 /******************************************************************************
3516 * RegSaveKey32W [ADVAPI32.166]
3519 * hkey [I] Handle of key where save begins
3520 * lpFile [I] Address of filename to save to
3521 * sa [I] Address of security structure
3523 LONG WINAPI
RegSaveKey32W( HKEY hkey
, LPCWSTR lpFile
,
3524 LPSECURITY_ATTRIBUTES sa
)
3528 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3530 /* It appears to do this check before the hkey check */
3531 if (!lpFile
|| !*lpFile
)
3532 return ERROR_INVALID_PARAMETER
;
3534 lpkey
= lookup_hkey( hkey
);
3536 return ERROR_INVALID_HANDLE
;
3538 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3540 return ERROR_SUCCESS
;
3544 /******************************************************************************
3545 * RegSaveKey32A [ADVAPI32.165]
3547 LONG WINAPI
RegSaveKey32A( HKEY hkey
, LPCSTR lpFile
,
3548 LPSECURITY_ATTRIBUTES sa
)
3551 LPWSTR lpFileW
= strdupA2W(lpFile
);
3552 ret
= RegSaveKey32W( hkey
, lpFileW
, sa
);
3558 /******************************************************************************
3559 * RegRestoreKey32W [ADVAPI32.164]
3562 * hkey [I] Handle of key where restore begins
3563 * lpFile [I] Address of filename containing saved tree
3564 * dwFlags [I] Optional flags
3566 LONG WINAPI
RegRestoreKey32W( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3570 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3572 /* It seems to do this check before the hkey check */
3573 if (!lpFile
|| !*lpFile
)
3574 return ERROR_INVALID_PARAMETER
;
3576 lpkey
= lookup_hkey( hkey
);
3578 return ERROR_INVALID_HANDLE
;
3580 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3582 /* Check for file existence */
3584 return ERROR_SUCCESS
;
3588 /******************************************************************************
3589 * RegRestoreKey32A [ADVAPI32.163]
3591 LONG WINAPI
RegRestoreKey32A( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3594 LPWSTR lpFileW
= strdupA2W(lpFile
);
3595 ret
= RegRestoreKey32W( hkey
, lpFileW
, dwFlags
);
3596 if(lpFileW
) free(lpFileW
);
3601 /******************************************************************************
3602 * RegReplaceKey32W [ADVAPI32.162]
3605 * hkey [I] Handle of open key
3606 * lpSubKey [I] Address of name of subkey
3607 * lpNewFile [I] Address of filename for file with new data
3608 * lpOldFile [I] Address of filename for backup file
3610 LONG WINAPI
RegReplaceKey32W( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3615 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3616 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3618 lpkey
= lookup_hkey( hkey
);
3620 return ERROR_INVALID_HANDLE
;
3622 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3623 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3625 return ERROR_SUCCESS
;
3629 /******************************************************************************
3630 * RegReplaceKey32A [ADVAPI32.161]
3632 LONG WINAPI
RegReplaceKey32A( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3636 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3637 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3638 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3639 ret
= RegReplaceKey32W( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);