Fixed CloseHandle() on global handles.
[wine/multimedia.git] / misc / registry.c
blob2f53228ca0642de153d2444367d89af6e9c3bd6d
1 /*
2 * Registry Functions
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.
11 * NOTES
12 * When changing this file, please re-run the regtest program to ensure
13 * the conditions are handled properly.
15 * TODO
16 * Security access
17 * Option handling
18 * Time for RegEnumKey*, RegQueryInfoKey*
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <assert.h>
32 #include <time.h>
33 #include "windows.h"
34 #include "win.h"
35 #include "winerror.h"
36 #include "file.h"
37 #include "heap.h"
38 #include "debug.h"
39 #include "xmalloc.h"
40 #include "winreg.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;
68 /* a registry key */
69 typedef struct tagKEYSTRUCT
71 LPWSTR keyname; /* name of THIS key (UNICODE) */
72 DWORD flags; /* flags. */
73 LPWSTR class;
74 /* values */
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 {
98 LPKEYSTRUCT lpkey;
99 HKEY hkey;
100 REGSAM accessmask;
101 } *openhandles=NULL;
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;
110 * QUESTION
111 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112 * If so, can we remove them?
113 * ANSWER
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)
120 if(src) {
121 LPWSTR dest=xmalloc(2*strlen(src)+2);
122 lstrcpyAtoW(dest,src);
123 return dest;
125 return NULL;
128 static LPWSTR strdupW(LPCWSTR a) {
129 LPWSTR b;
130 int len;
132 if(a) {
133 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
134 b=(LPWSTR)xmalloc(len);
135 memcpy(b,a,len);
136 return b;
138 return NULL;
141 LPWSTR strcvtA2W(LPCSTR src, int nchars)
144 LPWSTR dest = xmalloc (2 * nchars + 2);
146 lstrcpynAtoW(dest,src,nchars+1);
147 dest[nchars] = 0;
148 return dest;
152 /******************************************************************************
153 * is_standard_hkey [Internal]
154 * Determines if a hkey is a standard key
156 static BOOL32 is_standard_hkey( HKEY hkey )
158 switch(hkey) {
159 case 0x00000000:
160 case 0x00000001:
161 case HKEY_CLASSES_ROOT:
162 case HKEY_CURRENT_CONFIG:
163 case HKEY_CURRENT_USER:
164 case HKEY_LOCAL_MACHINE:
165 case HKEY_USERS:
166 case HKEY_PERFORMANCE_DATA:
167 case HKEY_DYN_DATA:
168 return TRUE;
169 default:
170 return FALSE;
174 /******************************************************************************
175 * add_handle [Internal]
177 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
179 int i;
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;
199 nrofopenhandles++;
203 /******************************************************************************
204 * get_handle [Internal]
206 * RETURNS
207 * Success: Pointer to key
208 * Failure: NULL
210 static LPKEYSTRUCT get_handle( HKEY hkey )
212 int i;
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);
218 return NULL;
222 /******************************************************************************
223 * remove_handle [Internal]
225 * PARAMS
226 * hkey [I] Handle of key to remove
228 * RETURNS
229 * Success: ERROR_SUCCESS
230 * Failure: ERROR_INVALID_HANDLE
232 static DWORD remove_handle( HKEY hkey )
234 int i;
236 for (i=0;i<nrofopenhandles;i++)
237 if (openhandles[i].hkey==hkey)
238 break;
240 if (i == nrofopenhandles) {
241 WARN(reg, "Could not find handle 0x%x\n",hkey);
242 return ERROR_INVALID_HANDLE;
245 memcpy( openhandles+i,
246 openhandles+i+1,
247 sizeof(struct openhandle)*(nrofopenhandles-i-1)
249 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
250 nrofopenhandles--;
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.
260 * RETURNS
261 * Success: Pointer to key structure
262 * Failure: NULL
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 )
271 switch (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
275 case 0x00000000:
276 case 0x00000001:
277 case HKEY_CLASSES_ROOT: {
278 if (!key_classes_root) {
279 HKEY cl_r_hkey;
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");
284 exit(1);
286 key_classes_root = lookup_hkey(cl_r_hkey);
288 return key_classes_root;
290 case HKEY_CURRENT_USER:
291 if (!key_current_user) {
292 HKEY c_u_hkey;
293 struct passwd *pwd;
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);
300 exit(1);
302 key_current_user = lookup_hkey(c_u_hkey);
303 } else {
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);
312 REGISTRY_Init();
314 return key_local_machine;
315 case HKEY_USERS:
316 if (!key_users) {
317 ADD_ROOT_KEY(key_users);
319 return key_users;
320 case HKEY_PERFORMANCE_DATA:
321 if (!key_performance_data) {
322 ADD_ROOT_KEY(key_performance_data);
324 return key_performance_data;
325 case HKEY_DYN_DATA:
326 if (!key_dyn_data) {
327 ADD_ROOT_KEY(key_dyn_data);
329 return 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;
335 default:
336 return get_handle(hkey);
338 /*NOTREACHED*/
340 #undef ADD_ROOT_KEY
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
356 * PARAMS
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)
363 int i,j,len;
364 LPWSTR ws;
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 */
371 *wpc = 1;
373 /* Replace each backslash with NULL, and increment the count */
374 for (i=0;ws[i];i++) {
375 if (ws[i]=='\\') {
376 ws[i]=0;
377 (*wpc)++;
381 len = i;
383 /* Allocate the space for the array of pointers, leaving room for the
384 NULL at the end */
385 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
386 (*wpv)[0]= ws;
388 /* Assign each pointer to the appropriate character in the string */
389 j = 1;
390 for (i=1;i<len;i++)
391 if (ws[i-1]==0) {
392 (*wpv)[j++]=ws+i;
393 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
396 (*wpv)[j]=NULL;
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) {
408 HKEY hkey;
409 char buf[200];
411 TRACE(reg,"(void)\n");
413 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
414 RegCloseKey(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"));
420 RegCloseKey(hkey);
422 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
423 * CurrentVersion
424 * CurrentBuildNumber
425 * CurrentType
426 * string RegisteredOwner
427 * string RegisteredOrganization
430 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
431 * string SysContact
432 * string SysLocation
433 * SysServices
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);
438 RegCloseKey(hkey);
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.
451 * Global:
452 * "WINE REGISTRY Version %d"
453 * subkeys....
454 * Subkeys:
455 * keyname
456 * valuename=lastmodified,type,data
457 * ...
458 * subkeys
459 * ...
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.)
464 * type,lastmodified:
465 * int
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 )
478 int tainted;
480 if (!lpkey)
481 return 0;
482 if (lpkey->flags & REG_OPTION_TAINTED)
483 tainted = 1;
484 else
485 tainted = 0;
486 while (lpkey) {
487 if (_save_check_tainted(lpkey->nextsub)) {
488 lpkey->flags |= REG_OPTION_TAINTED;
489 tainted = 1;
491 lpkey = lpkey->next;
493 return tainted;
496 /******************************************************************************
497 * _save_USTRING [Internal]
499 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
501 LPWSTR s;
502 int doescape;
504 if (wstr==NULL)
505 return;
506 s=wstr;
507 while (*s) {
508 doescape=0;
509 if (*s>0xff)
510 doescape = 1;
511 if (*s=='\n')
512 doescape = 1;
513 if (escapeeq && *s=='=')
514 doescape = 1;
515 if (*s=='\\')
516 fputc(*s,F); /* if \\ then put it twice. */
517 if (doescape)
518 fprintf(F,"\\u%04x",*((unsigned short*)s));
519 else
520 fputc(*s,F);
521 s++;
525 /******************************************************************************
526 * _savesubkey [Internal]
528 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
530 LPKEYSTRUCT lpxkey;
531 int i,tabs,j;
533 lpxkey = lpkey;
534 while (lpxkey) {
535 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
536 (all || (lpxkey->flags & REG_OPTION_TAINTED))
538 for (tabs=level;tabs--;)
539 fputc('\t',F);
540 _save_USTRING(F,lpxkey->keyname,1);
541 fputs("\n",F);
542 for (i=0;i<lpxkey->nrofvalues;i++) {
543 LPKEYVALUE val=lpxkey->values+i;
545 for (tabs=level+1;tabs--;)
546 fputc('\t',F);
547 _save_USTRING(F,val->name,0);
548 fputc('=',F);
549 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
550 if ((1<<val->type) & UNICONVMASK)
551 _save_USTRING(F,(LPWSTR)val->data,0);
552 else
553 for (j=0;j<val->len;j++)
554 fprintf(F,"%02x",*((unsigned char*)val->data+j));
555 fputs("\n",F);
557 /* descend recursively */
558 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
559 return 0;
561 lpxkey=lpxkey->next;
563 return 1;
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 )
583 FILE *F;
585 F=fopen(fn,"w");
586 if (F==NULL) {
587 WARN(reg,"Couldn't open %s for writing: %s\n",
588 fn,strerror(errno)
590 return FALSE;
592 if (!_savesubreg(F,lpkey,all)) {
593 fclose(F);
594 unlink(fn);
595 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
596 return FALSE;
598 fclose(F);
599 return TRUE;
603 /******************************************************************************
604 * SHELL_SaveRegistry [Internal]
606 void SHELL_SaveRegistry( void )
608 char *fn;
609 struct passwd *pwd;
610 char buf[4];
611 HKEY hkey;
612 int all;
614 TRACE(reg,"(void)\n");
616 all=0;
617 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
618 strcpy(buf,"yes");
619 } else {
620 DWORD len,junk,type;
622 len=4;
623 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
624 hkey,
625 VAL_SAVEUPDATED,
626 &junk,
627 &type,
628 buf,
629 &len
630 ))|| (type!=REG_SZ)
632 strcpy(buf,"yes");
633 RegCloseKey(hkey);
635 if (lstrcmpi32A(buf,"yes"))
636 all=1;
637 pwd=getpwuid(getuid());
638 if (pwd!=NULL && pwd->pw_dir!=NULL)
640 char *tmp;
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");
654 unlink(tmp);
657 free(tmp);
658 free(fn);
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");
667 unlink(tmp);
670 free(tmp);
671 free(fn);
672 } else
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)) {
689 free(keyname);
690 return lpkey;
692 lplpkey= &(lpkey->nextsub);
693 lpxkey = *lplpkey;
694 while (lpxkey) {
695 if ( (lpxkey->keyname[0]==keyname[0]) &&
696 !lstrcmpi32W(lpxkey->keyname,keyname)
698 break;
699 lplpkey = &(lpxkey->next);
700 lpxkey = *lplpkey;
702 if (lpxkey==NULL) {
703 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
704 lpxkey = *lplpkey;
705 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
706 lpxkey->keyname = keyname;
707 } else
708 free(keyname);
709 return lpxkey;
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 )
718 LPKEYVALUE val=NULL;
719 int i;
721 if (name && !*name) {/* empty string equals default (NULL) value */
722 free(name);
723 name = NULL;
726 for (i=0;i<lpkey->nrofvalues;i++) {
727 val=lpkey->values+i;
728 if (name==NULL) {
729 if (val->name==NULL)
730 break;
731 } else {
732 if ( val->name!=NULL &&
733 val->name[0]==name[0] &&
734 !lstrcmpi32W(val->name,name)
736 break;
739 if (i==lpkey->nrofvalues) {
740 lpkey->values = xrealloc(
741 lpkey->values,
742 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
744 val=lpkey->values+i;
745 memset(val,'\0',sizeof(KEYVALUE));
746 val->name = name;
747 } else {
748 if (name)
749 free(name);
751 if (val->lastmodified<lastmodified) {
752 val->lastmodified=lastmodified;
753 val->type = type;
754 val->len = len;
755 if (val->data)
756 free(val->data);
757 val->data = data;
758 } else
759 free(data);
763 /******************************************************************************
764 * _wine_read_line [Internal]
766 * reads a line including dynamically enlarging the readbuffer and throwing
767 * away comments
769 static int _wine_read_line( FILE *F, char **buf, int *len )
771 char *s,*curread;
772 int mylen,curoff;
774 curread = *buf;
775 mylen = *len;
776 **buf = '\0';
777 while (1) {
778 while (1) {
779 s=fgets(curread,mylen,F);
780 if (s==NULL)
781 return 0; /* EOF */
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
790 *len = *len * 2;
791 } else {
792 *s='\0';
793 break;
796 /* throw away comments */
797 if (**buf=='#' || **buf==';') {
798 curread = *buf;
799 mylen = *len;
800 continue;
802 if (s) /* got end of line */
803 break;
805 return 1;
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 )
817 char *s;
818 LPWSTR ws;
820 /* read up to "=" or "\0" or "\n" */
821 s = buf;
822 if (*s == '=') {
823 /* empty string is the win3.1 default value(NULL)*/
824 *str = NULL;
825 return s;
827 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
828 ws = *str;
829 while (*s && (*s!='\n') && (*s!='=')) {
830 if (*s!='\\')
831 *ws++=*((unsigned char*)s++);
832 else {
833 s++;
834 if (*s=='\\') {
835 *ws++='\\';
836 s++;
837 continue;
839 if (*s!='u') {
840 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
841 *ws++='\\';
842 *ws++=*s++;
843 } else {
844 char xbuf[5];
845 int wc;
847 s++;
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);
851 s+=4;
852 *ws++ =(unsigned short)wc;
856 *ws = 0;
857 ws = *str;
858 if (*ws)
859 *str = strdupW(*str);
860 else
861 *str = NULL;
862 free(ws);
863 return s;
867 /******************************************************************************
868 * _wine_loadsubkey [Internal]
870 * NOTES
871 * It seems like this is returning a boolean. Should it?
873 * RETURNS
874 * Success: 1
875 * Failure: 0
877 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
878 int *buflen, DWORD optflag )
880 LPKEYSTRUCT lpxkey;
881 int i;
882 char *s;
883 LPWSTR name;
885 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
886 *buflen, optflag);
888 lpkey->flags |= optflag;
890 /* Good. We already got a line here ... so parse it */
891 lpxkey = NULL;
892 while (1) {
893 i=0;s=*buf;
894 while (*s=='\t') {
895 s++;
896 i++;
898 if (i>level) {
899 if (lpxkey==NULL) {
900 WARN(reg,"Got a subhierarchy without resp. key?\n");
901 return 0;
903 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
904 continue;
907 /* let the caller handle this line */
908 if (i<level || **buf=='\0')
909 return 1;
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 */
915 switch (0) {
916 default:
917 if (*s=='\0') {
918 lpxkey=_find_or_add_key(lpkey,name);
919 } else {
920 LPBYTE data;
921 int len,lastmodified,type;
923 if (*s!='=') {
924 WARN(reg,"Unexpected character: %c\n",*s);
925 break;
927 s++;
928 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
929 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
930 break;
932 /* skip the 2 , */
933 s=strchr(s,',');s++;
934 s=strchr(s,',');s++;
935 if ((1<<type) & UNICONVMASK) {
936 s=_wine_read_USTRING(s,(LPWSTR*)&data);
937 if (data)
938 len = lstrlen32W((LPWSTR)data)*2+2;
939 else
940 len = 0;
941 } else {
942 len=strlen(s)/2;
943 data = (LPBYTE)xmalloc(len+1);
944 for (i=0;i<len;i++) {
945 data[i]=0;
946 if (*s>='0' && *s<='9')
947 data[i]=(*s-'0')<<4;
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;
952 s++;
953 if (*s>='0' && *s<='9')
954 data[i]|=*s-'0';
955 if (*s>='a' && *s<='f')
956 data[i]|=*s-'a'+'\xa';
957 if (*s>='A' && *s<='F')
958 data[i]|=*s-'A'+'\xa';
959 s++;
962 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
965 /* read the next line */
966 if (!_wine_read_line(F,buf,buflen))
967 return 1;
969 return 1;
973 /******************************************************************************
974 * _wine_loadsubreg [Internal]
976 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
978 int ver;
979 char *buf;
980 int buflen;
982 buf=xmalloc(10);buflen=10;
983 if (!_wine_read_line(F,&buf,&buflen)) {
984 free(buf);
985 return 0;
987 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
988 free(buf);
989 return 0;
991 if (ver!=REGISTRY_SAVE_VERSION) {
992 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
993 free(buf);
994 return 0;
996 if (!_wine_read_line(F,&buf,&buflen)) {
997 free(buf);
998 return 0;
1000 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1001 free(buf);
1002 return 0;
1004 free(buf);
1005 return 1;
1009 /******************************************************************************
1010 * _wine_loadreg [Internal]
1012 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1014 FILE *F;
1016 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1018 F = fopen(fn,"rb");
1019 if (F==NULL) {
1020 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1021 return;
1023 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1024 fclose(F);
1025 unlink(fn);
1026 return;
1028 fclose(F);
1032 /******************************************************************************
1033 * _copy_registry [Internal]
1035 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1037 LPKEYSTRUCT lpxkey;
1038 int j;
1039 LPKEYVALUE valfrom;
1041 from=from->nextsub;
1042 while (from) {
1043 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1045 for (j=0;j<from->nrofvalues;j++) {
1046 LPWSTR name;
1047 LPBYTE data;
1049 valfrom = from->values+j;
1050 name=valfrom->name;
1051 if (name) name=strdupW(name);
1052 data=(LPBYTE)xmalloc(valfrom->len);
1053 memcpy(data,valfrom->data,valfrom->len);
1055 _find_or_add_value(
1056 lpxkey,
1057 name,
1058 valfrom->type,
1059 data,
1060 valfrom->len,
1061 valfrom->lastmodified
1064 _copy_registry(from,lpxkey);
1065 from = from->next;
1070 /* WINDOWS 95 REGISTRY LOADER */
1072 * Structure of a win95 registry database.
1073 * main header:
1074 * 0 : "CREG" - magic
1075 * 4 : DWORD version
1076 * 8 : DWORD offset_of_RGDB_part
1077 * 0C..0F: ? (someone fill in please)
1078 * 10: WORD number of RGDB blocks
1079 * 12: WORD ?
1080 * 14: WORD always 0000?
1081 * 16: WORD always 0001?
1082 * 18..1F: ? (someone fill in please)
1084 * 20: RGKN_section:
1085 * header:
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
1108 * that RGDB section
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
1116 * RGDB_section:
1117 * 00: "RGDB" - magic
1118 * 04: DWORD offset to next RGDB section
1119 * 08: DWORD ?
1120 * 0C: WORD always 000d?
1121 * 0E: WORD RGDB block number
1122 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1123 * 14..1F: ?
1124 * 20.....: disk keys
1126 * disk key:
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
1137 * disk value:
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 {
1159 unsigned long type;
1160 unsigned short datalen;
1161 char *name;
1162 unsigned char *data;
1163 unsigned long x1;
1164 int lastmodified;
1167 struct _w95key {
1168 char *name;
1169 int nrofvals;
1170 struct _w95keyvalue *values;
1171 struct _w95key *prevlvl;
1172 struct _w95key *nextsub;
1173 struct _w95key *next;
1177 struct _w95_info {
1178 char *rgknbuffer;
1179 int rgknsize;
1180 char *rgdbbuffer;
1181 int rgdbsize;
1182 int depth;
1183 int lastmodified;
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) */
1195 struct dkh {
1196 unsigned long nextkeyoff;
1197 unsigned short nrLS;
1198 unsigned short nrMS;
1199 unsigned long bytesused;
1200 unsigned short keynamelen;
1201 unsigned short values;
1202 unsigned long xx1;
1203 /* keyname */
1204 /* disk key values or nothing */
1206 /* Disk Key Value structure */
1207 struct dkv {
1208 unsigned long type;
1209 unsigned long x1;
1210 unsigned short valnamelen;
1211 unsigned short valdatalen;
1212 /* valname, valdata */
1216 struct dkh dkh;
1217 int bytesread = 0;
1218 char *rgdbdata = info->rgdbbuffer;
1219 int nbytes = info->rgdbsize;
1220 char *curdata = rgdbdata;
1221 char *end = rgdbdata + nbytes;
1222 int off_next_rgdb;
1223 char *next = rgdbdata;
1224 int nrgdb, i;
1225 LPKEYSTRUCT lpxkey;
1227 do {
1228 curdata = next;
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 */
1238 curdata += 0x20;
1240 #define XREAD(whereto,len) \
1241 if ((curdata + len) <end) {\
1242 memcpy(whereto,curdata,len);\
1243 curdata+=len;\
1244 bytesread+=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);
1254 break;
1256 curdata += xdkh->nextkeyoff;
1259 if (dkh.nrLS != nrLS) return (NULL);
1261 if (nrgdb != dkh.nrMS)
1262 return (NULL);
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++) {
1269 struct dkv dkv;
1270 LPBYTE data;
1271 int len;
1272 LPWSTR name;
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);
1282 } else {
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;
1291 _find_or_add_value(
1292 lpxkey,
1293 name,
1294 dkv.type,
1295 data,
1296 len,
1297 info->lastmodified
1300 return (lpxkey);
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) */
1311 struct dke {
1312 unsigned long x1;
1313 unsigned long x2;
1314 unsigned long x3;/*usually 0xFFFFFFFF */
1315 unsigned long prevlvl;
1316 unsigned long nextsub;
1317 unsigned long next;
1318 unsigned short nrLS;
1319 unsigned short nrMS;
1320 } *dke = (struct dke *)off;
1321 LPKEYSTRUCT lpxkey;
1323 if (dke == NULL) {
1324 dke = (struct dke *) ((char *)info->rgknbuffer);
1327 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1328 /* XXX <-- This is a hack*/
1329 if (!lpxkey) {
1330 lpxkey = prevkey;
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,
1339 info);
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,
1347 info);
1350 return;
1354 /******************************************************************************
1355 * _w95_loadreg [Internal]
1357 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1359 HFILE32 hfd;
1360 char magic[5];
1361 unsigned long where,version,rgdbsection,end;
1362 struct _w95_info info;
1363 OFSTRUCT ofs;
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)
1369 return;
1370 magic[4]=0;
1371 if (4!=_lread32(hfd,magic,4))
1372 return;
1373 if (strcmp(magic,"CREG")) {
1374 WARN(reg,"%s is not a w95 registry.\n",fn);
1375 return;
1377 if (4!=_lread32(hfd,&version,4))
1378 return;
1379 if (4!=_lread32(hfd,&rgdbsection,4))
1380 return;
1381 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1382 return;
1383 if (4!=_lread32(hfd,magic,4))
1384 return;
1385 if (strcmp(magic,"RGKN")) {
1386 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1387 return;
1390 /* STEP 1: Keylink structures */
1391 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1392 return;
1393 where = 0x40;
1394 end = rgdbsection;
1396 info.rgknsize = end - where;
1397 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1398 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1399 return;
1401 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1402 return;
1404 end = hfdinfo.nFileSizeLow;
1405 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1407 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1408 return;
1410 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1411 info.rgdbsize = end - rgdbsection;
1413 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1414 return;
1415 _lclose32(hfd);
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
1438 the directory.
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 */
1488 /* key tabent: */
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 */
1496 /* value tabent: */
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 */
1505 void
1506 __w31_dumptree( unsigned short idx,
1507 unsigned char *txt,
1508 struct _w31_tabent *tab,
1509 struct _w31_header *head,
1510 LPKEYSTRUCT lpkey,
1511 time_t lastmodified,
1512 int level
1514 struct _w31_dirent *dir;
1515 struct _w31_keyent *key;
1516 struct _w31_valent *val;
1517 LPKEYSTRUCT xlpkey = NULL;
1518 LPWSTR name,value;
1519 static char tail[400];
1521 while (idx!=0) {
1522 dir=(struct _w31_dirent*)&tab[idx];
1524 if (dir->key_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;
1535 continue;
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);
1551 } else {
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) {
1564 HFILE32 hf;
1565 struct _w31_header head;
1566 struct _w31_tabent *tab;
1567 unsigned char *txt;
1568 int len;
1569 OFSTRUCT ofs;
1570 BY_HANDLE_FILE_INFORMATION hfinfo;
1571 time_t lastmodified;
1572 LPKEYSTRUCT lpkey;
1574 TRACE(reg,"(void)\n");
1576 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1577 if (hf==HFILE_ERROR32)
1578 return;
1580 /* read & dump header */
1581 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1582 ERR(reg, "reg.dat is too short.\n");
1583 _lclose32(hf);
1584 return;
1586 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1587 ERR(reg, "reg.dat has bad signature.\n");
1588 _lclose32(hf);
1589 return;
1592 len = head.tabcnt * sizeof(struct _w31_tabent);
1593 /* read and dump index table */
1594 tab = xmalloc(len);
1595 if (len!=_lread32(hf,tab,len)) {
1596 ERR(reg,"couldn't read %d bytes.\n",len);
1597 free(tab);
1598 _lclose32(hf);
1599 return;
1602 /* read text */
1603 txt = xmalloc(head.textsize);
1604 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1605 ERR(reg,"couldn't seek to textblock.\n");
1606 free(tab);
1607 free(txt);
1608 _lclose32(hf);
1609 return;
1611 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1612 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1613 free(tab);
1614 free(txt);
1615 _lclose32(hf);
1616 return;
1619 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1620 ERR(reg,"GetFileInformationByHandle failed?.\n");
1621 free(tab);
1622 free(txt);
1623 _lclose32(hf);
1624 return;
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);
1629 free(tab);
1630 free(txt);
1631 _lclose32(hf);
1632 return;
1636 /**********************************************************************************
1637 * SHELL_LoadRegistry [Internal]
1639 void SHELL_LoadRegistry( void )
1641 char *fn;
1642 struct passwd *pwd;
1643 LPKEYSTRUCT lpkey;
1644 HKEY hkey;
1646 TRACE(reg,"(void)\n");
1648 /* Load windows 3.1 entries */
1649 _w31_loadreg();
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);
1658 if(!lpkey)
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));
1664 RegCloseKey(hkey);
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);
1679 free(fn);
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);
1684 free(fn);
1685 } else
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;
1689 char data[5];
1691 len=4;
1692 if (( RegQueryValueEx32A(
1693 hkey,
1694 VAL_SAVEUPDATED,
1695 &junk,
1696 &type,
1697 data,
1698 &len
1699 )!=ERROR_SUCCESS) ||
1700 type != REG_SZ
1702 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1703 RegCloseKey(hkey);
1708 /********************* API FUNCTIONS ***************************************/
1710 * Open Keys.
1712 * All functions are stubs to RegOpenKeyEx32W where all the
1713 * magic happens.
1715 * Callpath:
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.
1727 * PARAMS
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
1734 * RETURNS
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;
1742 LPWSTR *wps;
1743 int wpc,i;
1745 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1746 samDesired,retkey);
1748 lpNextKey = lookup_hkey( hkey );
1749 if (!lpNextKey)
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 */
1755 currenthandle += 2;
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);
1767 i = 0;
1768 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1769 lpxkey = lpNextKey;
1771 while (wps[i]) {
1772 lpxkey=lpNextKey->nextsub;
1773 while (lpxkey) {
1774 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1775 break;
1777 lpxkey=lpxkey->next;
1780 if (!lpxkey) {
1781 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1782 FREE_KEY_PATH;
1783 return ERROR_FILE_NOT_FOUND;
1785 i++;
1786 lpNextKey = lpxkey;
1789 currenthandle += 2;
1790 add_handle(currenthandle,lpxkey,samDesired);
1791 *retkey = currenthandle;
1792 TRACE(reg," Returning %x\n", currenthandle);
1793 FREE_KEY_PATH;
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);
1805 DWORD ret;
1807 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1808 samDesired,retkey);
1809 ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1810 free(lpszSubKeyW);
1811 return ret;
1815 /******************************************************************************
1816 * RegOpenKey32W [ADVAPI32.151]
1818 * PARAMS
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
1823 * RETURNS
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 )
1839 DWORD ret;
1840 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1841 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1842 ret = RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1843 free(lpszSubKeyW);
1844 return ret;
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 );
1859 * Create keys
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
1867 * Callpath:
1868 * RegCreateKeyEx32A \
1869 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1873 /******************************************************************************
1874 * RegCreateKeyEx32W [ADVAPI32.131]
1876 * PARAMS
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;
1894 LPWSTR *wps;
1895 int wpc,i;
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);
1902 if (!lpNextKey)
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:
1910 break;
1911 default:
1912 return ERROR_INVALID_PARAMETER;
1915 /* Sam has to be a combination of the following */
1916 if (!(samDesired &
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) {
1923 currenthandle += 2;
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);
1937 i = 0;
1938 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1939 lpxkey = lpNextKey;
1940 while (wps[i]) {
1941 lpxkey=lpNextKey->nextsub;
1942 while (lpxkey) {
1943 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1944 break;
1945 lpxkey=lpxkey->next;
1947 if (!lpxkey)
1948 break;
1949 i++;
1950 lpNextKey = lpxkey;
1952 if (lpxkey) {
1953 currenthandle += 2;
1954 add_handle(currenthandle,lpxkey,samDesired);
1955 lpxkey->flags |= REG_OPTION_TAINTED;
1956 *retkey = currenthandle;
1957 TRACE(reg, "Returning %x\n", currenthandle);
1958 if (lpDispos)
1959 *lpDispos = REG_OPENED_EXISTING_KEY;
1960 FREE_KEY_PATH;
1961 return ERROR_SUCCESS;
1964 /* Good. Now the hard part */
1965 while (wps[i]) {
1966 lplpPrevKey = &(lpNextKey->nextsub);
1967 lpxkey = *lplpPrevKey;
1968 while (lpxkey) {
1969 lplpPrevKey = &(lpxkey->next);
1970 lpxkey = *lplpPrevKey;
1972 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1973 if (!*lplpPrevKey) {
1974 FREE_KEY_PATH;
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;
1986 if (lpszClass)
1987 (*lplpPrevKey)->class = strdupW(lpszClass);
1988 else
1989 (*lplpPrevKey)->class = NULL;
1990 lpNextKey = *lplpPrevKey;
1991 i++;
1993 currenthandle += 2;
1994 add_handle(currenthandle,lpNextKey,samDesired);
1996 /*FIXME: flag handling correct? */
1997 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1998 if (lpszClass)
1999 lpNextKey->class = strdupW(lpszClass);
2000 else
2001 lpNextKey->class = NULL;
2002 *retkey = currenthandle;
2003 TRACE(reg, "Returning %x\n", currenthandle);
2004 if (lpDispos)
2005 *lpDispos = REG_CREATED_NEW_KEY;
2006 FREE_KEY_PATH;
2007 return ERROR_SUCCESS;
2011 /******************************************************************************
2012 * RegCreateKeyEx32A [ADVAPI32.130]
2014 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2015 LPSTR lpszClass, DWORD fdwOptions,
2016 REGSAM samDesired,
2017 LPSECURITY_ATTRIBUTES lpSecAttribs,
2018 LPHKEY retkey, LPDWORD lpDispos )
2020 LPWSTR lpszSubKeyW, lpszClassW;
2021 DWORD ret;
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,
2025 retkey,lpDispos);
2027 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2028 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2030 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2031 fdwOptions, samDesired, lpSecAttribs, retkey,
2032 lpDispos );
2034 if(lpszSubKeyW) free(lpszSubKeyW);
2035 if(lpszClassW) free(lpszClassW);
2037 return ret;
2041 /******************************************************************************
2042 * RegCreateKey32W [ADVAPI32.132]
2044 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2046 DWORD junk;
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);
2054 if (!lpNextKey)
2055 return ERROR_BADKEY;
2057 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
2058 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2059 retkey, &junk);
2063 /******************************************************************************
2064 * RegCreateKey32A [ADVAPI32.129]
2066 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2068 DWORD ret;
2069 LPWSTR lpszSubKeyW;
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);
2075 return ret;
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
2094 * compat functions.
2096 * Callpath:
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
2106 * PARAMS
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
2111 * is not required.
2112 * lpbData [O] Address of data buffer. If NULL, the actual data is
2113 * not required.
2114 * lpcbData [I/O] Address of data buffer size
2116 * RETURNS
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 )
2124 LPKEYSTRUCT lpkey;
2125 int i;
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);
2131 if (!lpkey)
2132 return ERROR_INVALID_HANDLE;
2134 /* Reserved must be NULL (at least for now) */
2135 if (lpdwReserved)
2136 return ERROR_INVALID_PARAMETER;
2138 /* An empty name string is equivalent to NULL */
2139 if (lpValueName && !*lpValueName)
2140 lpValueName = NULL;
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)
2146 break;
2147 } else {
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)
2153 break;
2156 if (i==lpkey->nrofvalues) {
2157 TRACE(reg,"Key not found\n");
2158 if (lpValueName==NULL) {
2159 /* Empty keyname not found */
2160 if (lpbData) {
2161 *(WCHAR*)lpbData = 0;
2162 *lpcbData = 2;
2164 if (lpdwType)
2165 *lpdwType = REG_SZ;
2166 TRACE(reg, "Returning an empty string\n");
2167 return ERROR_SUCCESS;
2169 return ERROR_FILE_NOT_FOUND;
2172 if (lpdwType)
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 */
2200 if (lpdwType) {
2201 switch(*lpdwType){
2202 case REG_SZ:
2203 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
2204 break;
2205 case REG_DWORD:
2206 TRACE(reg," Data(dword)=%lx\n", (DWORD)*lpbData);
2207 break;
2208 case REG_BINARY:
2209 TRACE(reg," Data(binary)\n");
2210 /* Is there a way of printing this in readable form? */
2211 break;
2212 default:
2213 TRACE(reg, "Unknown data type %ld\n", *lpdwType);
2214 } /* switch */
2215 } /* if */
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,
2227 LPDWORD lpcbData )
2229 HKEY xhkey;
2230 DWORD ret,lpdwType;
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));
2240 return ret;
2242 } else
2243 xhkey = hkey;
2245 lpdwType = REG_SZ;
2246 ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2247 lpcbData );
2248 if (xhkey != hkey)
2249 RegCloseKey(xhkey);
2250 return ret;
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;
2262 LPBYTE buf;
2263 DWORD ret,myxlen;
2264 DWORD *mylen;
2265 DWORD type;
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 */
2273 if (lpdwType)
2274 type = *lpdwType;
2276 if (lpbData) {
2277 myxlen = 0;
2278 mylen = &myxlen;
2279 buf = xmalloc(4);
2280 /* Only get the size for now */
2281 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved,
2282 &type, buf, mylen );
2283 free(buf);
2284 if (ret==ERROR_MORE_DATA) {
2285 buf = (LPBYTE)xmalloc(*mylen);
2286 } else {
2287 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2288 myxlen = 2*(*lpcbData);
2290 } else {
2291 /* Data is not required */
2292 buf=NULL;
2293 if (lpcbData) {
2294 myxlen = *lpcbData*2;
2295 mylen = &myxlen;
2296 } else
2297 mylen = NULL;
2300 /* Now get the data */
2301 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &type,
2302 buf, mylen );
2303 if (lpdwType)
2304 *lpdwType=type;
2306 if (ret==ERROR_SUCCESS) {
2307 if (buf) {
2308 if (UNICONVMASK & (1<<(type))) {
2309 /* convert UNICODE to ASCII */
2310 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2311 *lpcbData = myxlen/2;
2312 } else {
2313 if (myxlen>*lpcbData)
2314 ret = ERROR_MORE_DATA;
2315 else
2316 memcpy(lpbData,buf,myxlen);
2318 *lpcbData = myxlen;
2320 } else {
2321 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2322 *lpcbData = myxlen/2;
2324 } else {
2325 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2326 *lpcbData = myxlen/2;
2329 if(buf) free(buf);
2330 if(lpszValueNameW) free(lpszValueNameW);
2331 return ret;
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,
2353 LPDWORD lpcbData )
2355 HKEY xhkey;
2356 DWORD ret, dwType;
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 )
2364 return ret;
2365 } else
2366 xhkey = hkey;
2368 dwType = REG_SZ;
2369 ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2370 lpcbData );
2371 if( xhkey != hkey )
2372 RegCloseKey( xhkey );
2373 return ret;
2377 /******************************************************************************
2378 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2380 * NOTES
2381 * Is this HACK still applicable?
2383 * HACK
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
2386 * Aldus FH4)
2388 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2389 LPDWORD lpcbData )
2391 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2392 lpcbData?*lpcbData:0);
2394 if (lpcbData)
2395 *lpcbData &= 0xFFFF;
2396 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2401 * Setting values of Registry keys
2403 * Callpath:
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
2413 * PARAMS
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
2421 * RETURNS
2422 * Success: ERROR_SUCCESS
2423 * Failure: Error code
2425 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2426 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2427 DWORD cbData)
2429 LPKEYSTRUCT lpkey;
2430 int i;
2432 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2433 dwReserved, dwType, lpbData, cbData);
2435 switch (dwType) {
2436 case REG_SZ:
2437 TRACE(reg," Data(sz)=%s\n", debugstr_w((LPCWSTR)lpbData));
2438 break;
2439 case REG_BINARY:
2440 TRACE(reg," Data(binary)\n");
2441 break;
2442 case REG_DWORD:
2443 TRACE(reg," Data(dword)=%lx\n", (DWORD)lpbData);
2444 break;
2445 default:
2446 TRACE(reg,"Unknown type: %ld\n", dwType);
2449 lpkey = lookup_hkey( hkey );
2450 if (!lpkey)
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)
2459 break;
2460 } else {
2461 for (i=0;i<lpkey->nrofvalues;i++)
2462 if ( lpkey->values[i].name &&
2463 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2465 break;
2467 if (i==lpkey->nrofvalues) {
2468 lpkey->values = (LPKEYVALUE)xrealloc(
2469 lpkey->values,
2470 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2472 lpkey->nrofvalues++;
2473 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2475 if (lpkey->values[i].name==NULL) {
2476 if (lpszValueName)
2477 lpkey->values[i].name = strdupW(lpszValueName);
2478 else
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,
2498 DWORD cbData )
2500 LPBYTE buf;
2501 LPWSTR lpszValueNameW;
2502 DWORD ret;
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;
2510 } else
2511 buf=lpbData;
2512 if (lpszValueName)
2513 lpszValueNameW = strdupA2W(lpszValueName);
2514 else
2515 lpszValueNameW = NULL;
2516 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2517 if (lpszValueNameW)
2518 free(lpszValueNameW);
2519 if (buf!=lpbData)
2520 free(buf);
2521 return ret;
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,
2534 cbData );
2538 /******************************************************************************
2539 * RegSetValue32W [ADVAPI32.171]
2541 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2542 LPCWSTR lpszData, DWORD cbData )
2544 HKEY xhkey;
2545 DWORD ret;
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)
2553 return ret;
2554 } else
2555 xhkey=hkey;
2556 if (dwType!=REG_SZ) {
2557 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2558 dwType=REG_SZ;
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);
2567 if (hkey!=xhkey)
2568 RegCloseKey(xhkey);
2569 return ret;
2573 /******************************************************************************
2574 * RegSetValue32A [ADVAPI32.168]
2577 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2578 LPCSTR lpszData, DWORD cbData )
2580 DWORD ret;
2581 HKEY xhkey;
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)
2587 return ret;
2588 } else
2589 xhkey=hkey;
2591 if (dwType!=REG_SZ) {
2592 TRACE(reg,"dwType=%ld!\n",dwType);
2593 dwType=REG_SZ;
2595 if (cbData!=strlen(lpszData)+1)
2596 cbData=strlen(lpszData)+1;
2597 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2598 if (xhkey!=hkey)
2599 RegCloseKey(xhkey);
2600 return ret;
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);
2617 * Key Enumeration
2619 * Callpath:
2620 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2621 * RegEnumKey32W -> RegEnumKeyEx32W
2625 /******************************************************************************
2626 * RegEnumKeyEx32W [ADVAPI32.139]
2628 * PARAMS
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,
2641 FILETIME *ft )
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 );
2649 if (!lpkey)
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) {
2658 iSubkey--;
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);
2668 if (*lpcchName)
2669 *lpcchName = lstrlen32W(lpszName);
2671 if (lpszClass) {
2672 /* FIXME: what should we write into it? */
2673 *lpszClass = 0;
2674 *lpcchClass = 2;
2676 return ERROR_SUCCESS;
2680 /******************************************************************************
2681 * RegEnumKey32W [ADVAPI32.140]
2683 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2684 DWORD lpcchName )
2686 FILETIME ft;
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,
2699 FILETIME *ft )
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
2708 if (lpszName) {
2709 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2710 lpcchNameW = *lpcchName;
2711 } else {
2712 lpszNameW = NULL;
2713 lpcchNameW = 0;
2715 if (lpszClass) {
2716 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2717 lpcchClassW = *lpcchClass;
2718 } else {
2719 lpszClassW =0;
2720 lpcchClassW=0;
2722 ret=RegEnumKeyEx32W(
2723 hkey,
2724 iSubkey,
2725 lpszNameW,
2726 &lpcchNameW,
2727 lpdwReserved,
2728 lpszClassW,
2729 &lpcchClassW,
2732 if (ret==ERROR_SUCCESS) {
2733 lstrcpyWtoA(lpszName,lpszNameW);
2734 *lpcchName=strlen(lpszName);
2735 if (lpszClassW) {
2736 lstrcpyWtoA(lpszClass,lpszClassW);
2737 *lpcchClass=strlen(lpszClass);
2740 if (lpszNameW)
2741 free(lpszNameW);
2742 if (lpszClassW)
2743 free(lpszClassW);
2744 return ret;
2748 /******************************************************************************
2749 * RegEnumKey32A [ADVAPI32.137]
2751 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2752 DWORD lpcchName )
2754 FILETIME ft;
2756 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2757 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2758 NULL, &ft );
2762 /******************************************************************************
2763 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2765 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2766 DWORD lpcchName )
2768 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2769 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2774 * Enumerate Registry Values
2776 * Callpath:
2777 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2781 /******************************************************************************
2782 * RegEnumValue32W [ADVAPI32.142]
2784 * PARAMS
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,
2800 LPDWORD lpcbData )
2802 LPKEYSTRUCT lpkey;
2803 LPKEYVALUE val;
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 );
2809 if (!lpkey)
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;
2818 if (val->name) {
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);
2825 } else {
2826 *lpszValue = 0;
2827 *lpcchValue = 0;
2830 /* Can be NULL if the type code is not required */
2831 if (lpdwType)
2832 *lpdwType = val->type;
2834 if (lpbData) {
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,
2850 LPDWORD lpcbData )
2852 LPWSTR lpszValueW;
2853 LPBYTE lpbDataW;
2854 DWORD ret,lpcbDataW;
2855 DWORD dwType;
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);
2861 if (lpbData) {
2862 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2863 lpcbDataW = *lpcbData;
2864 } else
2865 lpbDataW = NULL;
2867 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2868 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2870 if (lpdwType)
2871 *lpdwType = dwType;
2873 if (ret==ERROR_SUCCESS) {
2874 lstrcpyWtoA(lpszValue,lpszValueW);
2875 if (lpbData) {
2876 if ((1<<dwType) & UNICONVMASK) {
2877 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2878 } else {
2879 if (lpcbDataW > *lpcbData)
2880 ret = ERROR_MORE_DATA;
2881 else
2882 memcpy(lpbData,lpbDataW,lpcbDataW);
2884 *lpcbData = lpcbDataW;
2887 if (lpbDataW) free(lpbDataW);
2888 if (lpszValueW) free(lpszValueW);
2889 return ret;
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,
2899 LPDWORD lpcbData )
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
2912 * PARAMS
2913 * hkey [I] Handle of key to close
2915 * RETURNS
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
2924 closed */
2925 if (is_standard_hkey(hkey))
2926 return ERROR_SUCCESS;
2928 return remove_handle(hkey);
2933 * Delete registry key
2935 * Callpath:
2936 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2940 /******************************************************************************
2941 * RegDeleteKey32W [ADVAPI32.134]
2943 * PARAMS
2944 * hkey [I] Handle to open key
2945 * lpszSubKey [I] Name of subkey to delete
2947 * RETURNS
2948 * Success: ERROR_SUCCESS
2949 * Failure: Error code
2951 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
2953 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2954 LPWSTR *wps;
2955 int wpc,i;
2957 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
2959 lpNextKey = lookup_hkey(hkey);
2960 if (!lpNextKey)
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);
2969 i = 0;
2970 lpxkey = lpNextKey;
2971 while (i<wpc-1) {
2972 lpxkey=lpNextKey->nextsub;
2973 while (lpxkey) {
2974 TRACE(reg, " Scanning [%s]\n",
2975 debugstr_w(lpxkey->keyname));
2976 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2977 break;
2978 lpxkey=lpxkey->next;
2980 if (!lpxkey) {
2981 FREE_KEY_PATH;
2982 TRACE(reg, " Not found.\n");
2983 /* not found is success */
2984 return ERROR_SUCCESS;
2986 i++;
2987 lpNextKey = lpxkey;
2989 lpxkey = lpNextKey->nextsub;
2990 lplpPrevKey = &(lpNextKey->nextsub);
2991 while (lpxkey) {
2992 TRACE(reg, " Scanning [%s]\n",
2993 debugstr_w(lpxkey->keyname));
2994 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2995 break;
2996 lplpPrevKey = &(lpxkey->next);
2997 lpxkey = lpxkey->next;
3000 if (!lpxkey) {
3001 FREE_KEY_PATH;
3002 WARN(reg , " Not found.\n");
3003 return ERROR_FILE_NOT_FOUND;
3006 if (lpxkey->nextsub) {
3007 FREE_KEY_PATH;
3008 WARN(reg , " Not empty.\n");
3009 return ERROR_CANTWRITE;
3011 *lplpPrevKey = lpxkey->next;
3012 free(lpxkey->keyname);
3013 if (lpxkey->class)
3014 free(lpxkey->class);
3015 if (lpxkey->values)
3016 free(lpxkey->values);
3017 free(lpxkey);
3018 FREE_KEY_PATH;
3019 TRACE(reg, " Done.\n");
3020 return ERROR_SUCCESS;
3024 /******************************************************************************
3025 * RegDeleteKey32A [ADVAPI32.133]
3027 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3029 LPWSTR lpszSubKeyW;
3030 DWORD ret;
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);
3036 return ret;
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
3053 * Callpath:
3054 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3058 /******************************************************************************
3059 * RegDeleteValue32W [ADVAPI32.136]
3061 * PARAMS
3062 * hkey [I]
3063 * lpszValue [I]
3065 * RETURNS
3067 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3069 DWORD i;
3070 LPKEYSTRUCT lpkey;
3071 LPKEYVALUE val;
3073 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3075 lpkey = lookup_hkey( hkey );
3076 if (!lpkey)
3077 return ERROR_INVALID_HANDLE;
3079 if (lpszValue) {
3080 for (i=0;i<lpkey->nrofvalues;i++)
3081 if ( lpkey->values[i].name &&
3082 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3084 break;
3085 } else {
3086 for (i=0;i<lpkey->nrofvalues;i++)
3087 if (lpkey->values[i].name==NULL)
3088 break;
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);
3097 memcpy(
3098 lpkey->values+i,
3099 lpkey->values+i+1,
3100 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3102 lpkey->values = (LPKEYVALUE)xrealloc(
3103 lpkey->values,
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 )
3116 LPWSTR lpszValueW;
3117 DWORD ret;
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);
3123 return ret;
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
3141 * PARAMS
3142 * hkey [I] Handle of key to write
3144 * RETURNS
3145 * Success: ERROR_SUCCESS
3146 * Failure: Error code
3148 DWORD WINAPI RegFlushKey( HKEY hkey )
3150 LPKEYSTRUCT lpkey;
3151 BOOL32 ret;
3153 TRACE(reg, "(%x)\n", hkey);
3155 lpkey = lookup_hkey( hkey );
3156 if (!lpkey)
3157 return ERROR_INVALID_HANDLE;
3159 ERR(reg, "What is the correct filename?\n");
3161 ret = _savereg( lpkey, "foo.bar", TRUE);
3163 if( ret ) {
3164 return ERROR_SUCCESS;
3165 } else
3166 return ERROR_UNKNOWN; /* FIXME */
3170 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3173 /******************************************************************************
3174 * RegQueryInfoKey32W [ADVAPI32.153]
3176 * PARAMS
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
3188 * ft
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;
3205 int i;
3207 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3208 lpkey = lookup_hkey(hkey);
3209 if (!lpkey)
3210 return ERROR_INVALID_HANDLE;
3211 if (lpszClass) {
3212 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3213 return ERROR_INVALID_PARAMETER;
3215 /* either lpcchClass is valid or this is win95 and lpcchClass
3216 could be invalid */
3217 if (lpkey->class) {
3218 DWORD classLen = lstrlen32W(lpkey->class);
3220 if (lpcchClass && classLen+1>*lpcchClass) {
3221 *lpcchClass=classLen+1;
3222 return ERROR_MORE_DATA;
3224 if (lpcchClass)
3225 *lpcchClass=classLen;
3226 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3227 } else {
3228 *lpszClass = 0;
3229 if (lpcchClass)
3230 *lpcchClass = 0;
3232 } else {
3233 if (lpcchClass)
3234 *lpcchClass = lstrlen32W(lpkey->class);
3236 lpxkey=lpkey->nextsub;
3237 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3238 while (lpxkey) {
3239 nrofkeys++;
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)
3252 maxvdata=val->len;
3254 if (!maxclass) maxclass = 1;
3255 if (!maxvname) maxvname = 1;
3256 if (lpcValues)
3257 *lpcValues = lpkey->nrofvalues;
3258 if (lpcSubKeys)
3259 *lpcSubKeys = nrofkeys;
3260 if (lpcchMaxSubkey)
3261 *lpcchMaxSubkey = maxsubkey;
3262 if (lpcchMaxClass)
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;
3283 DWORD ret;
3285 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3286 if (lpszClass) {
3287 if (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);
3296 } else
3297 lpszClassW = NULL;
3298 ret=RegQueryInfoKey32W(
3299 hkey,
3300 lpszClassW,
3301 lpcchClass,
3302 lpdwReserved,
3303 lpcSubKeys,
3304 lpcchMaxSubkey,
3305 lpcchMaxClass,
3306 lpcValues,
3307 lpcchMaxValueName,
3308 lpccbMaxValueData,
3309 lpcbSecurityDescriptor,
3312 if (ret==ERROR_SUCCESS && lpszClass)
3313 lstrcpyWtoA(lpszClass,lpszClassW);
3314 if (lpszClassW)
3315 free(lpszClassW);
3316 return ret;
3320 /******************************************************************************
3321 * RegConnectRegistry32W [ADVAPI32.128]
3323 * PARAMS
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,
3329 LPHKEY phkResult )
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 )
3348 DWORD ret;
3349 LPWSTR machineW = strdupA2W(machine);
3350 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3351 free(machineW);
3352 return ret;
3356 /******************************************************************************
3357 * RegGetKeySecurity [ADVAPI32.144]
3358 * Retrieves a copy of security descriptor protecting the registry key
3360 * PARAMS
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
3366 * RETURNS
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 )
3375 LPKEYSTRUCT lpkey;
3377 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3378 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3380 lpkey = lookup_hkey( hkey );
3381 if (!lpkey)
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.???]
3399 * PARAMS
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 )
3406 LPKEYSTRUCT lpkey;
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 );
3414 if (!lpkey)
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 )
3429 LONG ret;
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);
3435 return ret;
3439 /******************************************************************************
3440 * RegNotifyChangeKeyValue [ADVAPI32.???]
3442 * PARAMS
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,
3451 BOOL32 fAsync )
3453 LPKEYSTRUCT lpkey;
3454 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3455 hEvent,fAsync);
3457 lpkey = lookup_hkey( hkey );
3458 if (!lpkey)
3459 return ERROR_INVALID_HANDLE;
3461 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3462 hEvent,fAsync);
3464 return ERROR_SUCCESS;
3468 /******************************************************************************
3469 * RegUnLoadKey32W [ADVAPI32.173]
3471 * PARAMS
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 )
3487 LONG ret;
3488 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3489 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3490 if(lpSubKeyW) free(lpSubKeyW);
3491 return ret;
3495 /******************************************************************************
3496 * RegSetKeySecurity [ADVAPI32.167]
3498 * PARAMS
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 )
3506 LPKEYSTRUCT lpkey;
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)) {
3515 /* Param OK */
3516 } else
3517 return ERROR_INVALID_PARAMETER;
3519 if (!pSecurityDesc)
3520 return ERROR_INVALID_PARAMETER;
3522 lpkey = lookup_hkey( hkey );
3523 if (!lpkey)
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]
3535 * PARAMS
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 )
3543 LPKEYSTRUCT lpkey;
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 );
3552 if (!lpkey)
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 )
3567 LONG ret;
3568 LPWSTR lpFileW = strdupA2W(lpFile);
3569 ret = RegSaveKey32W( hkey, lpFileW, sa );
3570 free(lpFileW);
3571 return ret;
3575 /******************************************************************************
3576 * RegRestoreKey32W [ADVAPI32.164]
3578 * PARAMS
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 )
3585 LPKEYSTRUCT lpkey;
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 );
3594 if (!lpkey)
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 )
3610 LONG ret;
3611 LPWSTR lpFileW = strdupA2W(lpFile);
3612 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3613 if(lpFileW) free(lpFileW);
3614 return ret;
3618 /******************************************************************************
3619 * RegReplaceKey32W [ADVAPI32.162]
3621 * PARAMS
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,
3628 LPCWSTR lpOldFile )
3630 LPKEYSTRUCT lpkey;
3632 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3633 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3635 lpkey = lookup_hkey( hkey );
3636 if (!lpkey)
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,
3650 LPCSTR lpOldFile )
3652 LONG ret;
3653 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3654 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3655 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3656 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3657 free(lpOldFileW);
3658 free(lpNewFileW);
3659 free(lpSubKeyW);
3660 return ret;