Small fixes.
[wine/dcerpc.git] / misc / registry.c
blob67ac2461320d944010734d75696098f144a9dac4
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"
42 static void REGISTRY_Init();
43 /* FIXME: following defines should be configured global ... */
45 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
46 #define WINE_PREFIX "/.wine"
47 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
48 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
50 /* relative in ~user/.wine/ : */
51 #define SAVE_CURRENT_USER "user.reg"
52 #define SAVE_LOCAL_MACHINE "system.reg"
54 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
55 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57 /* one value of a key */
58 typedef struct tagKEYVALUE
60 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
61 DWORD type; /* type of value */
62 DWORD len; /* length of data in BYTEs */
63 DWORD lastmodified; /* time of seconds since 1.1.1970 */
64 LPBYTE data; /* content, may be strings, binaries, etc. */
65 } KEYVALUE,*LPKEYVALUE;
67 /* a registry key */
68 typedef struct tagKEYSTRUCT
70 LPWSTR keyname; /* name of THIS key (UNICODE) */
71 DWORD flags; /* flags. */
72 LPWSTR class;
73 /* values */
74 DWORD nrofvalues; /* nr of values in THIS key */
75 LPKEYVALUE values; /* values in THIS key */
76 /* key management pointers */
77 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
78 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
79 } KEYSTRUCT, *LPKEYSTRUCT;
82 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
83 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
84 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
85 static KEYSTRUCT *key_users=NULL; /* all users? */
87 /* dynamic, not saved */
88 static KEYSTRUCT *key_performance_data=NULL;
89 static KEYSTRUCT *key_current_config=NULL;
90 static KEYSTRUCT *key_dyn_data=NULL;
92 /* what valuetypes do we need to convert? */
93 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
96 static struct openhandle {
97 LPKEYSTRUCT lpkey;
98 HKEY hkey;
99 REGSAM accessmask;
100 } *openhandles=NULL;
101 static int nrofopenhandles=0;
102 /* Starts after 1 because 0,1 are reserved for Win16 */
103 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
104 HKEYs for remote registry access */
105 static int currenthandle=2;
109 * QUESTION
110 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
111 * If so, can we remove them?
112 * ANSWER
113 * No, the memory handling functions are called very often in here,
114 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
115 * loading 100 times slower. -MM
117 static LPWSTR strdupA2W(LPCSTR src)
119 if(src) {
120 LPWSTR dest=xmalloc(2*strlen(src)+2);
121 lstrcpyAtoW(dest,src);
122 return dest;
124 return NULL;
127 static LPWSTR strdupW(LPCWSTR a) {
128 LPWSTR b;
129 int len;
131 if(a) {
132 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
133 b=(LPWSTR)xmalloc(len);
134 memcpy(b,a,len);
135 return b;
137 return NULL;
140 LPWSTR strcvtA2W(LPCSTR src, int nchars)
143 LPWSTR dest = xmalloc (2 * nchars + 2);
145 lstrcpynAtoW(dest,src,nchars+1);
146 dest[nchars] = 0;
147 return dest;
151 /******************************************************************************
152 * is_standard_hkey [Internal]
153 * Determines if a hkey is a standard key
155 static BOOL32 is_standard_hkey( HKEY hkey )
157 switch(hkey) {
158 case 0x00000000:
159 case 0x00000001:
160 case HKEY_CLASSES_ROOT:
161 case HKEY_CURRENT_CONFIG:
162 case HKEY_CURRENT_USER:
163 case HKEY_LOCAL_MACHINE:
164 case HKEY_USERS:
165 case HKEY_PERFORMANCE_DATA:
166 case HKEY_DYN_DATA:
167 return TRUE;
168 default:
169 return FALSE;
173 /******************************************************************************
174 * add_handle [Internal]
176 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
178 int i;
180 TRACE(reg,"(%x,%p,%lx)\n",hkey,lpkey,accessmask);
181 /* Check for duplicates */
182 for (i=0;i<nrofopenhandles;i++) {
183 if (openhandles[i].lpkey==lpkey) {
184 /* This is not really an error - the user is allowed to create
185 two (or more) handles to the same key */
186 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
188 if (openhandles[i].hkey==hkey) {
189 WARN(reg, "Adding handle %x twice\n",hkey);
192 openhandles=xrealloc( openhandles,
193 sizeof(struct openhandle)*(nrofopenhandles+1));
195 openhandles[i].lpkey = lpkey;
196 openhandles[i].hkey = hkey;
197 openhandles[i].accessmask = accessmask;
198 nrofopenhandles++;
202 /******************************************************************************
203 * get_handle [Internal]
205 * RETURNS
206 * Success: Pointer to key
207 * Failure: NULL
209 static LPKEYSTRUCT get_handle( HKEY hkey )
211 int i;
213 for (i=0; i<nrofopenhandles; i++)
214 if (openhandles[i].hkey == hkey)
215 return openhandles[i].lpkey;
216 WARN(reg, "Could not find handle %x\n",hkey);
217 return NULL;
221 /******************************************************************************
222 * remove_handle [Internal]
224 * PARAMS
225 * hkey [I] Handle of key to remove
227 * RETURNS
228 * Success: ERROR_SUCCESS
229 * Failure: ERROR_INVALID_HANDLE
231 static DWORD remove_handle( HKEY hkey )
233 int i;
235 for (i=0;i<nrofopenhandles;i++)
236 if (openhandles[i].hkey==hkey)
237 break;
239 if (i == nrofopenhandles) {
240 WARN(reg, "Could not find handle %x\n",hkey);
241 return ERROR_INVALID_HANDLE;
244 memcpy( openhandles+i,
245 openhandles+i+1,
246 sizeof(struct openhandle)*(nrofopenhandles-i-1)
248 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
249 nrofopenhandles--;
250 return ERROR_SUCCESS;
253 /******************************************************************************
254 * lookup_hkey [Internal]
256 * Just as the name says. Creates the root keys on demand, so we can call the
257 * Reg* functions at any time.
259 * RETURNS
260 * Success: Pointer to key structure
261 * Failure: NULL
263 #define ADD_ROOT_KEY(xx) \
264 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
265 memset(xx,'\0',sizeof(KEYSTRUCT));\
266 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
268 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
270 switch (hkey) {
271 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
272 * some programs. Do not remove those cases. -MM
274 case 0x00000000:
275 case 0x00000001:
276 case HKEY_CLASSES_ROOT: {
277 if (!key_classes_root) {
278 HKEY cl_r_hkey;
280 /* calls lookup_hkey recursively, TWICE */
281 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
282 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
283 exit(1);
285 key_classes_root = lookup_hkey(cl_r_hkey);
287 return key_classes_root;
289 case HKEY_CURRENT_USER:
290 if (!key_current_user) {
291 HKEY c_u_hkey;
292 struct passwd *pwd;
294 pwd=getpwuid(getuid());
295 /* calls lookup_hkey recursively, TWICE */
296 if (pwd && pwd->pw_name) {
297 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
298 ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
299 exit(1);
301 key_current_user = lookup_hkey(c_u_hkey);
302 } else {
303 /* nothing found, use standalone */
304 ADD_ROOT_KEY(key_current_user);
307 return key_current_user;
308 case HKEY_LOCAL_MACHINE:
309 if (!key_local_machine) {
310 ADD_ROOT_KEY(key_local_machine);
311 REGISTRY_Init();
313 return key_local_machine;
314 case HKEY_USERS:
315 if (!key_users) {
316 ADD_ROOT_KEY(key_users);
318 return key_users;
319 case HKEY_PERFORMANCE_DATA:
320 if (!key_performance_data) {
321 ADD_ROOT_KEY(key_performance_data);
323 return key_performance_data;
324 case HKEY_DYN_DATA:
325 if (!key_dyn_data) {
326 ADD_ROOT_KEY(key_dyn_data);
328 return key_dyn_data;
329 case HKEY_CURRENT_CONFIG:
330 if (!key_current_config) {
331 ADD_ROOT_KEY(key_current_config);
333 return key_current_config;
334 default:
335 return get_handle(hkey);
337 /*NOTREACHED*/
339 #undef ADD_ROOT_KEY
340 /* so we don't accidently access them ... */
341 #define key_current_config NULL NULL
342 #define key_current_user NULL NULL
343 #define key_users NULL NULL
344 #define key_local_machine NULL NULL
345 #define key_classes_root NULL NULL
346 #define key_dyn_data NULL NULL
347 #define key_performance_data NULL NULL
349 /******************************************************************************
350 * split_keypath [Internal]
351 * splits the unicode string 'wp' into an array of strings.
352 * the array is allocated by this function.
353 * Free the array using FREE_KEY_PATH
355 * PARAMS
356 * wp [I] String to split up
357 * wpv [O] Array of pointers to strings
358 * wpc [O] Number of components
360 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
362 int i,j,len;
363 LPWSTR ws;
365 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
367 ws = HEAP_strdupW( SystemHeap, 0, wp );
369 /* We know we have at least one substring */
370 *wpc = 1;
372 /* Replace each backslash with NULL, and increment the count */
373 for (i=0;ws[i];i++) {
374 if (ws[i]=='\\') {
375 ws[i]=0;
376 (*wpc)++;
380 len = i;
382 /* Allocate the space for the array of pointers, leaving room for the
383 NULL at the end */
384 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
385 (*wpv)[0]= ws;
387 /* Assign each pointer to the appropriate character in the string */
388 j = 1;
389 for (i=1;i<len;i++)
390 if (ws[i-1]==0) {
391 (*wpv)[j++]=ws+i;
392 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
395 (*wpv)[j]=NULL;
397 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
402 /******************************************************************************
403 * REGISTRY_Init [Internal]
404 * Registry initialisation, allocates some default keys.
406 static void REGISTRY_Init() {
407 HKEY hkey;
408 char buf[200];
410 TRACE(reg,"(void)\n");
412 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
413 RegCloseKey(hkey);
415 /* This was an Open, but since it is called before the real registries
416 are loaded, it was changed to a Create - MTB 980507*/
417 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
418 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
419 RegCloseKey(hkey);
421 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
422 * CurrentVersion
423 * CurrentBuildNumber
424 * CurrentType
425 * string RegisteredOwner
426 * string RegisteredOrganization
429 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
430 * string SysContact
431 * string SysLocation
432 * SysServices
434 if (-1!=gethostname(buf,200)) {
435 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
436 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
437 RegCloseKey(hkey);
442 /************************ SAVE Registry Function ****************************/
444 #define REGISTRY_SAVE_VERSION 0x00000001
446 /* Registry saveformat:
447 * If you change it, increase above number by 1, which will flush
448 * old registry database files.
450 * Global:
451 * "WINE REGISTRY Version %d"
452 * subkeys....
453 * Subkeys:
454 * keyname
455 * valuename=lastmodified,type,data
456 * ...
457 * subkeys
458 * ...
459 * keyname,valuename,stringdata:
460 * the usual ascii characters from 0x00-0xff (well, not 0x00)
461 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
462 * ( "=\\\t" escaped in \uXXXX form.)
463 * type,lastmodified:
464 * int
466 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
468 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
469 * SaveOnlyUpdatedKeys=yes
472 /******************************************************************************
473 * _save_check_tainted [Internal]
475 static int _save_check_tainted( LPKEYSTRUCT lpkey )
477 int tainted;
479 if (!lpkey)
480 return 0;
481 if (lpkey->flags & REG_OPTION_TAINTED)
482 tainted = 1;
483 else
484 tainted = 0;
485 while (lpkey) {
486 if (_save_check_tainted(lpkey->nextsub)) {
487 lpkey->flags |= REG_OPTION_TAINTED;
488 tainted = 1;
490 lpkey = lpkey->next;
492 return tainted;
495 /******************************************************************************
496 * _save_USTRING [Internal]
498 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
500 LPWSTR s;
501 int doescape;
503 if (wstr==NULL)
504 return;
505 s=wstr;
506 while (*s) {
507 doescape=0;
508 if (*s>0xff)
509 doescape = 1;
510 if (*s=='\n')
511 doescape = 1;
512 if (escapeeq && *s=='=')
513 doescape = 1;
514 if (*s=='\\')
515 fputc(*s,F); /* if \\ then put it twice. */
516 if (doescape)
517 fprintf(F,"\\u%04x",*((unsigned short*)s));
518 else
519 fputc(*s,F);
520 s++;
524 /******************************************************************************
525 * _savesubkey [Internal]
527 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
529 LPKEYSTRUCT lpxkey;
530 int i,tabs,j;
532 lpxkey = lpkey;
533 while (lpxkey) {
534 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
535 (all || (lpxkey->flags & REG_OPTION_TAINTED))
537 for (tabs=level;tabs--;)
538 fputc('\t',F);
539 _save_USTRING(F,lpxkey->keyname,1);
540 fputs("\n",F);
541 for (i=0;i<lpxkey->nrofvalues;i++) {
542 LPKEYVALUE val=lpxkey->values+i;
544 for (tabs=level+1;tabs--;)
545 fputc('\t',F);
546 _save_USTRING(F,val->name,0);
547 fputc('=',F);
548 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
549 if ((1<<val->type) & UNICONVMASK)
550 _save_USTRING(F,(LPWSTR)val->data,0);
551 else
552 for (j=0;j<val->len;j++)
553 fprintf(F,"%02x",*((unsigned char*)val->data+j));
554 fputs("\n",F);
556 /* descend recursively */
557 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
558 return 0;
560 lpxkey=lpxkey->next;
562 return 1;
566 /******************************************************************************
567 * _savesubreg [Internal]
569 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
571 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
572 _save_check_tainted(lpkey->nextsub);
573 return _savesubkey(F,lpkey->nextsub,0,all);
577 /******************************************************************************
578 * _savereg [Internal]
580 static BOOL32 _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
582 FILE *F;
584 F=fopen(fn,"w");
585 if (F==NULL) {
586 WARN(reg,"Couldn't open %s for writing: %s\n",
587 fn,strerror(errno)
589 return FALSE;
591 if (!_savesubreg(F,lpkey,all)) {
592 fclose(F);
593 unlink(fn);
594 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
595 return FALSE;
597 fclose(F);
598 return TRUE;
602 /******************************************************************************
603 * SHELL_SaveRegistry [Internal]
605 void SHELL_SaveRegistry( void )
607 char *fn;
608 struct passwd *pwd;
609 char buf[4];
610 HKEY hkey;
611 int all;
613 TRACE(reg,"(void)\n");
615 all=0;
616 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
617 strcpy(buf,"yes");
618 } else {
619 DWORD len,junk,type;
621 len=4;
622 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
623 hkey,
624 VAL_SAVEUPDATED,
625 &junk,
626 &type,
627 buf,
628 &len
629 ))|| (type!=REG_SZ)
631 strcpy(buf,"yes");
632 RegCloseKey(hkey);
634 if (lstrcmpi32A(buf,"yes"))
635 all=1;
636 pwd=getpwuid(getuid());
637 if (pwd!=NULL && pwd->pw_dir!=NULL)
639 char *tmp;
641 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
642 strlen(SAVE_CURRENT_USER) + 2 );
643 strcpy(fn,pwd->pw_dir);
644 strcat(fn,WINE_PREFIX);
645 /* create the directory. don't care about errorcodes. */
646 mkdir(fn,0755); /* drwxr-xr-x */
647 strcat(fn,"/"SAVE_CURRENT_USER);
648 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
649 strcpy(tmp,fn);strcat(tmp,".tmp");
650 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
651 if (-1==rename(tmp,fn)) {
652 perror("rename tmp registry");
653 unlink(tmp);
656 free(tmp);
657 free(fn);
658 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
659 strcpy(fn,pwd->pw_dir);
660 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
661 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
662 strcpy(tmp,fn);strcat(tmp,".tmp");
663 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
664 if (-1==rename(tmp,fn)) {
665 perror("rename tmp registry");
666 unlink(tmp);
669 free(tmp);
670 free(fn);
671 } else
672 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
676 /************************ LOAD Registry Function ****************************/
680 /******************************************************************************
681 * _find_or_add_key [Internal]
683 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
685 LPKEYSTRUCT lpxkey,*lplpkey;
687 if ((!keyname) || (keyname[0]==0)) {
688 free(keyname);
689 return lpkey;
691 lplpkey= &(lpkey->nextsub);
692 lpxkey = *lplpkey;
693 while (lpxkey) {
694 if ( (lpxkey->keyname[0]==keyname[0]) &&
695 !lstrcmpi32W(lpxkey->keyname,keyname)
697 break;
698 lplpkey = &(lpxkey->next);
699 lpxkey = *lplpkey;
701 if (lpxkey==NULL) {
702 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
703 lpxkey = *lplpkey;
704 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
705 lpxkey->keyname = keyname;
706 } else
707 free(keyname);
708 return lpxkey;
711 /******************************************************************************
712 * _find_or_add_value [Internal]
714 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
715 LPBYTE data, DWORD len, DWORD lastmodified )
717 LPKEYVALUE val=NULL;
718 int i;
720 if (name && !*name) {/* empty string equals default (NULL) value */
721 free(name);
722 name = NULL;
725 for (i=0;i<lpkey->nrofvalues;i++) {
726 val=lpkey->values+i;
727 if (name==NULL) {
728 if (val->name==NULL)
729 break;
730 } else {
731 if ( val->name!=NULL &&
732 val->name[0]==name[0] &&
733 !lstrcmpi32W(val->name,name)
735 break;
738 if (i==lpkey->nrofvalues) {
739 lpkey->values = xrealloc(
740 lpkey->values,
741 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
743 val=lpkey->values+i;
744 memset(val,'\0',sizeof(KEYVALUE));
745 val->name = name;
746 } else {
747 if (name)
748 free(name);
750 if (val->lastmodified<lastmodified) {
751 val->lastmodified=lastmodified;
752 val->type = type;
753 val->len = len;
754 if (val->data)
755 free(val->data);
756 val->data = data;
757 } else
758 free(data);
762 /******************************************************************************
763 * _wine_read_line [Internal]
765 * reads a line including dynamically enlarging the readbuffer and throwing
766 * away comments
768 static int _wine_read_line( FILE *F, char **buf, int *len )
770 char *s,*curread;
771 int mylen,curoff;
773 curread = *buf;
774 mylen = *len;
775 **buf = '\0';
776 while (1) {
777 while (1) {
778 s=fgets(curread,mylen,F);
779 if (s==NULL)
780 return 0; /* EOF */
781 if (NULL==(s=strchr(curread,'\n'))) {
782 /* buffer wasn't large enough */
783 curoff = strlen(*buf);
784 *buf = xrealloc(*buf,*len*2);
785 curread = *buf + curoff;
786 mylen = *len; /* we filled up the buffer and
787 * got new '*len' bytes to fill
789 *len = *len * 2;
790 } else {
791 *s='\0';
792 break;
795 /* throw away comments */
796 if (**buf=='#' || **buf==';') {
797 curread = *buf;
798 mylen = *len;
799 continue;
801 if (s) /* got end of line */
802 break;
804 return 1;
808 /******************************************************************************
809 * _wine_read_USTRING [Internal]
811 * converts a char* into a UNICODE string (up to a special char)
812 * and returns the position exactly after that string
814 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
816 char *s;
817 LPWSTR ws;
819 /* read up to "=" or "\0" or "\n" */
820 s = buf;
821 if (*s == '=') {
822 /* empty string is the win3.1 default value(NULL)*/
823 *str = NULL;
824 return s;
826 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
827 ws = *str;
828 while (*s && (*s!='\n') && (*s!='=')) {
829 if (*s!='\\')
830 *ws++=*((unsigned char*)s++);
831 else {
832 s++;
833 if (*s=='\\') {
834 *ws++='\\';
835 s++;
836 continue;
838 if (*s!='u') {
839 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
840 *ws++='\\';
841 *ws++=*s++;
842 } else {
843 char xbuf[5];
844 int wc;
846 s++;
847 memcpy(xbuf,s,4);xbuf[4]='\0';
848 if (!sscanf(xbuf,"%x",&wc))
849 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
850 s+=4;
851 *ws++ =(unsigned short)wc;
855 *ws = 0;
856 ws = *str;
857 if (*ws)
858 *str = strdupW(*str);
859 else
860 *str = NULL;
861 free(ws);
862 return s;
866 /******************************************************************************
867 * _wine_loadsubkey [Internal]
869 * NOTES
870 * It seems like this is returning a boolean. Should it?
872 * RETURNS
873 * Success: 1
874 * Failure: 0
876 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
877 int *buflen, DWORD optflag )
879 LPKEYSTRUCT lpxkey;
880 int i;
881 char *s;
882 LPWSTR name;
884 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
885 *buflen, optflag);
887 lpkey->flags |= optflag;
889 /* Good. We already got a line here ... so parse it */
890 lpxkey = NULL;
891 while (1) {
892 i=0;s=*buf;
893 while (*s=='\t') {
894 s++;
895 i++;
897 if (i>level) {
898 if (lpxkey==NULL) {
899 WARN(reg,"Got a subhierarchy without resp. key?\n");
900 return 0;
902 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
903 continue;
906 /* let the caller handle this line */
907 if (i<level || **buf=='\0')
908 return 1;
910 /* it can be: a value or a keyname. Parse the name first */
911 s=_wine_read_USTRING(s,&name);
913 /* switch() default: hack to avoid gotos */
914 switch (0) {
915 default:
916 if (*s=='\0') {
917 lpxkey=_find_or_add_key(lpkey,name);
918 } else {
919 LPBYTE data;
920 int len,lastmodified,type;
922 if (*s!='=') {
923 WARN(reg,"Unexpected character: %c\n",*s);
924 break;
926 s++;
927 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
928 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
929 break;
931 /* skip the 2 , */
932 s=strchr(s,',');s++;
933 s=strchr(s,',');s++;
934 if ((1<<type) & UNICONVMASK) {
935 s=_wine_read_USTRING(s,(LPWSTR*)&data);
936 if (data)
937 len = lstrlen32W((LPWSTR)data)*2+2;
938 else
939 len = 0;
940 } else {
941 len=strlen(s)/2;
942 data = (LPBYTE)xmalloc(len+1);
943 for (i=0;i<len;i++) {
944 data[i]=0;
945 if (*s>='0' && *s<='9')
946 data[i]=(*s-'0')<<4;
947 if (*s>='a' && *s<='f')
948 data[i]=(*s-'a'+'\xa')<<4;
949 if (*s>='A' && *s<='F')
950 data[i]=(*s-'A'+'\xa')<<4;
951 s++;
952 if (*s>='0' && *s<='9')
953 data[i]|=*s-'0';
954 if (*s>='a' && *s<='f')
955 data[i]|=*s-'a'+'\xa';
956 if (*s>='A' && *s<='F')
957 data[i]|=*s-'A'+'\xa';
958 s++;
961 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
964 /* read the next line */
965 if (!_wine_read_line(F,buf,buflen))
966 return 1;
968 return 1;
972 /******************************************************************************
973 * _wine_loadsubreg [Internal]
975 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
977 int ver;
978 char *buf;
979 int buflen;
981 buf=xmalloc(10);buflen=10;
982 if (!_wine_read_line(F,&buf,&buflen)) {
983 free(buf);
984 return 0;
986 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
987 free(buf);
988 return 0;
990 if (ver!=REGISTRY_SAVE_VERSION) {
991 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
992 free(buf);
993 return 0;
995 if (!_wine_read_line(F,&buf,&buflen)) {
996 free(buf);
997 return 0;
999 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1000 free(buf);
1001 return 0;
1003 free(buf);
1004 return 1;
1008 /******************************************************************************
1009 * _wine_loadreg [Internal]
1011 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1013 FILE *F;
1015 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1017 F = fopen(fn,"rb");
1018 if (F==NULL) {
1019 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1020 return;
1022 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1023 fclose(F);
1024 unlink(fn);
1025 return;
1027 fclose(F);
1031 /******************************************************************************
1032 * _copy_registry [Internal]
1034 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1036 LPKEYSTRUCT lpxkey;
1037 int j;
1038 LPKEYVALUE valfrom;
1040 from=from->nextsub;
1041 while (from) {
1042 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1044 for (j=0;j<from->nrofvalues;j++) {
1045 LPWSTR name;
1046 LPBYTE data;
1048 valfrom = from->values+j;
1049 name=valfrom->name;
1050 if (name) name=strdupW(name);
1051 data=(LPBYTE)xmalloc(valfrom->len);
1052 memcpy(data,valfrom->data,valfrom->len);
1054 _find_or_add_value(
1055 lpxkey,
1056 name,
1057 valfrom->type,
1058 data,
1059 valfrom->len,
1060 valfrom->lastmodified
1063 _copy_registry(from,lpxkey);
1064 from = from->next;
1069 /* WINDOWS 95 REGISTRY LOADER */
1071 * Structure of a win95 registry database.
1072 * main header:
1073 * 0 : "CREG" - magic
1074 * 4 : DWORD version
1075 * 8 : DWORD offset_of_RGDB_part
1076 * 0C..0F: ? (someone fill in please)
1077 * 10: WORD number of RGDB blocks
1078 * 12: WORD ?
1079 * 14: WORD always 0000?
1080 * 16: WORD always 0001?
1081 * 18..1F: ? (someone fill in please)
1083 * 20: RGKN_section:
1084 * header:
1085 * 0 : "RGKN" - magic
1086 * 4 : DWORD offset to first RGDB section
1087 * 8 : DWORD offset to the root record
1088 * C..0x1B: ? (fill in)
1089 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1091 * Disk Key Entry Structure:
1092 * 00: DWORD - Free entry indicator(?)
1093 * 04: DWORD - Hash = sum of bytes of keyname
1094 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1095 * 0C: DWORD - disk address of PreviousLevel Key.
1096 * 10: DWORD - disk address of Next Sublevel Key.
1097 * 14: DWORD - disk address of Next Key (on same level).
1098 * DKEP>18: WORD - Nr, Low Significant part.
1099 * 1A: WORD - Nr, High Significant part.
1101 * The disk address always points to the nr part of the previous key entry
1102 * of the referenced key. Don't ask me why, or even if I got this correct
1103 * from staring at 1kg of hexdumps. (DKEP)
1105 * The High significant part of the structure seems to equal the number
1106 * of the RGDB section. The low significant part is a unique ID within
1107 * that RGDB section
1109 * There are two minor corrections to the position of that structure.
1110 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1111 * the DKE reread from there.
1112 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1113 * CPS - I have not experienced the above phenomenon in my registry files
1115 * RGDB_section:
1116 * 00: "RGDB" - magic
1117 * 04: DWORD offset to next RGDB section
1118 * 08: DWORD ?
1119 * 0C: WORD always 000d?
1120 * 0E: WORD RGDB block number
1121 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1122 * 14..1F: ?
1123 * 20.....: disk keys
1125 * disk key:
1126 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1127 * 08: WORD nrLS - low significant part of NR
1128 * 0A: WORD nrHS - high significant part of NR
1129 * 0C: DWORD bytesused - bytes used in this structure.
1130 * 10: WORD name_len - length of name in bytes. without \0
1131 * 12: WORD nr_of_values - number of values.
1132 * 14: char name[name_len] - name string. No \0.
1133 * 14+name_len: disk values
1134 * nextkeyoffset: ... next disk key
1136 * disk value:
1137 * 00: DWORD type - value type (hmm, could be WORD too)
1138 * 04: DWORD - unknown, usually 0
1139 * 08: WORD namelen - length of Name. 0 means name=NULL
1140 * 0C: WORD datalen - length of Data.
1141 * 10: char name[namelen] - name, no \0
1142 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1143 * 10+namelen+datalen: next values or disk key
1145 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1146 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1147 * structure) and reading another RGDB_section.
1148 * repeat until end of file.
1150 * An interesting relationship exists in RGDB_section. The value at offset
1151 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1152 * idea at the moment what this means. (Kevin Cozens)
1154 * FIXME: this description needs some serious help, yes.
1157 struct _w95keyvalue {
1158 unsigned long type;
1159 unsigned short datalen;
1160 char *name;
1161 unsigned char *data;
1162 unsigned long x1;
1163 int lastmodified;
1166 struct _w95key {
1167 char *name;
1168 int nrofvals;
1169 struct _w95keyvalue *values;
1170 struct _w95key *prevlvl;
1171 struct _w95key *nextsub;
1172 struct _w95key *next;
1176 struct _w95_info {
1177 char *rgknbuffer;
1178 int rgknsize;
1179 char *rgdbbuffer;
1180 int rgdbsize;
1181 int depth;
1182 int lastmodified;
1186 /******************************************************************************
1187 * _w95_processKey [Internal]
1189 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1190 int nrLS, int nrMS, struct _w95_info *info )
1193 /* Disk Key Header structure (RGDB part) */
1194 struct dkh {
1195 unsigned long nextkeyoff;
1196 unsigned short nrLS;
1197 unsigned short nrMS;
1198 unsigned long bytesused;
1199 unsigned short keynamelen;
1200 unsigned short values;
1201 unsigned long xx1;
1202 /* keyname */
1203 /* disk key values or nothing */
1205 /* Disk Key Value structure */
1206 struct dkv {
1207 unsigned long type;
1208 unsigned long x1;
1209 unsigned short valnamelen;
1210 unsigned short valdatalen;
1211 /* valname, valdata */
1215 struct dkh dkh;
1216 int bytesread = 0;
1217 char *rgdbdata = info->rgdbbuffer;
1218 int nbytes = info->rgdbsize;
1219 char *curdata = rgdbdata;
1220 char *end = rgdbdata + nbytes;
1221 int off_next_rgdb;
1222 char *next = rgdbdata;
1223 int nrgdb, i;
1224 LPKEYSTRUCT lpxkey;
1226 do {
1227 curdata = next;
1228 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1230 memcpy(&off_next_rgdb,curdata+4,4);
1231 next = curdata + off_next_rgdb;
1232 nrgdb = (int) *((short *)curdata + 7);
1234 } while (nrgdb != nrMS && (next < end));
1236 /* curdata now points to the start of the right RGDB section */
1237 curdata += 0x20;
1239 #define XREAD(whereto,len) \
1240 if ((curdata + len) <end) {\
1241 memcpy(whereto,curdata,len);\
1242 curdata+=len;\
1243 bytesread+=len;\
1246 while (curdata < next) {
1247 struct dkh *xdkh = curdata;
1249 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1250 if (xdkh->nrLS == nrLS) {
1251 memcpy(&dkh,xdkh,sizeof(dkh));
1252 curdata += sizeof(dkh);
1253 break;
1255 curdata += xdkh->nextkeyoff;
1258 if (dkh.nrLS != nrLS) return (NULL);
1260 if (nrgdb != dkh.nrMS)
1261 return (NULL);
1263 assert((dkh.keynamelen<2) || curdata[0]);
1264 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1265 curdata += dkh.keynamelen;
1267 for (i=0;i< dkh.values; i++) {
1268 struct dkv dkv;
1269 LPBYTE data;
1270 int len;
1271 LPWSTR name;
1273 XREAD(&dkv,sizeof(dkv));
1275 name = strcvtA2W(curdata, dkv.valnamelen);
1276 curdata += dkv.valnamelen;
1278 if ((1 << dkv.type) & UNICONVMASK) {
1279 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1280 len = 2*(dkv.valdatalen + 1);
1281 } else {
1282 /* I don't think we want to NULL terminate all data */
1283 data = xmalloc(dkv.valdatalen);
1284 memcpy (data, curdata, dkv.valdatalen);
1285 len = dkv.valdatalen;
1288 curdata += dkv.valdatalen;
1290 _find_or_add_value(
1291 lpxkey,
1292 name,
1293 dkv.type,
1294 data,
1295 len,
1296 info->lastmodified
1299 return (lpxkey);
1302 /******************************************************************************
1303 * _w95_walkrgkn [Internal]
1305 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1306 struct _w95_info *info )
1309 /* Disk Key Entry structure (RGKN part) */
1310 struct dke {
1311 unsigned long x1;
1312 unsigned long x2;
1313 unsigned long x3;/*usually 0xFFFFFFFF */
1314 unsigned long prevlvl;
1315 unsigned long nextsub;
1316 unsigned long next;
1317 unsigned short nrLS;
1318 unsigned short nrMS;
1319 } *dke = (struct dke *)off;
1320 LPKEYSTRUCT lpxkey;
1322 if (dke == NULL) {
1323 dke = (struct dke *) ((char *)info->rgknbuffer);
1326 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1327 /* XXX <-- This is a hack*/
1328 if (!lpxkey) {
1329 lpxkey = prevkey;
1332 if (dke->nextsub != -1 &&
1333 ((dke->nextsub - 0x20) < info->rgknsize)
1334 && (dke->nextsub > 0x20)) {
1336 _w95_walkrgkn(lpxkey,
1337 info->rgknbuffer + dke->nextsub - 0x20,
1338 info);
1341 if (dke->next != -1 &&
1342 ((dke->next - 0x20) < info->rgknsize) &&
1343 (dke->next > 0x20)) {
1344 _w95_walkrgkn(prevkey,
1345 info->rgknbuffer + dke->next - 0x20,
1346 info);
1349 return;
1353 /******************************************************************************
1354 * _w95_loadreg [Internal]
1356 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1358 HFILE32 hfd;
1359 char magic[5];
1360 unsigned long where,version,rgdbsection,end;
1361 struct _w95_info info;
1362 OFSTRUCT ofs;
1363 BY_HANDLE_FILE_INFORMATION hfdinfo;
1365 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1366 hfd=OpenFile32(fn,&ofs,OF_READ);
1367 if (hfd==HFILE_ERROR32)
1368 return;
1369 magic[4]=0;
1370 if (4!=_lread32(hfd,magic,4))
1371 return;
1372 if (strcmp(magic,"CREG")) {
1373 WARN(reg,"%s is not a w95 registry.\n",fn);
1374 return;
1376 if (4!=_lread32(hfd,&version,4))
1377 return;
1378 if (4!=_lread32(hfd,&rgdbsection,4))
1379 return;
1380 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1381 return;
1382 if (4!=_lread32(hfd,magic,4))
1383 return;
1384 if (strcmp(magic,"RGKN")) {
1385 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1386 return;
1389 /* STEP 1: Keylink structures */
1390 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1391 return;
1392 where = 0x40;
1393 end = rgdbsection;
1395 info.rgknsize = end - where;
1396 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1397 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1398 return;
1400 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1401 return;
1403 end = hfdinfo.nFileSizeLow;
1404 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1406 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1407 return;
1409 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1410 info.rgdbsize = end - rgdbsection;
1412 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1413 return;
1414 _lclose32(hfd);
1416 _w95_walkrgkn(lpkey, NULL, &info);
1418 free (info.rgdbbuffer);
1419 free (info.rgknbuffer);
1423 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1426 reghack - windows 3.11 registry data format demo program.
1428 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1429 a combined hash table and tree description, and finally a text table.
1431 The header is obvious from the struct header. The taboff1 and taboff2
1432 fields are always 0x20, and their usage is unknown.
1434 The 8-byte entry table has various entry types.
1436 tabent[0] is a root index. The second word has the index of the root of
1437 the directory.
1438 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1439 the index of the key/value that has that hash. Data with the same
1440 hash value are on a circular list. The other three words in the
1441 hash entry are always zero.
1442 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1443 entry: dirent and keyent/valent. They are identified by context.
1444 tabent[freeidx] is the first free entry. The first word in a free entry
1445 is the index of the next free entry. The last has 0 as a link.
1446 The other three words in the free list are probably irrelevant.
1448 Entries in text table are preceeded by a word at offset-2. This word
1449 has the value (2*index)+1, where index is the referring keyent/valent
1450 entry in the table. I have no suggestion for the 2* and the +1.
1451 Following the word, there are N bytes of data, as per the keyent/valent
1452 entry length. The offset of the keyent/valent entry is from the start
1453 of the text table to the first data byte.
1455 This information is not available from Microsoft. The data format is
1456 deduced from the reg.dat file by me. Mistakes may
1457 have been made. I claim no rights and give no guarantees for this program.
1459 Tor Sjøwall, tor@sn.no
1462 /* reg.dat header format */
1463 struct _w31_header {
1464 char cookie[8]; /* 'SHCC3.10' */
1465 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1466 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1467 unsigned long tabcnt; /* number of entries in index table */
1468 unsigned long textoff; /* offset of text part */
1469 unsigned long textsize; /* byte size of text part */
1470 unsigned short hashsize; /* hash size */
1471 unsigned short freeidx; /* free index */
1474 /* generic format of table entries */
1475 struct _w31_tabent {
1476 unsigned short w0, w1, w2, w3;
1479 /* directory tabent: */
1480 struct _w31_dirent {
1481 unsigned short sibling_idx; /* table index of sibling dirent */
1482 unsigned short child_idx; /* table index of child dirent */
1483 unsigned short key_idx; /* table index of key keyent */
1484 unsigned short value_idx; /* table index of value valent */
1487 /* key tabent: */
1488 struct _w31_keyent {
1489 unsigned short hash_idx; /* hash chain index for string */
1490 unsigned short refcnt; /* reference count */
1491 unsigned short length; /* length of string */
1492 unsigned short string_off; /* offset of string in text table */
1495 /* value tabent: */
1496 struct _w31_valent {
1497 unsigned short hash_idx; /* hash chain index for string */
1498 unsigned short refcnt; /* reference count */
1499 unsigned short length; /* length of string */
1500 unsigned short string_off; /* offset of string in text table */
1503 /* recursive helper function to display a directory tree */
1504 void
1505 __w31_dumptree( unsigned short idx,
1506 unsigned char *txt,
1507 struct _w31_tabent *tab,
1508 struct _w31_header *head,
1509 LPKEYSTRUCT lpkey,
1510 time_t lastmodified,
1511 int level
1513 struct _w31_dirent *dir;
1514 struct _w31_keyent *key;
1515 struct _w31_valent *val;
1516 LPKEYSTRUCT xlpkey = NULL;
1517 LPWSTR name,value;
1518 static char tail[400];
1520 while (idx!=0) {
1521 dir=(struct _w31_dirent*)&tab[idx];
1523 if (dir->key_idx) {
1524 key = (struct _w31_keyent*)&tab[dir->key_idx];
1526 memcpy(tail,&txt[key->string_off],key->length);
1527 tail[key->length]='\0';
1528 /* all toplevel entries AND the entries in the
1529 * toplevel subdirectory belong to \SOFTWARE\Classes
1531 if (!level && !lstrcmp32A(tail,".classes")) {
1532 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1533 idx=dir->sibling_idx;
1534 continue;
1536 name=strdupA2W(tail);
1538 xlpkey=_find_or_add_key(lpkey,name);
1540 /* only add if leaf node or valued node */
1541 if (dir->value_idx!=0||dir->child_idx==0) {
1542 if (dir->value_idx) {
1543 val=(struct _w31_valent*)&tab[dir->value_idx];
1544 memcpy(tail,&txt[val->string_off],val->length);
1545 tail[val->length]='\0';
1546 value=strdupA2W(tail);
1547 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1550 } else {
1551 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1553 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1554 idx=dir->sibling_idx;
1559 /******************************************************************************
1560 * _w31_loadreg [Internal]
1562 void _w31_loadreg() {
1563 HFILE32 hf;
1564 struct _w31_header head;
1565 struct _w31_tabent *tab;
1566 unsigned char *txt;
1567 int len;
1568 OFSTRUCT ofs;
1569 BY_HANDLE_FILE_INFORMATION hfinfo;
1570 time_t lastmodified;
1571 LPKEYSTRUCT lpkey;
1573 TRACE(reg,"(void)\n");
1575 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1576 if (hf==HFILE_ERROR32)
1577 return;
1579 /* read & dump header */
1580 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1581 ERR(reg, "reg.dat is too short.\n");
1582 _lclose32(hf);
1583 return;
1585 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1586 ERR(reg, "reg.dat has bad signature.\n");
1587 _lclose32(hf);
1588 return;
1591 len = head.tabcnt * sizeof(struct _w31_tabent);
1592 /* read and dump index table */
1593 tab = xmalloc(len);
1594 if (len!=_lread32(hf,tab,len)) {
1595 ERR(reg,"couldn't read %d bytes.\n",len);
1596 free(tab);
1597 _lclose32(hf);
1598 return;
1601 /* read text */
1602 txt = xmalloc(head.textsize);
1603 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1604 ERR(reg,"couldn't seek to textblock.\n");
1605 free(tab);
1606 free(txt);
1607 _lclose32(hf);
1608 return;
1610 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1611 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1612 free(tab);
1613 free(txt);
1614 _lclose32(hf);
1615 return;
1618 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1619 ERR(reg,"GetFileInformationByHandle failed?.\n");
1620 free(tab);
1621 free(txt);
1622 _lclose32(hf);
1623 return;
1625 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1626 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1627 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1628 free(tab);
1629 free(txt);
1630 _lclose32(hf);
1631 return;
1635 /**********************************************************************************
1636 * SHELL_LoadRegistry [Internal]
1638 void SHELL_LoadRegistry( void )
1640 char *fn;
1641 struct passwd *pwd;
1642 LPKEYSTRUCT lpkey;
1643 HKEY hkey;
1645 TRACE(reg,"(void)\n");
1647 /* Load windows 3.1 entries */
1648 _w31_loadreg();
1649 /* Load windows 95 entries */
1650 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1651 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1652 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1654 /* the global user default is loaded under HKEY_USERS\\.Default */
1655 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1656 lpkey = lookup_hkey(hkey);
1657 if(!lpkey)
1658 WARN(reg,"Could not create global user default key\n");
1659 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1661 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1662 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1663 RegCloseKey(hkey);
1665 /* the global machine defaults */
1666 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1668 /* load the user saved registries */
1670 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1672 pwd=getpwuid(getuid());
1673 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1674 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1675 strcpy(fn,pwd->pw_dir);
1676 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1677 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1678 free(fn);
1679 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1680 strcpy(fn,pwd->pw_dir);
1681 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1682 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1683 free(fn);
1684 } else
1685 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1686 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1687 DWORD junk,type,len;
1688 char data[5];
1690 len=4;
1691 if (( RegQueryValueEx32A(
1692 hkey,
1693 VAL_SAVEUPDATED,
1694 &junk,
1695 &type,
1696 data,
1697 &len
1698 )!=ERROR_SUCCESS) ||
1699 type != REG_SZ
1701 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1702 RegCloseKey(hkey);
1707 /********************* API FUNCTIONS ***************************************/
1709 * Open Keys.
1711 * All functions are stubs to RegOpenKeyEx32W where all the
1712 * magic happens.
1714 * Callpath:
1715 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1716 * RegOpenKey32W -> RegOpenKeyEx32W
1720 /******************************************************************************
1721 * RegOpenKeyEx32W [ADVAPI32.150]
1722 * Opens the specified key
1724 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1726 * PARAMS
1727 * hkey [I] Handle of open key
1728 * lpszSubKey [I] Name of subkey to open
1729 * dwReserved [I] Reserved - must be zero
1730 * samDesired [I] Security access mask
1731 * retkey [O] Address of handle of open key
1733 * RETURNS
1734 * Success: ERROR_SUCCESS
1735 * Failure: Error code
1737 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1738 REGSAM samDesired, LPHKEY retkey )
1740 LPKEYSTRUCT lpNextKey,lpxkey;
1741 LPWSTR *wps;
1742 int wpc,i;
1744 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1745 samDesired,retkey);
1747 lpNextKey = lookup_hkey( hkey );
1748 if (!lpNextKey)
1749 return ERROR_INVALID_HANDLE;
1751 if (!lpszSubKey || !*lpszSubKey) {
1752 /* Either NULL or pointer to empty string, so return a new handle
1753 to the original hkey */
1754 currenthandle += 2;
1755 add_handle(currenthandle,lpNextKey,samDesired);
1756 *retkey=currenthandle;
1757 return ERROR_SUCCESS;
1760 if (lpszSubKey[0] == '\\') {
1761 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1762 return ERROR_BAD_PATHNAME;
1765 split_keypath(lpszSubKey,&wps,&wpc);
1766 i = 0;
1767 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1768 lpxkey = lpNextKey;
1770 while (wps[i]) {
1771 lpxkey=lpNextKey->nextsub;
1772 while (lpxkey) {
1773 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1774 break;
1776 lpxkey=lpxkey->next;
1779 if (!lpxkey) {
1780 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1781 FREE_KEY_PATH;
1782 return ERROR_FILE_NOT_FOUND;
1784 i++;
1785 lpNextKey = lpxkey;
1788 currenthandle += 2;
1789 add_handle(currenthandle,lpxkey,samDesired);
1790 *retkey = currenthandle;
1791 TRACE(reg," Returning %x\n", currenthandle);
1792 FREE_KEY_PATH;
1793 return ERROR_SUCCESS;
1797 /******************************************************************************
1798 * RegOpenKeyEx32A [ADVAPI32.149]
1800 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1801 REGSAM samDesired, LPHKEY retkey )
1803 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1804 DWORD ret;
1806 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1807 samDesired,retkey);
1808 ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1809 free(lpszSubKeyW);
1810 return ret;
1814 /******************************************************************************
1815 * RegOpenKey32W [ADVAPI32.151]
1817 * PARAMS
1818 * hkey [I] Handle of open key
1819 * lpszSubKey [I] Address of name of subkey to open
1820 * retkey [O] Address of handle of open key
1822 * RETURNS
1823 * Success: ERROR_SUCCESS
1824 * Failure: Error code
1826 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1828 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1829 return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1833 /******************************************************************************
1834 * RegOpenKey32A [ADVAPI32.148]
1836 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1838 DWORD ret;
1839 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1840 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1841 ret = RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1842 free(lpszSubKeyW);
1843 return ret;
1847 /******************************************************************************
1848 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1850 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1852 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1853 return RegOpenKey32A( hkey, lpszSubKey, retkey );
1858 * Create keys
1860 * All those functions convert their respective
1861 * arguments and call RegCreateKeyExW at the end.
1863 * We stay away from the Ex functions as long as possible because there are
1864 * differences in the return values
1866 * Callpath:
1867 * RegCreateKeyEx32A \
1868 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1872 /******************************************************************************
1873 * RegCreateKeyEx32W [ADVAPI32.131]
1875 * PARAMS
1876 * hkey [I] Handle of an open key
1877 * lpszSubKey [I] Address of subkey name
1878 * dwReserved [I] Reserved - must be 0
1879 * lpszClass [I] Address of class string
1880 * fdwOptions [I] Special options flag
1881 * samDesired [I] Desired security access
1882 * lpSecAttribs [I] Address of key security structure
1883 * retkey [O] Address of buffer for opened handle
1884 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1886 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey,
1887 DWORD dwReserved, LPWSTR lpszClass,
1888 DWORD fdwOptions, REGSAM samDesired,
1889 LPSECURITY_ATTRIBUTES lpSecAttribs,
1890 LPHKEY retkey, LPDWORD lpDispos )
1892 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1893 LPWSTR *wps;
1894 int wpc,i;
1896 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1897 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1898 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1900 lpNextKey = lookup_hkey(hkey);
1901 if (!lpNextKey)
1902 return ERROR_INVALID_HANDLE;
1904 /* Check for valid options */
1905 switch(fdwOptions) {
1906 case REG_OPTION_NON_VOLATILE:
1907 case REG_OPTION_VOLATILE:
1908 case REG_OPTION_BACKUP_RESTORE:
1909 break;
1910 default:
1911 return ERROR_INVALID_PARAMETER;
1914 /* Sam has to be a combination of the following */
1915 if (!(samDesired &
1916 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
1917 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1918 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1919 return ERROR_INVALID_PARAMETER;
1921 if (!lpszSubKey || !*lpszSubKey) {
1922 currenthandle += 2;
1923 add_handle(currenthandle,lpNextKey,samDesired);
1924 *retkey=currenthandle;
1925 TRACE(reg, "Returning %x\n", currenthandle);
1926 lpNextKey->flags|=REG_OPTION_TAINTED;
1927 return ERROR_SUCCESS;
1930 if (lpszSubKey[0] == '\\') {
1931 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1932 return ERROR_BAD_PATHNAME;
1935 split_keypath(lpszSubKey,&wps,&wpc);
1936 i = 0;
1937 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1938 lpxkey = lpNextKey;
1939 while (wps[i]) {
1940 lpxkey=lpNextKey->nextsub;
1941 while (lpxkey) {
1942 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1943 break;
1944 lpxkey=lpxkey->next;
1946 if (!lpxkey)
1947 break;
1948 i++;
1949 lpNextKey = lpxkey;
1951 if (lpxkey) {
1952 currenthandle += 2;
1953 add_handle(currenthandle,lpxkey,samDesired);
1954 lpxkey->flags |= REG_OPTION_TAINTED;
1955 *retkey = currenthandle;
1956 TRACE(reg, "Returning %x\n", currenthandle);
1957 if (lpDispos)
1958 *lpDispos = REG_OPENED_EXISTING_KEY;
1959 FREE_KEY_PATH;
1960 return ERROR_SUCCESS;
1963 /* Good. Now the hard part */
1964 while (wps[i]) {
1965 lplpPrevKey = &(lpNextKey->nextsub);
1966 lpxkey = *lplpPrevKey;
1967 while (lpxkey) {
1968 lplpPrevKey = &(lpxkey->next);
1969 lpxkey = *lplpPrevKey;
1971 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1972 if (!*lplpPrevKey) {
1973 FREE_KEY_PATH;
1974 TRACE(reg, "Returning OUTOFMEMORY\n");
1975 return ERROR_OUTOFMEMORY;
1977 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1978 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
1979 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1980 (*lplpPrevKey)->next = NULL;
1981 (*lplpPrevKey)->nextsub = NULL;
1982 (*lplpPrevKey)->values = NULL;
1983 (*lplpPrevKey)->nrofvalues = 0;
1984 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1985 if (lpszClass)
1986 (*lplpPrevKey)->class = strdupW(lpszClass);
1987 else
1988 (*lplpPrevKey)->class = NULL;
1989 lpNextKey = *lplpPrevKey;
1990 i++;
1992 currenthandle += 2;
1993 add_handle(currenthandle,lpNextKey,samDesired);
1995 /*FIXME: flag handling correct? */
1996 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1997 if (lpszClass)
1998 lpNextKey->class = strdupW(lpszClass);
1999 else
2000 lpNextKey->class = NULL;
2001 *retkey = currenthandle;
2002 TRACE(reg, "Returning %x\n", currenthandle);
2003 if (lpDispos)
2004 *lpDispos = REG_CREATED_NEW_KEY;
2005 FREE_KEY_PATH;
2006 return ERROR_SUCCESS;
2010 /******************************************************************************
2011 * RegCreateKeyEx32A [ADVAPI32.130]
2013 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2014 LPSTR lpszClass, DWORD fdwOptions,
2015 REGSAM samDesired,
2016 LPSECURITY_ATTRIBUTES lpSecAttribs,
2017 LPHKEY retkey, LPDWORD lpDispos )
2019 LPWSTR lpszSubKeyW, lpszClassW;
2020 DWORD ret;
2022 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2023 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2024 retkey,lpDispos);
2026 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2027 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2029 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2030 fdwOptions, samDesired, lpSecAttribs, retkey,
2031 lpDispos );
2033 if(lpszSubKeyW) free(lpszSubKeyW);
2034 if(lpszClassW) free(lpszClassW);
2036 return ret;
2040 /******************************************************************************
2041 * RegCreateKey32W [ADVAPI32.132]
2043 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2045 DWORD junk;
2046 LPKEYSTRUCT lpNextKey;
2048 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2050 /* This check is here because the return value is different than the
2051 one from the Ex functions */
2052 lpNextKey = lookup_hkey(hkey);
2053 if (!lpNextKey)
2054 return ERROR_BADKEY;
2056 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
2057 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2058 retkey, &junk);
2062 /******************************************************************************
2063 * RegCreateKey32A [ADVAPI32.129]
2065 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2067 DWORD ret;
2068 LPWSTR lpszSubKeyW;
2070 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2071 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2072 ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2073 if(lpszSubKeyW) free(lpszSubKeyW);
2074 return ret;
2078 /******************************************************************************
2079 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2081 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2083 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2084 return RegCreateKey32A( hkey, lpszSubKey, retkey );
2089 * Query Value Functions
2090 * Win32 differs between keynames and valuenames.
2091 * multiple values may belong to one key, the special value
2092 * with name NULL is the default value used by the win31
2093 * compat functions.
2095 * Callpath:
2096 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2097 * RegQueryValue32W -> RegQueryValueEx32W
2101 /******************************************************************************
2102 * RegQueryValueEx32W [ADVAPI32.158]
2103 * Retrieves type and data for a specified name associated with an open key
2105 * PARAMS
2106 * hkey [I] Handle of key to query
2107 * lpValueName [I] Name of value to query
2108 * lpdwReserved [I] Reserved - must be NULL
2109 * lpdwType [O] Address of buffer for value type. If NULL, the type
2110 * is not required.
2111 * lpbData [O] Address of data buffer. If NULL, the actual data is
2112 * not required.
2113 * lpcbData [I/O] Address of data buffer size
2115 * RETURNS
2116 * ERROR_SUCCESS: Success
2117 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2119 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2120 LPDWORD lpdwReserved, LPDWORD lpdwType,
2121 LPBYTE lpbData, LPDWORD lpcbData )
2123 LPKEYSTRUCT lpkey;
2124 int i;
2126 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey, debugstr_w(lpValueName),
2127 lpdwReserved, lpdwType, lpbData, lpcbData?*lpcbData:0);
2129 lpkey = lookup_hkey(hkey);
2130 if (!lpkey)
2131 return ERROR_INVALID_HANDLE;
2133 /* Reserved must be NULL (at least for now) */
2134 if (lpdwReserved)
2135 return ERROR_INVALID_PARAMETER;
2137 /* An empty name string is equivalent to NULL */
2138 if (lpValueName && !*lpValueName)
2139 lpValueName = NULL;
2141 if (lpValueName==NULL) {
2142 /* Use key's unnamed or default value, if any */
2143 for (i=0;i<lpkey->nrofvalues;i++)
2144 if (lpkey->values[i].name==NULL)
2145 break;
2146 } else {
2147 /* Search for the key name */
2148 for (i=0;i<lpkey->nrofvalues;i++)
2149 if ( lpkey->values[i].name &&
2150 !lstrcmpi32W(lpValueName,lpkey->values[i].name)
2152 break;
2155 if (i==lpkey->nrofvalues) {
2156 TRACE(reg,"Key not found\n");
2157 if (lpValueName==NULL) {
2158 /* Empty keyname not found */
2159 if (lpbData) {
2160 *(WCHAR*)lpbData = 0;
2161 *lpcbData = 2;
2163 if (lpdwType)
2164 *lpdwType = REG_SZ;
2165 TRACE(reg, "Returning an empty string\n");
2166 return ERROR_SUCCESS;
2168 return ERROR_BAD_PATHNAME;
2171 if (lpdwType)
2172 *lpdwType = lpkey->values[i].type;
2174 if (lpbData==NULL) {
2175 /* Data is not required */
2176 if (lpcbData==NULL) {
2177 /* And data size is not required */
2178 /* So all that is returned is the type (set above) */
2179 return ERROR_SUCCESS;
2181 /* Set the size required and return success */
2182 *lpcbData = lpkey->values[i].len;
2183 return ERROR_SUCCESS;
2186 if (*lpcbData<lpkey->values[i].len) {
2187 /* The size was specified, but the data is too big for it */
2188 /* Instead of setting it to NULL, fill in with as much as possible */
2189 /* But the docs do not specify how to handle the lpbData here */
2190 /* *(WCHAR*)lpbData= 0; */
2191 memcpy(lpbData,lpkey->values[i].data,*lpcbData);
2192 *lpcbData = lpkey->values[i].len;
2193 return ERROR_MORE_DATA;
2196 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2198 /* Extra debugging output */
2199 if (lpdwType) {
2200 switch(*lpdwType){
2201 case REG_SZ:
2202 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
2203 break;
2204 case REG_DWORD:
2205 TRACE(reg," Data(dword)=%lx\n", (DWORD)*lpbData);
2206 break;
2207 case REG_BINARY:
2208 TRACE(reg," Data(binary)\n");
2209 /* Is there a way of printing this in readable form? */
2210 break;
2211 default:
2212 TRACE(reg, "Unknown data type %ld\n", *lpdwType);
2213 } /* switch */
2214 } /* if */
2216 /* Set the actual size */
2217 *lpcbData = lpkey->values[i].len;
2218 return ERROR_SUCCESS;
2222 /******************************************************************************
2223 * RegQueryValue32W [ADVAPI32.159]
2225 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2226 LPDWORD lpcbData )
2228 HKEY xhkey;
2229 DWORD ret,lpdwType;
2231 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2232 lpcbData?*lpcbData:0);
2234 /* Only open subkey, if we really do descend */
2235 if (lpszSubKey && *lpszSubKey) {
2236 ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2237 if (ret != ERROR_SUCCESS) {
2238 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2239 return ret;
2241 } else
2242 xhkey = hkey;
2244 lpdwType = REG_SZ;
2245 ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2246 lpcbData );
2247 if (xhkey != hkey)
2248 RegCloseKey(xhkey);
2249 return ret;
2253 /******************************************************************************
2254 * RegQueryValueEx32A [ADVAPI32.157]
2256 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2257 LPDWORD lpdwReserved, LPDWORD lpdwType,
2258 LPBYTE lpbData, LPDWORD lpcbData )
2260 LPWSTR lpszValueNameW;
2261 LPBYTE buf;
2262 DWORD ret,myxlen;
2263 DWORD *mylen;
2264 DWORD type;
2266 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey,debugstr_a(lpszValueName),
2267 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2269 lpszValueNameW = lpszValueName?strdupA2W(lpszValueName):NULL;
2271 /* Why would this be set? It is just an output */
2272 if (lpdwType)
2273 type = *lpdwType;
2275 if (lpbData) {
2276 myxlen = 0;
2277 mylen = &myxlen;
2278 buf = xmalloc(4);
2279 /* Only get the size for now */
2280 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved,
2281 &type, buf, mylen );
2282 free(buf);
2283 if (ret==ERROR_MORE_DATA) {
2284 buf = (LPBYTE)xmalloc(*mylen);
2285 } else {
2286 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2287 myxlen = 2*(*lpcbData);
2289 } else {
2290 /* Data is not required */
2291 buf=NULL;
2292 if (lpcbData) {
2293 myxlen = *lpcbData*2;
2294 mylen = &myxlen;
2295 } else
2296 mylen = NULL;
2299 /* Now get the data */
2300 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &type,
2301 buf, mylen );
2302 if (lpdwType)
2303 *lpdwType=type;
2305 if (ret==ERROR_SUCCESS) {
2306 if (buf) {
2307 if (UNICONVMASK & (1<<(type))) {
2308 /* convert UNICODE to ASCII */
2309 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2310 *lpcbData = myxlen/2;
2311 } else {
2312 if (myxlen>*lpcbData)
2313 ret = ERROR_MORE_DATA;
2314 else
2315 memcpy(lpbData,buf,myxlen);
2317 *lpcbData = myxlen;
2319 } else {
2320 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2321 *lpcbData = myxlen/2;
2323 } else {
2324 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2325 *lpcbData = myxlen/2;
2328 if(buf) free(buf);
2329 if(lpszValueNameW) free(lpszValueNameW);
2330 return ret;
2334 /******************************************************************************
2335 * RegQueryValueEx16 [KERNEL.225]
2337 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2338 LPDWORD lpdwReserved, LPDWORD lpdwType,
2339 LPBYTE lpbData, LPDWORD lpcbData )
2341 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2342 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2343 return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2344 lpbData, lpcbData );
2348 /******************************************************************************
2349 * RegQueryValue32A [ADVAPI32.156]
2351 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2352 LPDWORD lpcbData )
2354 HKEY xhkey;
2355 DWORD ret, dwType;
2357 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2358 lpcbData?*lpcbData:0);
2360 if (lpszSubKey && *lpszSubKey) {
2361 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2362 if( ret != ERROR_SUCCESS )
2363 return ret;
2364 } else
2365 xhkey = hkey;
2367 dwType = REG_SZ;
2368 ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2369 lpcbData );
2370 if( xhkey != hkey )
2371 RegCloseKey( xhkey );
2372 return ret;
2376 /******************************************************************************
2377 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2379 * NOTES
2380 * Is this HACK still applicable?
2382 * HACK
2383 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2384 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2385 * Aldus FH4)
2387 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2388 LPDWORD lpcbData )
2390 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2391 lpcbData?*lpcbData:0);
2393 if (lpcbData)
2394 *lpcbData &= 0xFFFF;
2395 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2400 * Setting values of Registry keys
2402 * Callpath:
2403 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2404 * RegSetValue32W -> RegSetValueEx32W
2408 /******************************************************************************
2409 * RegSetValueEx32W [ADVAPI32.170]
2410 * Sets the data and type of a value under a register key
2412 * PARAMS
2413 * hkey [I] Handle of key to set value for
2414 * lpszValueName [I] Name of value to set
2415 * dwReserved [I] Reserved - must be zero
2416 * dwType [I] Flag for value type
2417 * lpbData [I] Address of value data
2418 * cbData [I] Size of value data
2420 * RETURNS
2421 * Success: ERROR_SUCCESS
2422 * Failure: Error code
2424 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2425 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2426 DWORD cbData)
2428 LPKEYSTRUCT lpkey;
2429 int i;
2431 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2432 dwReserved, dwType, lpbData, cbData);
2434 switch (dwType) {
2435 case REG_SZ:
2436 TRACE(reg," Data(sz)=%s\n", debugstr_w((LPCWSTR)lpbData));
2437 break;
2438 case REG_BINARY:
2439 TRACE(reg," Data(binary)\n");
2440 break;
2441 case REG_DWORD:
2442 TRACE(reg," Data(dword)=%lx\n", (DWORD)lpbData);
2443 break;
2444 default:
2445 TRACE(reg,"Unknown type: %ld\n", dwType);
2448 lpkey = lookup_hkey( hkey );
2449 if (!lpkey)
2450 return ERROR_INVALID_HANDLE;
2452 lpkey->flags |= REG_OPTION_TAINTED;
2454 if (lpszValueName==NULL) {
2455 /* Sets type and name for key's unnamed or default value */
2456 for (i=0;i<lpkey->nrofvalues;i++)
2457 if (lpkey->values[i].name==NULL)
2458 break;
2459 } else {
2460 for (i=0;i<lpkey->nrofvalues;i++)
2461 if ( lpkey->values[i].name &&
2462 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2464 break;
2466 if (i==lpkey->nrofvalues) {
2467 lpkey->values = (LPKEYVALUE)xrealloc(
2468 lpkey->values,
2469 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2471 lpkey->nrofvalues++;
2472 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2474 if (lpkey->values[i].name==NULL)
2475 if (lpszValueName)
2476 lpkey->values[i].name = strdupW(lpszValueName);
2477 else
2478 lpkey->values[i].name = NULL;
2479 lpkey->values[i].len = cbData;
2480 lpkey->values[i].type = dwType;
2481 if (lpkey->values[i].data !=NULL)
2482 free(lpkey->values[i].data);
2483 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2484 lpkey->values[i].lastmodified = time(NULL);
2485 memcpy(lpkey->values[i].data,lpbData,cbData);
2486 return ERROR_SUCCESS;
2490 /******************************************************************************
2491 * RegSetValueEx32A [ADVAPI32.169]
2494 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2495 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2496 DWORD cbData )
2498 LPBYTE buf;
2499 LPWSTR lpszValueNameW;
2500 DWORD ret;
2502 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2503 dwReserved,dwType,lpbData,cbData);
2505 if ((1<<dwType) & UNICONVMASK) {
2506 buf=(LPBYTE)strdupA2W(lpbData);
2507 cbData=2*strlen(lpbData)+2;
2508 } else
2509 buf=lpbData;
2510 if (lpszValueName)
2511 lpszValueNameW = strdupA2W(lpszValueName);
2512 else
2513 lpszValueNameW = NULL;
2514 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2515 if (lpszValueNameW)
2516 free(lpszValueNameW);
2517 if (buf!=lpbData)
2518 free(buf);
2519 return ret;
2523 /******************************************************************************
2524 * RegSetValueEx16 [KERNEL.226]
2526 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2527 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2529 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2530 dwReserved,dwType,lpbData,cbData);
2531 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2532 cbData );
2536 /******************************************************************************
2537 * RegSetValue32W [ADVAPI32.171]
2539 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2540 LPCWSTR lpszData, DWORD cbData )
2542 HKEY xhkey;
2543 DWORD ret;
2545 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2546 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2548 if (lpszSubKey && *lpszSubKey) {
2549 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2550 if (ret!=ERROR_SUCCESS)
2551 return ret;
2552 } else
2553 xhkey=hkey;
2554 if (dwType!=REG_SZ) {
2555 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2556 dwType=REG_SZ;
2558 if (cbData!=2*lstrlen32W(lpszData)+2) {
2559 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2560 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2562 cbData=2*lstrlen32W(lpszData)+2;
2564 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2565 if (hkey!=xhkey)
2566 RegCloseKey(xhkey);
2567 return ret;
2571 /******************************************************************************
2572 * RegSetValue32A [ADVAPI32.168]
2575 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2576 LPCSTR lpszData, DWORD cbData )
2578 DWORD ret;
2579 HKEY xhkey;
2581 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2582 if (lpszSubKey && *lpszSubKey) {
2583 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2584 if (ret!=ERROR_SUCCESS)
2585 return ret;
2586 } else
2587 xhkey=hkey;
2589 if (dwType!=REG_SZ) {
2590 TRACE(reg,"dwType=%ld!\n",dwType);
2591 dwType=REG_SZ;
2593 if (cbData!=strlen(lpszData)+1)
2594 cbData=strlen(lpszData)+1;
2595 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2596 if (xhkey!=hkey)
2597 RegCloseKey(xhkey);
2598 return ret;
2602 /******************************************************************************
2603 * RegSetValue16 [KERNEL.221] [SHELL.5]
2605 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2606 LPCSTR lpszData, DWORD cbData )
2608 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2609 debugstr_a(lpszData),cbData);
2610 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2615 * Key Enumeration
2617 * Callpath:
2618 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2619 * RegEnumKey32W -> RegEnumKeyEx32W
2623 /******************************************************************************
2624 * RegEnumKeyEx32W [ADVAPI32.139]
2626 * PARAMS
2627 * hkey [I] Handle to key to enumerate
2628 * iSubKey [I] Index of subkey to enumerate
2629 * lpszName [O] Buffer for subkey name
2630 * lpcchName [O] Size of subkey buffer
2631 * lpdwReserved [I] Reserved
2632 * lpszClass [O] Buffer for class string
2633 * lpcchClass [O] Size of class buffer
2634 * ft [O] Time key last written to
2636 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2637 LPDWORD lpcchName, LPDWORD lpdwReserved,
2638 LPWSTR lpszClass, LPDWORD lpcchClass,
2639 FILETIME *ft )
2641 LPKEYSTRUCT lpkey,lpxkey;
2643 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2644 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2646 lpkey = lookup_hkey( hkey );
2647 if (!lpkey)
2648 return ERROR_INVALID_HANDLE;
2650 if (!lpkey->nextsub)
2651 return ERROR_NO_MORE_ITEMS;
2652 lpxkey=lpkey->nextsub;
2654 /* Traverse the subkeys */
2655 while (iSubkey && lpxkey) {
2656 iSubkey--;
2657 lpxkey=lpxkey->next;
2660 if (iSubkey || !lpxkey)
2661 return ERROR_NO_MORE_ITEMS;
2662 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2663 return ERROR_MORE_DATA;
2664 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2666 if (*lpcchName)
2667 *lpcchName = lstrlen32W(lpszName);
2669 if (lpszClass) {
2670 /* FIXME: what should we write into it? */
2671 *lpszClass = 0;
2672 *lpcchClass = 2;
2674 return ERROR_SUCCESS;
2678 /******************************************************************************
2679 * RegEnumKey32W [ADVAPI32.140]
2681 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2682 DWORD lpcchName )
2684 FILETIME ft;
2686 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2687 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2691 /******************************************************************************
2692 * RegEnumKeyEx32A [ADVAPI32.138]
2694 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2695 LPDWORD lpcchName, LPDWORD lpdwReserved,
2696 LPSTR lpszClass, LPDWORD lpcchClass,
2697 FILETIME *ft )
2699 DWORD ret,lpcchNameW,lpcchClassW;
2700 LPWSTR lpszNameW,lpszClassW;
2703 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2704 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2706 if (lpszName) {
2707 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2708 lpcchNameW = *lpcchName*2;
2709 } else {
2710 lpszNameW = NULL;
2711 lpcchNameW = 0;
2713 if (lpszClass) {
2714 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2715 lpcchClassW = *lpcchClass*2;
2716 } else {
2717 lpszClassW =0;
2718 lpcchClassW=0;
2720 ret=RegEnumKeyEx32W(
2721 hkey,
2722 iSubkey,
2723 lpszNameW,
2724 &lpcchNameW,
2725 lpdwReserved,
2726 lpszClassW,
2727 &lpcchClassW,
2730 if (ret==ERROR_SUCCESS) {
2731 lstrcpyWtoA(lpszName,lpszNameW);
2732 *lpcchName=strlen(lpszName);
2733 if (lpszClassW) {
2734 lstrcpyWtoA(lpszClass,lpszClassW);
2735 *lpcchClass=strlen(lpszClass);
2738 if (lpszNameW)
2739 free(lpszNameW);
2740 if (lpszClassW)
2741 free(lpszClassW);
2742 return ret;
2746 /******************************************************************************
2747 * RegEnumKey32A [ADVAPI32.137]
2749 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2750 DWORD lpcchName )
2752 FILETIME ft;
2754 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2755 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2756 NULL, &ft );
2760 /******************************************************************************
2761 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2763 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2764 DWORD lpcchName )
2766 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2767 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2772 * Enumerate Registry Values
2774 * Callpath:
2775 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2779 /******************************************************************************
2780 * RegEnumValue32W [ADVAPI32.142]
2782 * PARAMS
2783 * hkey [I] Handle to key to query
2784 * iValue [I] Index of value to query
2785 * lpszValue [O] Value string
2786 * lpcchValue [O] Size of value buffer
2787 * lpdReserved [I] Reserved
2788 * lpdwType [O] Type code
2789 * lpbData [O] Value data
2790 * lpcbData [O] Size of data buffer
2792 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2793 LPDWORD lpcchValue, LPDWORD lpdReserved,
2794 LPDWORD lpdwType, LPBYTE lpbData,
2795 LPDWORD lpcbData )
2797 LPKEYSTRUCT lpkey;
2798 LPKEYVALUE val;
2800 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2801 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2803 lpkey = lookup_hkey( hkey );
2804 if (!lpkey)
2805 return ERROR_INVALID_HANDLE;
2807 if (lpkey->nrofvalues <= iValue)
2808 return ERROR_NO_MORE_ITEMS;
2810 /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2811 val = lpkey->values + iValue;
2813 if (val->name) {
2814 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2815 *lpcchValue = lstrlen32W(val->name)*2+2;
2816 return ERROR_MORE_DATA;
2818 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2819 *lpcchValue=lstrlen32W(val->name)*2+2;
2820 } else {
2821 *lpszValue = 0;
2822 *lpcchValue = 0;
2825 /* Can be NULL if the type code is not required */
2826 if (lpdwType)
2827 *lpdwType = val->type;
2829 if (lpbData) {
2830 if (val->len>*lpcbData)
2831 return ERROR_MORE_DATA;
2832 memcpy(lpbData,val->data,val->len);
2833 *lpcbData = val->len;
2835 return ERROR_SUCCESS;
2839 /******************************************************************************
2840 * RegEnumValue32A [ADVAPI32.141]
2842 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2843 LPDWORD lpcchValue, LPDWORD lpdReserved,
2844 LPDWORD lpdwType, LPBYTE lpbData,
2845 LPDWORD lpcbData )
2847 LPWSTR lpszValueW;
2848 LPBYTE lpbDataW;
2849 DWORD ret,lpcbDataW;
2850 DWORD dwType;
2852 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2853 lpdReserved,lpdwType,lpbData,lpcbData);
2855 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2856 if (lpbData) {
2857 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2858 lpcbDataW = *lpcbData*2;
2859 } else
2860 lpbDataW = NULL;
2862 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2863 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2865 if (lpdwType)
2866 *lpdwType = dwType;
2868 if (ret==ERROR_SUCCESS) {
2869 lstrcpyWtoA(lpszValue,lpszValueW);
2870 if (lpbData) {
2871 if ((1<<dwType) & UNICONVMASK) {
2872 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2873 } else {
2874 if (lpcbDataW > *lpcbData)
2875 ret = ERROR_MORE_DATA;
2876 else
2877 memcpy(lpbData,lpbDataW,lpcbDataW);
2879 *lpcbData = lpcbDataW;
2882 if (lpbDataW) free(lpbDataW);
2883 if (lpszValueW) free(lpszValueW);
2884 return ret;
2888 /******************************************************************************
2889 * RegEnumValue16 [KERNEL.223]
2891 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2892 LPDWORD lpcchValue, LPDWORD lpdReserved,
2893 LPDWORD lpdwType, LPBYTE lpbData,
2894 LPDWORD lpcbData )
2896 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2897 lpdReserved,lpdwType,lpbData,lpcbData);
2898 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2899 lpdwType, lpbData, lpcbData );
2903 /******************************************************************************
2904 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2905 * Releases the handle of the specified key
2907 * PARAMS
2908 * hkey [I] Handle of key to close
2910 * RETURNS
2911 * Success: ERROR_SUCCESS
2912 * Failure: Error code
2914 DWORD WINAPI RegCloseKey( HKEY hkey )
2916 TRACE(reg,"(%x)\n",hkey);
2918 /* The standard handles are allowed to succeed, even though they are not
2919 closed */
2920 if (is_standard_hkey(hkey))
2921 return ERROR_SUCCESS;
2923 return remove_handle(hkey);
2928 * Delete registry key
2930 * Callpath:
2931 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2935 /******************************************************************************
2936 * RegDeleteKey32W [ADVAPI32.134]
2938 * PARAMS
2939 * hkey [I] Handle to open key
2940 * lpszSubKey [I] Name of subkey to delete
2942 * RETURNS
2943 * Success: ERROR_SUCCESS
2944 * Failure: Error code
2946 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
2948 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2949 LPWSTR *wps;
2950 int wpc,i;
2952 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
2954 lpNextKey = lookup_hkey(hkey);
2955 if (!lpNextKey)
2956 return ERROR_INVALID_HANDLE;
2958 /* Subkey param cannot be NULL */
2959 if (!lpszSubKey || !*lpszSubKey)
2960 return ERROR_BADKEY;
2962 /* We need to know the previous key in the hier. */
2963 split_keypath(lpszSubKey,&wps,&wpc);
2964 i = 0;
2965 lpxkey = lpNextKey;
2966 while (i<wpc-1) {
2967 lpxkey=lpNextKey->nextsub;
2968 while (lpxkey) {
2969 TRACE(reg, " Scanning [%s]\n",
2970 debugstr_w(lpxkey->keyname));
2971 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2972 break;
2973 lpxkey=lpxkey->next;
2975 if (!lpxkey) {
2976 FREE_KEY_PATH;
2977 TRACE(reg, " Not found.\n");
2978 /* not found is success */
2979 return ERROR_SUCCESS;
2981 i++;
2982 lpNextKey = lpxkey;
2984 lpxkey = lpNextKey->nextsub;
2985 lplpPrevKey = &(lpNextKey->nextsub);
2986 while (lpxkey) {
2987 TRACE(reg, " Scanning [%s]\n",
2988 debugstr_w(lpxkey->keyname));
2989 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2990 break;
2991 lplpPrevKey = &(lpxkey->next);
2992 lpxkey = lpxkey->next;
2995 if (!lpxkey) {
2996 FREE_KEY_PATH;
2997 WARN(reg , " Not found.\n");
2998 return ERROR_FILE_NOT_FOUND;
3001 if (lpxkey->nextsub) {
3002 FREE_KEY_PATH;
3003 WARN(reg , " Not empty.\n");
3004 return ERROR_CANTWRITE;
3006 *lplpPrevKey = lpxkey->next;
3007 free(lpxkey->keyname);
3008 if (lpxkey->class)
3009 free(lpxkey->class);
3010 if (lpxkey->values)
3011 free(lpxkey->values);
3012 free(lpxkey);
3013 FREE_KEY_PATH;
3014 TRACE(reg, " Done.\n");
3015 return ERROR_SUCCESS;
3019 /******************************************************************************
3020 * RegDeleteKey32A [ADVAPI32.133]
3022 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3024 LPWSTR lpszSubKeyW;
3025 DWORD ret;
3027 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3028 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3029 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3030 if(lpszSubKeyW) free(lpszSubKeyW);
3031 return ret;
3035 /******************************************************************************
3036 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3038 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3040 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3041 return RegDeleteKey32A( hkey, lpszSubKey );
3046 * Delete registry value
3048 * Callpath:
3049 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3053 /******************************************************************************
3054 * RegDeleteValue32W [ADVAPI32.136]
3056 * PARAMS
3057 * hkey [I]
3058 * lpszValue [I]
3060 * RETURNS
3062 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3064 DWORD i;
3065 LPKEYSTRUCT lpkey;
3066 LPKEYVALUE val;
3068 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3070 lpkey = lookup_hkey( hkey );
3071 if (!lpkey)
3072 return ERROR_INVALID_HANDLE;
3074 if (lpszValue) {
3075 for (i=0;i<lpkey->nrofvalues;i++)
3076 if ( lpkey->values[i].name &&
3077 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3079 break;
3080 } else {
3081 for (i=0;i<lpkey->nrofvalues;i++)
3082 if (lpkey->values[i].name==NULL)
3083 break;
3086 if (i == lpkey->nrofvalues)
3087 return ERROR_FILE_NOT_FOUND;
3089 val = lpkey->values+i;
3090 if (val->name) free(val->name);
3091 if (val->data) free(val->data);
3092 memcpy(
3093 lpkey->values+i,
3094 lpkey->values+i+1,
3095 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3097 lpkey->values = (LPKEYVALUE)xrealloc(
3098 lpkey->values,
3099 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3101 lpkey->nrofvalues--;
3102 return ERROR_SUCCESS;
3106 /******************************************************************************
3107 * RegDeleteValue32A [ADVAPI32.135]
3109 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3111 LPWSTR lpszValueW;
3112 DWORD ret;
3114 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3115 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3116 ret = RegDeleteValue32W( hkey, lpszValueW );
3117 if(lpszValueW) free(lpszValueW);
3118 return ret;
3122 /******************************************************************************
3123 * RegDeleteValue16 [KERNEL.222]
3125 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3127 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3128 return RegDeleteValue32A( hkey, lpszValue );
3132 /******************************************************************************
3133 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3134 * Writes key to registry
3136 * PARAMS
3137 * hkey [I] Handle of key to write
3139 * RETURNS
3140 * Success: ERROR_SUCCESS
3141 * Failure: Error code
3143 DWORD WINAPI RegFlushKey( HKEY hkey )
3145 LPKEYSTRUCT lpkey;
3146 BOOL32 ret;
3148 TRACE(reg, "(%x)\n", hkey);
3150 lpkey = lookup_hkey( hkey );
3151 if (!lpkey)
3152 return ERROR_INVALID_HANDLE;
3154 ERR(reg, "What is the correct filename?\n");
3156 ret = _savereg( lpkey, "foo.bar", TRUE);
3158 if( ret ) {
3159 return ERROR_SUCCESS;
3160 } else
3161 return ERROR_UNKNOWN; /* FIXME */
3165 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3168 /******************************************************************************
3169 * RegQueryInfoKey32W [ADVAPI32.153]
3171 * PARAMS
3172 * hkey [I] Handle to key to query
3173 * lpszClass [O] Buffer for class string
3174 * lpcchClass [O] Size of class string buffer
3175 * lpdwReserved [I] Reserved
3176 * lpcSubKeys [I] Buffer for number of subkeys
3177 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3178 * lpcchMaxClass [O] Buffer for longest class string length
3179 * lpcValues [O] Buffer for number of value entries
3180 * lpcchMaxValueName [O] Buffer for longest value name length
3181 * lpccbMaxValueData [O] Buffer for longest value data length
3182 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3183 * ft
3185 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass,
3186 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3187 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3188 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3189 LPDWORD lpcchMaxValueName,
3190 LPDWORD lpccbMaxValueData,
3191 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3193 LPKEYSTRUCT lpkey,lpxkey;
3194 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3195 int i;
3197 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3198 lpkey = lookup_hkey(hkey);
3199 if (!lpkey)
3200 return ERROR_INVALID_HANDLE;
3201 if (lpszClass) {
3202 if (lpkey->class) {
3203 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
3204 *lpcchClass=lstrlen32W(lpkey->class)*2;
3205 return ERROR_MORE_DATA;
3207 *lpcchClass=lstrlen32W(lpkey->class)*2;
3208 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
3209 } else {
3210 *lpszClass = 0;
3211 *lpcchClass = 0;
3213 } else {
3214 if (lpcchClass)
3215 *lpcchClass = lstrlen32W(lpkey->class)*2;
3217 lpxkey=lpkey->nextsub;
3218 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3219 while (lpxkey) {
3220 nrofkeys++;
3221 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3222 maxsubkey=lstrlen32W(lpxkey->keyname);
3223 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3224 maxclass=lstrlen32W(lpxkey->class);
3225 lpxkey=lpxkey->next;
3227 for (i=0;i<lpkey->nrofvalues;i++) {
3228 LPKEYVALUE val=lpkey->values+i;
3230 if (val->name && lstrlen32W(val->name)>maxvname)
3231 maxvname=lstrlen32W(val->name);
3232 if (val->len>maxvdata)
3233 maxvdata=val->len;
3235 if (!maxclass) maxclass = 1;
3236 if (!maxvname) maxvname = 1;
3237 if (lpcValues)
3238 *lpcValues = lpkey->nrofvalues;
3239 if (lpcSubKeys)
3240 *lpcSubKeys = nrofkeys;
3241 if (lpcchMaxSubkey)
3242 *lpcchMaxSubkey = maxsubkey*2;
3243 if (lpcchMaxClass)
3244 *lpcchMaxClass = maxclass*2;
3245 if (lpcchMaxValueName)
3246 *lpcchMaxValueName= maxvname;
3247 if (lpccbMaxValueData)
3248 *lpccbMaxValueData= maxvdata;
3249 return ERROR_SUCCESS;
3253 /******************************************************************************
3254 * RegQueryInfoKey32A [ADVAPI32.152]
3256 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3257 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3258 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3259 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3260 LPDWORD lpccbMaxValueData,
3261 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3263 LPWSTR lpszClassW;
3264 DWORD ret;
3266 TRACE(reg,"(%x,......)\n",hkey);
3267 if (lpszClass) {
3268 *lpcchClass*= 2;
3269 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
3271 } else
3272 lpszClassW = NULL;
3273 ret=RegQueryInfoKey32W(
3274 hkey,
3275 lpszClassW,
3276 lpcchClass,
3277 lpdwReserved,
3278 lpcSubKeys,
3279 lpcchMaxSubkey,
3280 lpcchMaxClass,
3281 lpcValues,
3282 lpcchMaxValueName,
3283 lpccbMaxValueData,
3284 lpcbSecurityDescriptor,
3287 if (ret==ERROR_SUCCESS && lpszClass)
3288 lstrcpyWtoA(lpszClass,lpszClassW);
3289 if (lpcchClass)
3290 *lpcchClass/=2;
3291 if (lpcchMaxSubkey)
3292 *lpcchMaxSubkey/=2;
3293 if (lpcchMaxClass)
3294 *lpcchMaxClass/=2;
3295 if (lpcchMaxValueName)
3296 *lpcchMaxValueName/=2;
3297 if (lpszClassW)
3298 free(lpszClassW);
3299 return ret;
3303 /******************************************************************************
3304 * RegConnectRegistry32W [ADVAPI32.128]
3306 * PARAMS
3307 * lpMachineName [I] Address of name of remote computer
3308 * hHey [I] Predefined registry handle
3309 * phkResult [I] Address of buffer for remote registry handle
3311 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey,
3312 LPHKEY phkResult )
3314 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3316 if (!lpMachineName || !*lpMachineName) {
3317 /* Use the local machine name */
3318 return RegOpenKey16( hKey, "", phkResult );
3321 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3322 return ERROR_BAD_NETPATH;
3326 /******************************************************************************
3327 * RegConnectRegistry32A [ADVAPI32.127]
3329 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3331 DWORD ret;
3332 LPWSTR machineW = strdupA2W(machine);
3333 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3334 free(machineW);
3335 return ret;
3339 /******************************************************************************
3340 * RegGetKeySecurity [ADVAPI32.144]
3341 * Retrieves a copy of security descriptor protecting the registry key
3343 * PARAMS
3344 * hkey [I] Open handle of key to set
3345 * SecurityInformation [I] Descriptor contents
3346 * pSecurityDescriptor [O] Address of descriptor for key
3347 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3349 * RETURNS
3350 * Success: ERROR_SUCCESS
3351 * Failure: Error code
3353 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3354 SECURITY_INFORMATION SecurityInformation,
3355 LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3356 LPDWORD lpcbSecurityDescriptor )
3358 LPKEYSTRUCT lpkey;
3360 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3361 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3363 lpkey = lookup_hkey( hkey );
3364 if (!lpkey)
3365 return ERROR_INVALID_HANDLE;
3367 /* FIXME: Check for valid SecurityInformation values */
3369 if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3370 return ERROR_INSUFFICIENT_BUFFER;
3372 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3373 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3375 return ERROR_SUCCESS;
3379 /******************************************************************************
3380 * RegLoadKey32W [ADVAPI32.???]
3382 * PARAMS
3383 * hkey [I] Handle of open key
3384 * lpszSubKey [I] Address of name of subkey
3385 * lpszFile [I] Address of filename for registry information
3387 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3389 LPKEYSTRUCT lpkey;
3390 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3392 /* Do this check before the hkey check */
3393 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3394 return ERROR_INVALID_PARAMETER;
3396 lpkey = lookup_hkey( hkey );
3397 if (!lpkey)
3398 return ERROR_INVALID_HANDLE;
3400 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3401 debugstr_w(lpszFile));
3403 return ERROR_SUCCESS;
3407 /******************************************************************************
3408 * RegLoadKey32A [ADVAPI32.???]
3410 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3412 LONG ret;
3413 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3414 LPWSTR lpszFileW = strdupA2W(lpszFile);
3415 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3416 if(lpszFileW) free(lpszFileW);
3417 if(lpszSubKeyW) free(lpszSubKeyW);
3418 return ret;
3422 /******************************************************************************
3423 * RegNotifyChangeKeyValue [ADVAPI32.???]
3425 * PARAMS
3426 * hkey [I] Handle of key to watch
3427 * fWatchSubTree [I] Flag for subkey notification
3428 * fdwNotifyFilter [I] Changes to be reported
3429 * hEvent [I] Handle of signaled event
3430 * fAsync [I] Flag for asynchronous reporting
3432 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3433 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3434 BOOL32 fAsync )
3436 LPKEYSTRUCT lpkey;
3437 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3438 hEvent,fAsync);
3440 lpkey = lookup_hkey( hkey );
3441 if (!lpkey)
3442 return ERROR_INVALID_HANDLE;
3444 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3445 hEvent,fAsync);
3447 return ERROR_SUCCESS;
3451 /******************************************************************************
3452 * RegUnLoadKey32W [ADVAPI32.173]
3454 * PARAMS
3455 * hkey [I] Handle of open key
3456 * lpSubKey [I] Address of name of subkey to unload
3458 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3460 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3461 return ERROR_SUCCESS;
3465 /******************************************************************************
3466 * RegUnLoadKey32A [ADVAPI32.172]
3468 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3470 LONG ret;
3471 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3472 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3473 if(lpSubKeyW) free(lpSubKeyW);
3474 return ret;
3478 /******************************************************************************
3479 * RegSetKeySecurity [ADVAPI32.167]
3481 * PARAMS
3482 * hkey [I] Open handle of key to set
3483 * SecurityInfo [I] Descriptor contents
3484 * pSecurityDesc [I] Address of descriptor for key
3486 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3487 LPSECURITY_DESCRIPTOR pSecurityDesc )
3489 LPKEYSTRUCT lpkey;
3491 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3493 /* It seems to perform this check before the hkey check */
3494 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3495 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3496 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3497 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3498 /* Param OK */
3499 } else
3500 return ERROR_INVALID_PARAMETER;
3502 if (!pSecurityDesc)
3503 return ERROR_INVALID_PARAMETER;
3505 lpkey = lookup_hkey( hkey );
3506 if (!lpkey)
3507 return ERROR_INVALID_HANDLE;
3509 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3511 return ERROR_SUCCESS;
3515 /******************************************************************************
3516 * RegSaveKey32W [ADVAPI32.166]
3518 * PARAMS
3519 * hkey [I] Handle of key where save begins
3520 * lpFile [I] Address of filename to save to
3521 * sa [I] Address of security structure
3523 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3524 LPSECURITY_ATTRIBUTES sa )
3526 LPKEYSTRUCT lpkey;
3528 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3530 /* It appears to do this check before the hkey check */
3531 if (!lpFile || !*lpFile)
3532 return ERROR_INVALID_PARAMETER;
3534 lpkey = lookup_hkey( hkey );
3535 if (!lpkey)
3536 return ERROR_INVALID_HANDLE;
3538 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3540 return ERROR_SUCCESS;
3544 /******************************************************************************
3545 * RegSaveKey32A [ADVAPI32.165]
3547 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3548 LPSECURITY_ATTRIBUTES sa )
3550 LONG ret;
3551 LPWSTR lpFileW = strdupA2W(lpFile);
3552 ret = RegSaveKey32W( hkey, lpFileW, sa );
3553 free(lpFileW);
3554 return ret;
3558 /******************************************************************************
3559 * RegRestoreKey32W [ADVAPI32.164]
3561 * PARAMS
3562 * hkey [I] Handle of key where restore begins
3563 * lpFile [I] Address of filename containing saved tree
3564 * dwFlags [I] Optional flags
3566 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3568 LPKEYSTRUCT lpkey;
3570 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3572 /* It seems to do this check before the hkey check */
3573 if (!lpFile || !*lpFile)
3574 return ERROR_INVALID_PARAMETER;
3576 lpkey = lookup_hkey( hkey );
3577 if (!lpkey)
3578 return ERROR_INVALID_HANDLE;
3580 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3582 /* Check for file existence */
3584 return ERROR_SUCCESS;
3588 /******************************************************************************
3589 * RegRestoreKey32A [ADVAPI32.163]
3591 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3593 LONG ret;
3594 LPWSTR lpFileW = strdupA2W(lpFile);
3595 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3596 if(lpFileW) free(lpFileW);
3597 return ret;
3601 /******************************************************************************
3602 * RegReplaceKey32W [ADVAPI32.162]
3604 * PARAMS
3605 * hkey [I] Handle of open key
3606 * lpSubKey [I] Address of name of subkey
3607 * lpNewFile [I] Address of filename for file with new data
3608 * lpOldFile [I] Address of filename for backup file
3610 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3611 LPCWSTR lpOldFile )
3613 LPKEYSTRUCT lpkey;
3615 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3616 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3618 lpkey = lookup_hkey( hkey );
3619 if (!lpkey)
3620 return ERROR_INVALID_HANDLE;
3622 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3623 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3625 return ERROR_SUCCESS;
3629 /******************************************************************************
3630 * RegReplaceKey32A [ADVAPI32.161]
3632 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3633 LPCSTR lpOldFile )
3635 LONG ret;
3636 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3637 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3638 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3639 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3640 free(lpOldFileW);
3641 free(lpNewFileW);
3642 free(lpSubKeyW);
3643 return ret;