Fixed differences between SetRectRgn16 and SetRectRgn32. Also a bug fix for
[wine.git] / misc / registry.c
blobbf9e335b42e3d7c493aeba0d43ed1a5b502102b3
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,"(0x%x,%p,0x%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 0x%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 0x%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 = (struct dkh*)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,"(0x%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,"(0x%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;
2480 lpkey->values[i].len = cbData;
2481 lpkey->values[i].type = dwType;
2482 if (lpkey->values[i].data !=NULL)
2483 free(lpkey->values[i].data);
2484 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2485 lpkey->values[i].lastmodified = time(NULL);
2486 memcpy(lpkey->values[i].data,lpbData,cbData);
2487 return ERROR_SUCCESS;
2491 /******************************************************************************
2492 * RegSetValueEx32A [ADVAPI32.169]
2495 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2496 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2497 DWORD cbData )
2499 LPBYTE buf;
2500 LPWSTR lpszValueNameW;
2501 DWORD ret;
2503 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2504 dwReserved,dwType,lpbData,cbData);
2506 if ((1<<dwType) & UNICONVMASK) {
2507 buf=(LPBYTE)strdupA2W(lpbData);
2508 cbData=2*strlen(lpbData)+2;
2509 } else
2510 buf=lpbData;
2511 if (lpszValueName)
2512 lpszValueNameW = strdupA2W(lpszValueName);
2513 else
2514 lpszValueNameW = NULL;
2515 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2516 if (lpszValueNameW)
2517 free(lpszValueNameW);
2518 if (buf!=lpbData)
2519 free(buf);
2520 return ret;
2524 /******************************************************************************
2525 * RegSetValueEx16 [KERNEL.226]
2527 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2528 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2530 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2531 dwReserved,dwType,lpbData,cbData);
2532 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2533 cbData );
2537 /******************************************************************************
2538 * RegSetValue32W [ADVAPI32.171]
2540 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2541 LPCWSTR lpszData, DWORD cbData )
2543 HKEY xhkey;
2544 DWORD ret;
2546 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2547 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2549 if (lpszSubKey && *lpszSubKey) {
2550 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2551 if (ret!=ERROR_SUCCESS)
2552 return ret;
2553 } else
2554 xhkey=hkey;
2555 if (dwType!=REG_SZ) {
2556 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2557 dwType=REG_SZ;
2559 if (cbData!=2*lstrlen32W(lpszData)+2) {
2560 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2561 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2563 cbData=2*lstrlen32W(lpszData)+2;
2565 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2566 if (hkey!=xhkey)
2567 RegCloseKey(xhkey);
2568 return ret;
2572 /******************************************************************************
2573 * RegSetValue32A [ADVAPI32.168]
2576 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2577 LPCSTR lpszData, DWORD cbData )
2579 DWORD ret;
2580 HKEY xhkey;
2582 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2583 if (lpszSubKey && *lpszSubKey) {
2584 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2585 if (ret!=ERROR_SUCCESS)
2586 return ret;
2587 } else
2588 xhkey=hkey;
2590 if (dwType!=REG_SZ) {
2591 TRACE(reg,"dwType=%ld!\n",dwType);
2592 dwType=REG_SZ;
2594 if (cbData!=strlen(lpszData)+1)
2595 cbData=strlen(lpszData)+1;
2596 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2597 if (xhkey!=hkey)
2598 RegCloseKey(xhkey);
2599 return ret;
2603 /******************************************************************************
2604 * RegSetValue16 [KERNEL.221] [SHELL.5]
2606 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2607 LPCSTR lpszData, DWORD cbData )
2609 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2610 debugstr_a(lpszData),cbData);
2611 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2616 * Key Enumeration
2618 * Callpath:
2619 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2620 * RegEnumKey32W -> RegEnumKeyEx32W
2624 /******************************************************************************
2625 * RegEnumKeyEx32W [ADVAPI32.139]
2627 * PARAMS
2628 * hkey [I] Handle to key to enumerate
2629 * iSubKey [I] Index of subkey to enumerate
2630 * lpszName [O] Buffer for subkey name
2631 * lpcchName [O] Size of subkey buffer
2632 * lpdwReserved [I] Reserved
2633 * lpszClass [O] Buffer for class string
2634 * lpcchClass [O] Size of class buffer
2635 * ft [O] Time key last written to
2637 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2638 LPDWORD lpcchName, LPDWORD lpdwReserved,
2639 LPWSTR lpszClass, LPDWORD lpcchClass,
2640 FILETIME *ft )
2642 LPKEYSTRUCT lpkey,lpxkey;
2644 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2645 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2647 lpkey = lookup_hkey( hkey );
2648 if (!lpkey)
2649 return ERROR_INVALID_HANDLE;
2651 if (!lpkey->nextsub)
2652 return ERROR_NO_MORE_ITEMS;
2653 lpxkey=lpkey->nextsub;
2655 /* Traverse the subkeys */
2656 while (iSubkey && lpxkey) {
2657 iSubkey--;
2658 lpxkey=lpxkey->next;
2661 if (iSubkey || !lpxkey)
2662 return ERROR_NO_MORE_ITEMS;
2663 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2664 return ERROR_MORE_DATA;
2665 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2667 if (*lpcchName)
2668 *lpcchName = lstrlen32W(lpszName);
2670 if (lpszClass) {
2671 /* FIXME: what should we write into it? */
2672 *lpszClass = 0;
2673 *lpcchClass = 2;
2675 return ERROR_SUCCESS;
2679 /******************************************************************************
2680 * RegEnumKey32W [ADVAPI32.140]
2682 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2683 DWORD lpcchName )
2685 FILETIME ft;
2687 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2688 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2692 /******************************************************************************
2693 * RegEnumKeyEx32A [ADVAPI32.138]
2695 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2696 LPDWORD lpcchName, LPDWORD lpdwReserved,
2697 LPSTR lpszClass, LPDWORD lpcchClass,
2698 FILETIME *ft )
2700 DWORD ret,lpcchNameW,lpcchClassW;
2701 LPWSTR lpszNameW,lpszClassW;
2704 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2705 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2707 if (lpszName) {
2708 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2709 lpcchNameW = *lpcchName*2;
2710 } else {
2711 lpszNameW = NULL;
2712 lpcchNameW = 0;
2714 if (lpszClass) {
2715 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2716 lpcchClassW = *lpcchClass*2;
2717 } else {
2718 lpszClassW =0;
2719 lpcchClassW=0;
2721 ret=RegEnumKeyEx32W(
2722 hkey,
2723 iSubkey,
2724 lpszNameW,
2725 &lpcchNameW,
2726 lpdwReserved,
2727 lpszClassW,
2728 &lpcchClassW,
2731 if (ret==ERROR_SUCCESS) {
2732 lstrcpyWtoA(lpszName,lpszNameW);
2733 *lpcchName=strlen(lpszName);
2734 if (lpszClassW) {
2735 lstrcpyWtoA(lpszClass,lpszClassW);
2736 *lpcchClass=strlen(lpszClass);
2739 if (lpszNameW)
2740 free(lpszNameW);
2741 if (lpszClassW)
2742 free(lpszClassW);
2743 return ret;
2747 /******************************************************************************
2748 * RegEnumKey32A [ADVAPI32.137]
2750 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2751 DWORD lpcchName )
2753 FILETIME ft;
2755 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2756 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2757 NULL, &ft );
2761 /******************************************************************************
2762 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2764 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2765 DWORD lpcchName )
2767 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2768 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2773 * Enumerate Registry Values
2775 * Callpath:
2776 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2780 /******************************************************************************
2781 * RegEnumValue32W [ADVAPI32.142]
2783 * PARAMS
2784 * hkey [I] Handle to key to query
2785 * iValue [I] Index of value to query
2786 * lpszValue [O] Value string
2787 * lpcchValue [O] Size of value buffer
2788 * lpdReserved [I] Reserved
2789 * lpdwType [O] Type code
2790 * lpbData [O] Value data
2791 * lpcbData [O] Size of data buffer
2793 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2794 LPDWORD lpcchValue, LPDWORD lpdReserved,
2795 LPDWORD lpdwType, LPBYTE lpbData,
2796 LPDWORD lpcbData )
2798 LPKEYSTRUCT lpkey;
2799 LPKEYVALUE val;
2801 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2802 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2804 lpkey = lookup_hkey( hkey );
2805 if (!lpkey)
2806 return ERROR_INVALID_HANDLE;
2808 if (lpkey->nrofvalues <= iValue)
2809 return ERROR_NO_MORE_ITEMS;
2811 /* FIXME: Should this be lpkey->values + iValue * sizeof(KEYVALUE)? */
2812 val = lpkey->values + iValue;
2814 if (val->name) {
2815 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2816 *lpcchValue = lstrlen32W(val->name)*2+2;
2817 return ERROR_MORE_DATA;
2819 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2820 *lpcchValue=lstrlen32W(val->name)*2+2;
2821 } else {
2822 *lpszValue = 0;
2823 *lpcchValue = 0;
2826 /* Can be NULL if the type code is not required */
2827 if (lpdwType)
2828 *lpdwType = val->type;
2830 if (lpbData) {
2831 if (val->len>*lpcbData)
2832 return ERROR_MORE_DATA;
2833 memcpy(lpbData,val->data,val->len);
2834 *lpcbData = val->len;
2836 return ERROR_SUCCESS;
2840 /******************************************************************************
2841 * RegEnumValue32A [ADVAPI32.141]
2843 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2844 LPDWORD lpcchValue, LPDWORD lpdReserved,
2845 LPDWORD lpdwType, LPBYTE lpbData,
2846 LPDWORD lpcbData )
2848 LPWSTR lpszValueW;
2849 LPBYTE lpbDataW;
2850 DWORD ret,lpcbDataW;
2851 DWORD dwType;
2853 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2854 lpdReserved,lpdwType,lpbData,lpcbData);
2856 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2857 if (lpbData) {
2858 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2859 lpcbDataW = *lpcbData*2;
2860 } else
2861 lpbDataW = NULL;
2863 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2864 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2866 if (lpdwType)
2867 *lpdwType = dwType;
2869 if (ret==ERROR_SUCCESS) {
2870 lstrcpyWtoA(lpszValue,lpszValueW);
2871 if (lpbData) {
2872 if ((1<<dwType) & UNICONVMASK) {
2873 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2874 } else {
2875 if (lpcbDataW > *lpcbData)
2876 ret = ERROR_MORE_DATA;
2877 else
2878 memcpy(lpbData,lpbDataW,lpcbDataW);
2880 *lpcbData = lpcbDataW;
2883 if (lpbDataW) free(lpbDataW);
2884 if (lpszValueW) free(lpszValueW);
2885 return ret;
2889 /******************************************************************************
2890 * RegEnumValue16 [KERNEL.223]
2892 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2893 LPDWORD lpcchValue, LPDWORD lpdReserved,
2894 LPDWORD lpdwType, LPBYTE lpbData,
2895 LPDWORD lpcbData )
2897 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2898 lpdReserved,lpdwType,lpbData,lpcbData);
2899 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2900 lpdwType, lpbData, lpcbData );
2904 /******************************************************************************
2905 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2906 * Releases the handle of the specified key
2908 * PARAMS
2909 * hkey [I] Handle of key to close
2911 * RETURNS
2912 * Success: ERROR_SUCCESS
2913 * Failure: Error code
2915 DWORD WINAPI RegCloseKey( HKEY hkey )
2917 TRACE(reg,"(%x)\n",hkey);
2919 /* The standard handles are allowed to succeed, even though they are not
2920 closed */
2921 if (is_standard_hkey(hkey))
2922 return ERROR_SUCCESS;
2924 return remove_handle(hkey);
2929 * Delete registry key
2931 * Callpath:
2932 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2936 /******************************************************************************
2937 * RegDeleteKey32W [ADVAPI32.134]
2939 * PARAMS
2940 * hkey [I] Handle to open key
2941 * lpszSubKey [I] Name of subkey to delete
2943 * RETURNS
2944 * Success: ERROR_SUCCESS
2945 * Failure: Error code
2947 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
2949 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2950 LPWSTR *wps;
2951 int wpc,i;
2953 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
2955 lpNextKey = lookup_hkey(hkey);
2956 if (!lpNextKey)
2957 return ERROR_INVALID_HANDLE;
2959 /* Subkey param cannot be NULL */
2960 if (!lpszSubKey || !*lpszSubKey)
2961 return ERROR_BADKEY;
2963 /* We need to know the previous key in the hier. */
2964 split_keypath(lpszSubKey,&wps,&wpc);
2965 i = 0;
2966 lpxkey = lpNextKey;
2967 while (i<wpc-1) {
2968 lpxkey=lpNextKey->nextsub;
2969 while (lpxkey) {
2970 TRACE(reg, " Scanning [%s]\n",
2971 debugstr_w(lpxkey->keyname));
2972 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2973 break;
2974 lpxkey=lpxkey->next;
2976 if (!lpxkey) {
2977 FREE_KEY_PATH;
2978 TRACE(reg, " Not found.\n");
2979 /* not found is success */
2980 return ERROR_SUCCESS;
2982 i++;
2983 lpNextKey = lpxkey;
2985 lpxkey = lpNextKey->nextsub;
2986 lplpPrevKey = &(lpNextKey->nextsub);
2987 while (lpxkey) {
2988 TRACE(reg, " Scanning [%s]\n",
2989 debugstr_w(lpxkey->keyname));
2990 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2991 break;
2992 lplpPrevKey = &(lpxkey->next);
2993 lpxkey = lpxkey->next;
2996 if (!lpxkey) {
2997 FREE_KEY_PATH;
2998 WARN(reg , " Not found.\n");
2999 return ERROR_FILE_NOT_FOUND;
3002 if (lpxkey->nextsub) {
3003 FREE_KEY_PATH;
3004 WARN(reg , " Not empty.\n");
3005 return ERROR_CANTWRITE;
3007 *lplpPrevKey = lpxkey->next;
3008 free(lpxkey->keyname);
3009 if (lpxkey->class)
3010 free(lpxkey->class);
3011 if (lpxkey->values)
3012 free(lpxkey->values);
3013 free(lpxkey);
3014 FREE_KEY_PATH;
3015 TRACE(reg, " Done.\n");
3016 return ERROR_SUCCESS;
3020 /******************************************************************************
3021 * RegDeleteKey32A [ADVAPI32.133]
3023 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3025 LPWSTR lpszSubKeyW;
3026 DWORD ret;
3028 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3029 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3030 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3031 if(lpszSubKeyW) free(lpszSubKeyW);
3032 return ret;
3036 /******************************************************************************
3037 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3039 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3041 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3042 return RegDeleteKey32A( hkey, lpszSubKey );
3047 * Delete registry value
3049 * Callpath:
3050 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3054 /******************************************************************************
3055 * RegDeleteValue32W [ADVAPI32.136]
3057 * PARAMS
3058 * hkey [I]
3059 * lpszValue [I]
3061 * RETURNS
3063 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3065 DWORD i;
3066 LPKEYSTRUCT lpkey;
3067 LPKEYVALUE val;
3069 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3071 lpkey = lookup_hkey( hkey );
3072 if (!lpkey)
3073 return ERROR_INVALID_HANDLE;
3075 if (lpszValue) {
3076 for (i=0;i<lpkey->nrofvalues;i++)
3077 if ( lpkey->values[i].name &&
3078 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3080 break;
3081 } else {
3082 for (i=0;i<lpkey->nrofvalues;i++)
3083 if (lpkey->values[i].name==NULL)
3084 break;
3087 if (i == lpkey->nrofvalues)
3088 return ERROR_FILE_NOT_FOUND;
3090 val = lpkey->values+i;
3091 if (val->name) free(val->name);
3092 if (val->data) free(val->data);
3093 memcpy(
3094 lpkey->values+i,
3095 lpkey->values+i+1,
3096 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3098 lpkey->values = (LPKEYVALUE)xrealloc(
3099 lpkey->values,
3100 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3102 lpkey->nrofvalues--;
3103 return ERROR_SUCCESS;
3107 /******************************************************************************
3108 * RegDeleteValue32A [ADVAPI32.135]
3110 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3112 LPWSTR lpszValueW;
3113 DWORD ret;
3115 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3116 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3117 ret = RegDeleteValue32W( hkey, lpszValueW );
3118 if(lpszValueW) free(lpszValueW);
3119 return ret;
3123 /******************************************************************************
3124 * RegDeleteValue16 [KERNEL.222]
3126 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3128 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3129 return RegDeleteValue32A( hkey, lpszValue );
3133 /******************************************************************************
3134 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3135 * Writes key to registry
3137 * PARAMS
3138 * hkey [I] Handle of key to write
3140 * RETURNS
3141 * Success: ERROR_SUCCESS
3142 * Failure: Error code
3144 DWORD WINAPI RegFlushKey( HKEY hkey )
3146 LPKEYSTRUCT lpkey;
3147 BOOL32 ret;
3149 TRACE(reg, "(%x)\n", hkey);
3151 lpkey = lookup_hkey( hkey );
3152 if (!lpkey)
3153 return ERROR_INVALID_HANDLE;
3155 ERR(reg, "What is the correct filename?\n");
3157 ret = _savereg( lpkey, "foo.bar", TRUE);
3159 if( ret ) {
3160 return ERROR_SUCCESS;
3161 } else
3162 return ERROR_UNKNOWN; /* FIXME */
3166 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3169 /******************************************************************************
3170 * RegQueryInfoKey32W [ADVAPI32.153]
3172 * PARAMS
3173 * hkey [I] Handle to key to query
3174 * lpszClass [O] Buffer for class string
3175 * lpcchClass [O] Size of class string buffer
3176 * lpdwReserved [I] Reserved
3177 * lpcSubKeys [I] Buffer for number of subkeys
3178 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3179 * lpcchMaxClass [O] Buffer for longest class string length
3180 * lpcValues [O] Buffer for number of value entries
3181 * lpcchMaxValueName [O] Buffer for longest value name length
3182 * lpccbMaxValueData [O] Buffer for longest value data length
3183 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3184 * ft
3186 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass,
3187 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3188 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3189 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3190 LPDWORD lpcchMaxValueName,
3191 LPDWORD lpccbMaxValueData,
3192 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3194 LPKEYSTRUCT lpkey,lpxkey;
3195 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3196 int i;
3198 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3199 lpkey = lookup_hkey(hkey);
3200 if (!lpkey)
3201 return ERROR_INVALID_HANDLE;
3202 if (lpszClass) {
3203 if (lpkey->class) {
3204 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
3205 *lpcchClass=lstrlen32W(lpkey->class)*2;
3206 return ERROR_MORE_DATA;
3208 *lpcchClass=lstrlen32W(lpkey->class)*2;
3209 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
3210 } else {
3211 *lpszClass = 0;
3212 *lpcchClass = 0;
3214 } else {
3215 if (lpcchClass)
3216 *lpcchClass = lstrlen32W(lpkey->class)*2;
3218 lpxkey=lpkey->nextsub;
3219 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3220 while (lpxkey) {
3221 nrofkeys++;
3222 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3223 maxsubkey=lstrlen32W(lpxkey->keyname);
3224 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3225 maxclass=lstrlen32W(lpxkey->class);
3226 lpxkey=lpxkey->next;
3228 for (i=0;i<lpkey->nrofvalues;i++) {
3229 LPKEYVALUE val=lpkey->values+i;
3231 if (val->name && lstrlen32W(val->name)>maxvname)
3232 maxvname=lstrlen32W(val->name);
3233 if (val->len>maxvdata)
3234 maxvdata=val->len;
3236 if (!maxclass) maxclass = 1;
3237 if (!maxvname) maxvname = 1;
3238 if (lpcValues)
3239 *lpcValues = lpkey->nrofvalues;
3240 if (lpcSubKeys)
3241 *lpcSubKeys = nrofkeys;
3242 if (lpcchMaxSubkey)
3243 *lpcchMaxSubkey = maxsubkey*2;
3244 if (lpcchMaxClass)
3245 *lpcchMaxClass = maxclass*2;
3246 if (lpcchMaxValueName)
3247 *lpcchMaxValueName= maxvname;
3248 if (lpccbMaxValueData)
3249 *lpccbMaxValueData= maxvdata;
3250 return ERROR_SUCCESS;
3254 /******************************************************************************
3255 * RegQueryInfoKey32A [ADVAPI32.152]
3257 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3258 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3259 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3260 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3261 LPDWORD lpccbMaxValueData,
3262 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3264 LPWSTR lpszClassW;
3265 DWORD ret;
3267 TRACE(reg,"(%x,......)\n",hkey);
3268 if (lpszClass) {
3269 *lpcchClass*= 2;
3270 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
3272 } else
3273 lpszClassW = NULL;
3274 ret=RegQueryInfoKey32W(
3275 hkey,
3276 lpszClassW,
3277 lpcchClass,
3278 lpdwReserved,
3279 lpcSubKeys,
3280 lpcchMaxSubkey,
3281 lpcchMaxClass,
3282 lpcValues,
3283 lpcchMaxValueName,
3284 lpccbMaxValueData,
3285 lpcbSecurityDescriptor,
3288 if (ret==ERROR_SUCCESS && lpszClass)
3289 lstrcpyWtoA(lpszClass,lpszClassW);
3290 if (lpcchClass)
3291 *lpcchClass/=2;
3292 if (lpcchMaxSubkey)
3293 *lpcchMaxSubkey/=2;
3294 if (lpcchMaxClass)
3295 *lpcchMaxClass/=2;
3296 if (lpcchMaxValueName)
3297 *lpcchMaxValueName/=2;
3298 if (lpszClassW)
3299 free(lpszClassW);
3300 return ret;
3304 /******************************************************************************
3305 * RegConnectRegistry32W [ADVAPI32.128]
3307 * PARAMS
3308 * lpMachineName [I] Address of name of remote computer
3309 * hHey [I] Predefined registry handle
3310 * phkResult [I] Address of buffer for remote registry handle
3312 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey,
3313 LPHKEY phkResult )
3315 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3317 if (!lpMachineName || !*lpMachineName) {
3318 /* Use the local machine name */
3319 return RegOpenKey16( hKey, "", phkResult );
3322 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3323 return ERROR_BAD_NETPATH;
3327 /******************************************************************************
3328 * RegConnectRegistry32A [ADVAPI32.127]
3330 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3332 DWORD ret;
3333 LPWSTR machineW = strdupA2W(machine);
3334 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3335 free(machineW);
3336 return ret;
3340 /******************************************************************************
3341 * RegGetKeySecurity [ADVAPI32.144]
3342 * Retrieves a copy of security descriptor protecting the registry key
3344 * PARAMS
3345 * hkey [I] Open handle of key to set
3346 * SecurityInformation [I] Descriptor contents
3347 * pSecurityDescriptor [O] Address of descriptor for key
3348 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3350 * RETURNS
3351 * Success: ERROR_SUCCESS
3352 * Failure: Error code
3354 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3355 SECURITY_INFORMATION SecurityInformation,
3356 LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3357 LPDWORD lpcbSecurityDescriptor )
3359 LPKEYSTRUCT lpkey;
3361 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3362 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3364 lpkey = lookup_hkey( hkey );
3365 if (!lpkey)
3366 return ERROR_INVALID_HANDLE;
3368 /* FIXME: Check for valid SecurityInformation values */
3370 if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3371 return ERROR_INSUFFICIENT_BUFFER;
3373 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3374 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3376 return ERROR_SUCCESS;
3380 /******************************************************************************
3381 * RegLoadKey32W [ADVAPI32.???]
3383 * PARAMS
3384 * hkey [I] Handle of open key
3385 * lpszSubKey [I] Address of name of subkey
3386 * lpszFile [I] Address of filename for registry information
3388 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3390 LPKEYSTRUCT lpkey;
3391 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3393 /* Do this check before the hkey check */
3394 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3395 return ERROR_INVALID_PARAMETER;
3397 lpkey = lookup_hkey( hkey );
3398 if (!lpkey)
3399 return ERROR_INVALID_HANDLE;
3401 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3402 debugstr_w(lpszFile));
3404 return ERROR_SUCCESS;
3408 /******************************************************************************
3409 * RegLoadKey32A [ADVAPI32.???]
3411 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3413 LONG ret;
3414 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3415 LPWSTR lpszFileW = strdupA2W(lpszFile);
3416 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3417 if(lpszFileW) free(lpszFileW);
3418 if(lpszSubKeyW) free(lpszSubKeyW);
3419 return ret;
3423 /******************************************************************************
3424 * RegNotifyChangeKeyValue [ADVAPI32.???]
3426 * PARAMS
3427 * hkey [I] Handle of key to watch
3428 * fWatchSubTree [I] Flag for subkey notification
3429 * fdwNotifyFilter [I] Changes to be reported
3430 * hEvent [I] Handle of signaled event
3431 * fAsync [I] Flag for asynchronous reporting
3433 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3434 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3435 BOOL32 fAsync )
3437 LPKEYSTRUCT lpkey;
3438 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3439 hEvent,fAsync);
3441 lpkey = lookup_hkey( hkey );
3442 if (!lpkey)
3443 return ERROR_INVALID_HANDLE;
3445 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3446 hEvent,fAsync);
3448 return ERROR_SUCCESS;
3452 /******************************************************************************
3453 * RegUnLoadKey32W [ADVAPI32.173]
3455 * PARAMS
3456 * hkey [I] Handle of open key
3457 * lpSubKey [I] Address of name of subkey to unload
3459 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3461 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3462 return ERROR_SUCCESS;
3466 /******************************************************************************
3467 * RegUnLoadKey32A [ADVAPI32.172]
3469 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3471 LONG ret;
3472 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3473 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3474 if(lpSubKeyW) free(lpSubKeyW);
3475 return ret;
3479 /******************************************************************************
3480 * RegSetKeySecurity [ADVAPI32.167]
3482 * PARAMS
3483 * hkey [I] Open handle of key to set
3484 * SecurityInfo [I] Descriptor contents
3485 * pSecurityDesc [I] Address of descriptor for key
3487 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3488 LPSECURITY_DESCRIPTOR pSecurityDesc )
3490 LPKEYSTRUCT lpkey;
3492 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3494 /* It seems to perform this check before the hkey check */
3495 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3496 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3497 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3498 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3499 /* Param OK */
3500 } else
3501 return ERROR_INVALID_PARAMETER;
3503 if (!pSecurityDesc)
3504 return ERROR_INVALID_PARAMETER;
3506 lpkey = lookup_hkey( hkey );
3507 if (!lpkey)
3508 return ERROR_INVALID_HANDLE;
3510 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3512 return ERROR_SUCCESS;
3516 /******************************************************************************
3517 * RegSaveKey32W [ADVAPI32.166]
3519 * PARAMS
3520 * hkey [I] Handle of key where save begins
3521 * lpFile [I] Address of filename to save to
3522 * sa [I] Address of security structure
3524 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3525 LPSECURITY_ATTRIBUTES sa )
3527 LPKEYSTRUCT lpkey;
3529 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3531 /* It appears to do this check before the hkey check */
3532 if (!lpFile || !*lpFile)
3533 return ERROR_INVALID_PARAMETER;
3535 lpkey = lookup_hkey( hkey );
3536 if (!lpkey)
3537 return ERROR_INVALID_HANDLE;
3539 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3541 return ERROR_SUCCESS;
3545 /******************************************************************************
3546 * RegSaveKey32A [ADVAPI32.165]
3548 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3549 LPSECURITY_ATTRIBUTES sa )
3551 LONG ret;
3552 LPWSTR lpFileW = strdupA2W(lpFile);
3553 ret = RegSaveKey32W( hkey, lpFileW, sa );
3554 free(lpFileW);
3555 return ret;
3559 /******************************************************************************
3560 * RegRestoreKey32W [ADVAPI32.164]
3562 * PARAMS
3563 * hkey [I] Handle of key where restore begins
3564 * lpFile [I] Address of filename containing saved tree
3565 * dwFlags [I] Optional flags
3567 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3569 LPKEYSTRUCT lpkey;
3571 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3573 /* It seems to do this check before the hkey check */
3574 if (!lpFile || !*lpFile)
3575 return ERROR_INVALID_PARAMETER;
3577 lpkey = lookup_hkey( hkey );
3578 if (!lpkey)
3579 return ERROR_INVALID_HANDLE;
3581 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3583 /* Check for file existence */
3585 return ERROR_SUCCESS;
3589 /******************************************************************************
3590 * RegRestoreKey32A [ADVAPI32.163]
3592 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3594 LONG ret;
3595 LPWSTR lpFileW = strdupA2W(lpFile);
3596 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3597 if(lpFileW) free(lpFileW);
3598 return ret;
3602 /******************************************************************************
3603 * RegReplaceKey32W [ADVAPI32.162]
3605 * PARAMS
3606 * hkey [I] Handle of open key
3607 * lpSubKey [I] Address of name of subkey
3608 * lpNewFile [I] Address of filename for file with new data
3609 * lpOldFile [I] Address of filename for backup file
3611 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3612 LPCWSTR lpOldFile )
3614 LPKEYSTRUCT lpkey;
3616 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3617 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3619 lpkey = lookup_hkey( hkey );
3620 if (!lpkey)
3621 return ERROR_INVALID_HANDLE;
3623 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3624 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3626 return ERROR_SUCCESS;
3630 /******************************************************************************
3631 * RegReplaceKey32A [ADVAPI32.161]
3633 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3634 LPCSTR lpOldFile )
3636 LONG ret;
3637 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3638 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3639 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3640 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3641 free(lpOldFileW);
3642 free(lpNewFileW);
3643 free(lpSubKeyW);
3644 return ret;