Release 980601
[wine.git] / misc / registry.c
blob55307e50e79bb6f0b666f36d9da444b37721432f
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
6 * December 21, 1997 - Kevin Cozens
7 * Fixed bugs in the _w95_loadreg() function. Added extra information
8 * regarding the format of the Windows '95 registry files.
10 * May 5, 1998 - Matthew Becker
11 * Changed optionflags to DWORD instead of int because it could be 0x8000000
12 * All error return values must come from winerror.h
14 * NOTES
15 * When changing this file, please re-run the regtest program to ensure
16 * the conditions are handled properly.
18 * TODO
19 * Security access
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <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))
97 * FIXME
98 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
99 * If so, can we remove them?
100 * ANSWER
101 * No, the memory handling functions are called very often in here,
102 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
103 * loading 100 times slower. -MM
105 static LPWSTR strdupA2W(LPCSTR src)
107 LPWSTR dest=xmalloc(2*strlen(src)+2);
108 lstrcpyAtoW(dest,src);
109 return dest;
112 static LPWSTR strdupW(LPCWSTR a) {
113 LPWSTR b;
114 int len;
116 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
117 b=(LPWSTR)xmalloc(len);
118 memcpy(b,a,len);
119 return b;
123 static struct openhandle {
124 LPKEYSTRUCT lpkey;
125 HKEY hkey;
126 REGSAM accessmask;
127 } *openhandles=NULL;
128 static int nrofopenhandles=0;
129 static int currenthandle=1;
132 /******************************************************************************
133 * add_handle [Internal]
135 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
137 int i;
139 TRACE(reg,"(%x,%p,%lx)\n",hkey,lpkey,accessmask);
140 if (lpkey)
141 TRACE(reg," (%s)\n",debugstr_w(lpkey->keyname));
143 /* Check for duplicates */
144 for (i=0;i<nrofopenhandles;i++) {
145 if (openhandles[i].lpkey==lpkey) {
146 /* This is not really an error - the user is allowed to create
147 two (or more) handles to the same key */
148 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
150 if (openhandles[i].hkey==hkey) {
151 WARN(reg, "Adding handle %x twice\n",hkey);
154 openhandles=xrealloc( openhandles,
155 sizeof(struct openhandle)*(nrofopenhandles+1));
157 openhandles[i].lpkey = lpkey;
158 openhandles[i].hkey = hkey;
159 openhandles[i].accessmask = accessmask;
160 nrofopenhandles++;
164 /******************************************************************************
165 * get_handle [Internal]
167 * RETURNS
168 * Success: Pointer to key
169 * Failure: NULL
171 static LPKEYSTRUCT get_handle( HKEY hkey )
173 int i;
175 for (i=0; i<nrofopenhandles; i++)
176 if (openhandles[i].hkey == hkey)
177 return openhandles[i].lpkey;
178 WARN(reg, "Could not find handle %x\n",hkey);
179 return NULL;
183 /******************************************************************************
184 * remove_handle [Internal]
186 * PARAMS
187 * hkey [I] Handle of key to remove
189 * RETURNS
190 * Success: ERROR_SUCCESS
191 * Failure: ERROR_INVALID_HANDLE
193 static DWORD remove_handle( HKEY hkey )
195 int i;
197 for (i=0;i<nrofopenhandles;i++)
198 if (openhandles[i].hkey==hkey)
199 break;
201 if (i == nrofopenhandles) {
202 WARN(reg, "Could not find handle %x\n",hkey);
203 return ERROR_INVALID_HANDLE;
206 memcpy( openhandles+i,
207 openhandles+i+1,
208 sizeof(struct openhandle)*(nrofopenhandles-i-1)
210 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
211 nrofopenhandles--;
212 return ERROR_SUCCESS;
216 /******************************************************************************
217 * lookup_hkey [Internal]
219 * Just as the name says. Creates the root keys on demand, so we can call the
220 * Reg* functions at any time.
222 * RETURNS
223 * Success: Pointer to key structure
224 * Failure: NULL
226 #define ADD_ROOT_KEY(xx) \
227 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
228 memset(xx,'\0',sizeof(KEYSTRUCT));\
229 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
231 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
233 switch (hkey) {
234 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
235 * some programs. Do not remove those cases. -MM
237 case 0x00000000:
238 case 0x00000001:
239 case HKEY_CLASSES_ROOT: {
240 if (!key_classes_root) {
241 HKEY cl_r_hkey;
243 /* calls lookup_hkey recursively, TWICE */
244 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
245 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
246 exit(1);
248 key_classes_root = lookup_hkey(cl_r_hkey);
250 return key_classes_root;
252 case HKEY_CURRENT_USER:
253 if (!key_current_user) {
254 HKEY c_u_hkey;
255 struct passwd *pwd;
257 pwd=getpwuid(getuid());
258 /* calls lookup_hkey recursively, TWICE */
259 if (pwd && pwd->pw_name) {
260 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
261 ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
262 exit(1);
264 key_current_user = lookup_hkey(c_u_hkey);
265 } else {
266 /* nothing found, use standalone */
267 ADD_ROOT_KEY(key_current_user);
270 return key_current_user;
271 case HKEY_LOCAL_MACHINE:
272 if (!key_local_machine) {
273 ADD_ROOT_KEY(key_local_machine);
274 REGISTRY_Init();
276 return key_local_machine;
277 case HKEY_USERS:
278 if (!key_users) {
279 ADD_ROOT_KEY(key_users);
281 return key_users;
282 case HKEY_PERFORMANCE_DATA:
283 if (!key_performance_data) {
284 ADD_ROOT_KEY(key_performance_data);
286 return key_performance_data;
287 case HKEY_DYN_DATA:
288 if (!key_dyn_data) {
289 ADD_ROOT_KEY(key_dyn_data);
291 return key_dyn_data;
292 case HKEY_CURRENT_CONFIG:
293 if (!key_current_config) {
294 ADD_ROOT_KEY(key_current_config);
296 return key_current_config;
297 default:
298 return get_handle(hkey);
300 /*NOTREACHED*/
302 #undef ADD_ROOT_KEY
303 /* so we don't accidently access them ... */
304 #define key_current_config NULL NULL
305 #define key_current_user NULL NULL
306 #define key_users NULL NULL
307 #define key_local_machine NULL NULL
308 #define key_classes_root NULL NULL
309 #define key_dyn_data NULL NULL
310 #define key_performance_data NULL NULL
312 /******************************************************************************
313 * split_keypath [Internal]
314 * splits the unicode string 'wp' into an array of strings.
315 * the array is allocated by this function.
316 * Free the array using FREE_KEY_PATH
318 * PARAMS
319 * wp [I] String to split up
320 * wpv [O] Array of pointers to strings
321 * wpc [O] Number of components
323 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
325 int i,j,len;
326 LPWSTR ws;
328 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
330 ws = HEAP_strdupW( SystemHeap, 0, wp );
332 /* We know we have at least one substring */
333 *wpc = 1;
335 /* Replace each backslash with NULL, and increment the count */
336 for (i=0;ws[i];i++) {
337 if (ws[i]=='\\') {
338 ws[i]=0;
339 (*wpc)++;
343 len = i;
345 /* Allocate the space for the array of pointers, leaving room for the
346 NULL at the end */
347 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
348 (*wpv)[0]= ws;
350 /* Assign each pointer to the appropriate character in the string */
351 j = 1;
352 for (i=1;i<len;i++)
353 if (ws[i-1]==0) {
354 (*wpv)[j++]=ws+i;
355 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
358 (*wpv)[j]=NULL;
360 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
365 /******************************************************************************
366 * REGISTRY_Init [Internal]
367 * Registry initialisation, allocates some default keys.
369 static void REGISTRY_Init() {
370 HKEY hkey;
371 char buf[200];
373 TRACE(reg,"(void)\n");
375 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
376 RegCloseKey(hkey);
378 /* This was an Open, but since it is called before the real registries
379 are loaded, it was changed to a Create - MTB 980507*/
380 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
381 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
382 RegCloseKey(hkey);
384 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
385 * CurrentVersion
386 * CurrentBuildNumber
387 * CurrentType
388 * string RegisteredOwner
389 * string RegisteredOrganization
392 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
393 * string SysContact
394 * string SysLocation
395 * SysServices
397 if (-1!=gethostname(buf,200)) {
398 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
399 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
400 RegCloseKey(hkey);
405 /************************ SAVE Registry Function ****************************/
407 #define REGISTRY_SAVE_VERSION 0x00000001
409 /* Registry saveformat:
410 * If you change it, increase above number by 1, which will flush
411 * old registry database files.
413 * Global:
414 * "WINE REGISTRY Version %d"
415 * subkeys....
416 * Subkeys:
417 * keyname
418 * valuename=lastmodified,type,data
419 * ...
420 * subkeys
421 * ...
422 * keyname,valuename,stringdata:
423 * the usual ascii characters from 0x00-0xff (well, not 0x00)
424 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
425 * ( "=\\\t" escaped in \uXXXX form.)
426 * type,lastmodified:
427 * int
429 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
431 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
432 * SaveOnlyUpdatedKeys=yes
434 static int
435 _save_check_tainted(LPKEYSTRUCT lpkey) {
436 int tainted;
438 if (!lpkey)
439 return 0;
440 if (lpkey->flags & REG_OPTION_TAINTED)
441 tainted = 1;
442 else
443 tainted = 0;
444 while (lpkey) {
445 if (_save_check_tainted(lpkey->nextsub)) {
446 lpkey->flags |= REG_OPTION_TAINTED;
447 tainted = 1;
449 lpkey = lpkey->next;
451 return tainted;
454 static void
455 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
456 LPWSTR s;
457 int doescape;
459 if (wstr==NULL)
460 return;
461 s=wstr;
462 while (*s) {
463 doescape=0;
464 if (*s>0xff)
465 doescape = 1;
466 if (*s=='\n')
467 doescape = 1;
468 if (escapeeq && *s=='=')
469 doescape = 1;
470 if (*s=='\\')
471 fputc(*s,F); /* if \\ then put it twice. */
472 if (doescape)
473 fprintf(F,"\\u%04x",*((unsigned short*)s));
474 else
475 fputc(*s,F);
476 s++;
480 static int
481 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
482 LPKEYSTRUCT lpxkey;
483 int i,tabs,j;
485 lpxkey = lpkey;
486 while (lpxkey) {
487 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
488 (all || (lpxkey->flags & REG_OPTION_TAINTED))
490 for (tabs=level;tabs--;)
491 fputc('\t',F);
492 _save_USTRING(F,lpxkey->keyname,1);
493 fputs("\n",F);
494 for (i=0;i<lpxkey->nrofvalues;i++) {
495 LPKEYVALUE val=lpxkey->values+i;
497 for (tabs=level+1;tabs--;)
498 fputc('\t',F);
499 _save_USTRING(F,val->name,0);
500 fputc('=',F);
501 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
502 if ((1<<val->type) & UNICONVMASK)
503 _save_USTRING(F,(LPWSTR)val->data,0);
504 else
505 for (j=0;j<val->len;j++)
506 fprintf(F,"%02x",*((unsigned char*)val->data+j));
507 fputs("\n",F);
509 /* descend recursively */
510 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
511 return 0;
513 lpxkey=lpxkey->next;
515 return 1;
518 static int
519 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
520 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
521 _save_check_tainted(lpkey->nextsub);
522 return _savesubkey(F,lpkey->nextsub,0,all);
525 static BOOL32
526 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
527 FILE *F;
529 F=fopen(fn,"w");
530 if (F==NULL) {
531 WARN(reg,"Couldn't open %s for writing: %s\n",
532 fn,strerror(errno)
534 return FALSE;
536 if (!_savesubreg(F,lpkey,all)) {
537 fclose(F);
538 unlink(fn);
539 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
540 return FALSE;
542 fclose(F);
543 return TRUE;
547 /******************************************************************************
548 * SHELL_SaveRegistry [Internal]
550 void SHELL_SaveRegistry( void )
552 char *fn;
553 struct passwd *pwd;
554 char buf[4];
555 HKEY hkey;
556 int all;
558 TRACE(reg,"(void)\n");
560 all=0;
561 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
562 strcpy(buf,"yes");
563 } else {
564 DWORD len,junk,type;
566 len=4;
567 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
568 hkey,
569 VAL_SAVEUPDATED,
570 &junk,
571 &type,
572 buf,
573 &len
574 ))|| (type!=REG_SZ)
576 strcpy(buf,"yes");
577 RegCloseKey(hkey);
579 if (lstrcmpi32A(buf,"yes"))
580 all=1;
581 pwd=getpwuid(getuid());
582 if (pwd!=NULL && pwd->pw_dir!=NULL)
584 char *tmp;
586 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
587 strlen(SAVE_CURRENT_USER) + 2 );
588 strcpy(fn,pwd->pw_dir);
589 strcat(fn,WINE_PREFIX);
590 /* create the directory. don't care about errorcodes. */
591 mkdir(fn,0755); /* drwxr-xr-x */
592 strcat(fn,"/"SAVE_CURRENT_USER);
593 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
594 strcpy(tmp,fn);strcat(tmp,".tmp");
595 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
596 if (-1==rename(tmp,fn)) {
597 perror("rename tmp registry");
598 unlink(tmp);
601 free(tmp);
602 free(fn);
603 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
604 strcpy(fn,pwd->pw_dir);
605 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
606 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
607 strcpy(tmp,fn);strcat(tmp,".tmp");
608 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
609 if (-1==rename(tmp,fn)) {
610 perror("rename tmp registry");
611 unlink(tmp);
614 free(tmp);
615 free(fn);
616 } else
617 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
620 /************************ LOAD Registry Function ****************************/
623 /******************************************************************************
624 * _find_or_add_key [Internal]
626 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
628 LPKEYSTRUCT lpxkey,*lplpkey;
630 if ((!keyname) || (keyname[0]==0)) {
631 free(keyname);
632 return lpkey;
634 lplpkey= &(lpkey->nextsub);
635 lpxkey = *lplpkey;
636 while (lpxkey) {
637 if (!lstrcmpi32W(lpxkey->keyname,keyname))
638 break;
639 lplpkey = &(lpxkey->next);
640 lpxkey = *lplpkey;
642 if (lpxkey==NULL) {
643 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
644 lpxkey = *lplpkey;
645 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
646 lpxkey->keyname = keyname;
647 } else
648 free(keyname);
649 return lpxkey;
652 static void
653 _find_or_add_value(
654 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
655 DWORD lastmodified
657 LPKEYVALUE val=NULL;
658 int i;
660 if (name && !*name) {/* empty string equals default (NULL) value */
661 free(name);
662 name = NULL;
665 for (i=0;i<lpkey->nrofvalues;i++) {
666 val=lpkey->values+i;
667 if (name==NULL) {
668 if (val->name==NULL)
669 break;
670 } else {
671 if ( val->name!=NULL &&
672 !lstrcmpi32W(val->name,name)
674 break;
677 if (i==lpkey->nrofvalues) {
678 lpkey->values = xrealloc(
679 lpkey->values,
680 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
682 val=lpkey->values+i;
683 memset(val,'\0',sizeof(KEYVALUE));
684 val->name = name;
685 } else {
686 if (name)
687 free(name);
689 if (val->lastmodified<lastmodified) {
690 val->lastmodified=lastmodified;
691 val->type = type;
692 val->len = len;
693 if (val->data)
694 free(val->data);
695 val->data = data;
696 } else
697 free(data);
701 /* reads a line including dynamically enlarging the readbuffer and throwing
702 * away comments
704 static int
705 _wine_read_line(FILE *F,char **buf,int *len) {
706 char *s,*curread;
707 int mylen,curoff;
709 curread = *buf;
710 mylen = *len;
711 **buf = '\0';
712 while (1) {
713 while (1) {
714 s=fgets(curread,mylen,F);
715 if (s==NULL)
716 return 0; /* EOF */
717 if (NULL==(s=strchr(curread,'\n'))) {
718 /* buffer wasn't large enough */
719 curoff = strlen(*buf);
720 *buf = xrealloc(*buf,*len*2);
721 curread = *buf + curoff;
722 mylen = *len; /* we filled up the buffer and
723 * got new '*len' bytes to fill
725 *len = *len * 2;
726 } else {
727 *s='\0';
728 break;
731 /* throw away comments */
732 if (**buf=='#' || **buf==';') {
733 curread = *buf;
734 mylen = *len;
735 continue;
737 if (s) /* got end of line */
738 break;
740 return 1;
743 /* converts a char* into a UNICODE string (up to a special char)
744 * and returns the position exactly after that string
746 static char*
747 _wine_read_USTRING(char *buf,LPWSTR *str) {
748 char *s;
749 LPWSTR ws;
751 /* read up to "=" or "\0" or "\n" */
752 s = buf;
753 if (*s == '=') {
754 /* empty string is the win3.1 default value(NULL)*/
755 *str = NULL;
756 return s;
758 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
759 ws = *str;
760 while (*s && (*s!='\n') && (*s!='=')) {
761 if (*s!='\\')
762 *ws++=*((unsigned char*)s++);
763 else {
764 s++;
765 if (*s=='\\') {
766 *ws++='\\';
767 s++;
768 continue;
770 if (*s!='u') {
771 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
772 *ws++='\\';
773 *ws++=*s++;
774 } else {
775 char xbuf[5];
776 int wc;
778 s++;
779 memcpy(xbuf,s,4);xbuf[4]='\0';
780 if (!sscanf(xbuf,"%x",&wc))
781 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
782 s+=4;
783 *ws++ =(unsigned short)wc;
787 *ws = 0;
788 ws = *str;
789 if (*ws)
790 *str = strdupW(*str);
791 else
792 *str = NULL;
793 free(ws);
794 return s;
798 /******************************************************************************
799 * _wine_loadsubkey [Internal]
801 * NOTES
802 * It seems like this is returning a boolean. Should it?
804 * RETURNS
805 * Success: 1
806 * Failure: 0
808 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
809 int *buflen, DWORD optflag )
811 LPKEYSTRUCT lpxkey;
812 int i;
813 char *s;
814 LPWSTR name;
816 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
817 *buflen, optflag);
819 lpkey->flags |= optflag;
821 /* Good. We already got a line here ... so parse it */
822 lpxkey = NULL;
823 while (1) {
824 i=0;s=*buf;
825 while (*s=='\t') {
826 s++;
827 i++;
829 if (i>level) {
830 if (lpxkey==NULL) {
831 WARN(reg,"Got a subhierarchy without resp. key?\n");
832 return 0;
834 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
835 continue;
838 /* let the caller handle this line */
839 if (i<level || **buf=='\0')
840 return 1;
842 /* it can be: a value or a keyname. Parse the name first */
843 s=_wine_read_USTRING(s,&name);
845 /* switch() default: hack to avoid gotos */
846 switch (0) {
847 default:
848 if (*s=='\0') {
849 lpxkey=_find_or_add_key(lpkey,name);
850 } else {
851 LPBYTE data;
852 int len,lastmodified,type;
854 if (*s!='=') {
855 WARN(reg,"Unexpected character: %c\n",*s);
856 break;
858 s++;
859 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
860 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
861 break;
863 /* skip the 2 , */
864 s=strchr(s,',');s++;
865 s=strchr(s,',');s++;
866 if ((1<<type) & UNICONVMASK) {
867 s=_wine_read_USTRING(s,(LPWSTR*)&data);
868 if (data)
869 len = lstrlen32W((LPWSTR)data)*2+2;
870 else
871 len = 0;
872 } else {
873 len=strlen(s)/2;
874 data = (LPBYTE)xmalloc(len+1);
875 for (i=0;i<len;i++) {
876 data[i]=0;
877 if (*s>='0' && *s<='9')
878 data[i]=(*s-'0')<<4;
879 if (*s>='a' && *s<='f')
880 data[i]=(*s-'a'+'\xa')<<4;
881 if (*s>='A' && *s<='F')
882 data[i]=(*s-'A'+'\xa')<<4;
883 s++;
884 if (*s>='0' && *s<='9')
885 data[i]|=*s-'0';
886 if (*s>='a' && *s<='f')
887 data[i]|=*s-'a'+'\xa';
888 if (*s>='A' && *s<='F')
889 data[i]|=*s-'A'+'\xa';
890 s++;
893 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
896 /* read the next line */
897 if (!_wine_read_line(F,buf,buflen))
898 return 1;
900 return 1;
904 /******************************************************************************
905 * _wine_loadsubreg [Internal]
907 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
909 int ver;
910 char *buf;
911 int buflen;
913 buf=xmalloc(10);buflen=10;
914 if (!_wine_read_line(F,&buf,&buflen)) {
915 free(buf);
916 return 0;
918 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
919 free(buf);
920 return 0;
922 if (ver!=REGISTRY_SAVE_VERSION) {
923 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
924 free(buf);
925 return 0;
927 if (!_wine_read_line(F,&buf,&buflen)) {
928 free(buf);
929 return 0;
931 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
932 free(buf);
933 return 0;
935 free(buf);
936 return 1;
940 /******************************************************************************
941 * _wine_loadreg [Internal]
943 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
945 FILE *F;
947 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
949 F = fopen(fn,"rb");
950 if (F==NULL) {
951 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
952 return;
954 if (!_wine_loadsubreg(F,lpkey,optflag)) {
955 fclose(F);
956 unlink(fn);
957 return;
959 fclose(F);
963 /******************************************************************************
964 * _copy_registry [Internal]
966 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
968 LPKEYSTRUCT lpxkey;
969 int j;
970 LPKEYVALUE valfrom;
972 from=from->nextsub;
973 while (from) {
974 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
976 for (j=0;j<from->nrofvalues;j++) {
977 LPWSTR name;
978 LPBYTE data;
980 valfrom = from->values+j;
981 name=valfrom->name;
982 if (name) name=strdupW(name);
983 data=(LPBYTE)xmalloc(valfrom->len);
984 memcpy(data,valfrom->data,valfrom->len);
986 _find_or_add_value(
987 lpxkey,
988 name,
989 valfrom->type,
990 data,
991 valfrom->len,
992 valfrom->lastmodified
995 _copy_registry(from,lpxkey);
996 from = from->next;
1001 /* WINDOWS 95 REGISTRY LOADER */
1003 * Structure of a win95 registry database.
1004 * main header:
1005 * 0 : "CREG" - magic
1006 * 4 : DWORD version
1007 * 8 : DWORD offset_of_RGDB_part
1008 * 0C..0F: ? (someone fill in please)
1009 * 10: WORD number of RGDB blocks
1010 * 12: WORD ?
1011 * 14: WORD always 0000?
1012 * 16: WORD always 0001?
1013 * 18..1F: ? (someone fill in please)
1015 * 20: RGKN_section:
1016 * header:
1017 * 0 : "RGKN" - magic
1018 * 4 : DWORD offset to first RGDB section
1019 * 8 : DWORD offset to ?
1020 * C..0x1B: ? (fill in)
1021 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1023 * Disk Key Entry Structure:
1024 * 00: DWORD - Free entry indicator(?)
1025 * 04: DWORD - Hash = sum of bytes of keyname
1026 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1027 * 0C: DWORD - disk address of PreviousLevel Key.
1028 * 10: DWORD - disk address of Next Sublevel Key.
1029 * 14: DWORD - disk address of Next Key (on same level).
1030 * DKEP>18: WORD - Nr, Low Significant part.
1031 * 1A: WORD - Nr, High Significant part.
1033 * The disk address always points to the nr part of the previous key entry
1034 * of the referenced key. Don't ask me why, or even if I got this correct
1035 * from staring at 1kg of hexdumps. (DKEP)
1037 * The High significant part of the structure seems to equal the number
1038 * of the RGDB section. The low significant part is a unique ID within
1039 * that RGDB section
1041 * There are two minor corrections to the position of that structure.
1042 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1043 * the DKE reread from there.
1044 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1045 * CPS - I have not experienced the above phenomenon in my registry files
1047 * RGDB_section:
1048 * 00: "RGDB" - magic
1049 * 04: DWORD offset to next RGDB section
1050 * 08: DWORD ?
1051 * 0C: WORD always 000d?
1052 * 0E: WORD RGDB block number
1053 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1054 * 14..1F: ?
1055 * 20.....: disk keys
1057 * disk key:
1058 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1059 * 08: WORD nrLS - low significant part of NR
1060 * 0A: WORD nrHS - high significant part of NR
1061 * 0C: DWORD bytesused - bytes used in this structure.
1062 * 10: WORD name_len - length of name in bytes. without \0
1063 * 12: WORD nr_of_values - number of values.
1064 * 14: char name[name_len] - name string. No \0.
1065 * 14+name_len: disk values
1066 * nextkeyoffset: ... next disk key
1068 * disk value:
1069 * 00: DWORD type - value type (hmm, could be WORD too)
1070 * 04: DWORD - unknown, usually 0
1071 * 08: WORD namelen - length of Name. 0 means name=NULL
1072 * 0C: WORD datalen - length of Data.
1073 * 10: char name[namelen] - name, no \0
1074 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1075 * 10+namelen+datalen: next values or disk key
1077 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1078 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1079 * structure) and reading another RGDB_section.
1080 * repeat until end of file.
1082 * An interesting relationship exists in RGDB_section. The value at offset
1083 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1084 * idea at the moment what this means. (Kevin Cozens)
1086 * FIXME: this description needs some serious help, yes.
1089 struct _w95keyvalue {
1090 unsigned long type;
1091 unsigned short datalen;
1092 char *name;
1093 unsigned char *data;
1094 unsigned long x1;
1095 int lastmodified;
1098 struct _w95key {
1099 char *name;
1100 int nrofvals;
1101 struct _w95keyvalue *values;
1102 struct _w95key *prevlvl;
1103 struct _w95key *nextsub;
1104 struct _w95key *next;
1108 struct _w95_info {
1109 char *rgknbuffer;
1110 int rgknsize;
1111 char *rgdbbuffer;
1112 int rgdbsize;
1113 int depth;
1114 int lastmodified;
1117 LPWSTR strcvtA2W(LPCSTR src, int nchars)
1120 LPWSTR dest = xmalloc (2 * nchars + 2);
1122 lstrcpynAtoW(dest,src,nchars+1);
1123 dest[nchars] = 0;
1124 return dest;
1128 /******************************************************************************
1129 * _w95_processKey [Internal]
1131 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1132 int nrLS, int nrMS, struct _w95_info *info )
1135 /* Disk Key Header structure (RGDB part) */
1136 struct dkh {
1137 unsigned long nextkeyoff;
1138 unsigned short nrLS;
1139 unsigned short nrMS;
1140 unsigned long bytesused;
1141 unsigned short keynamelen;
1142 unsigned short values;
1143 unsigned long xx1;
1144 /* keyname */
1145 /* disk key values or nothing */
1147 /* Disk Key Value structure */
1148 struct dkv {
1149 unsigned long type;
1150 unsigned long x1;
1151 unsigned short valnamelen;
1152 unsigned short valdatalen;
1153 /* valname, valdata */
1157 struct dkh dkh;
1158 int bytesread = 0;
1159 char *rgdbdata = info->rgdbbuffer;
1160 int nbytes = info->rgdbsize;
1161 char *curdata = rgdbdata;
1162 char *end = rgdbdata + nbytes;
1163 int off_next_rgdb;
1164 char *next = rgdbdata;
1165 int nrgdb, i;
1166 LPKEYSTRUCT lpxkey;
1168 do {
1169 curdata = next;
1170 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1172 memcpy(&off_next_rgdb,curdata+4,4);
1173 next = curdata + off_next_rgdb;
1174 nrgdb = (int) *((short *)curdata + 7);
1176 } while (nrgdb != nrMS && (next < end));
1178 /* curdata now points to the start of the right RGDB section */
1179 curdata += 0x20;
1181 #define XREAD(whereto,len) \
1182 if ((curdata + len) <end) {\
1183 memcpy(whereto,curdata,len);\
1184 curdata+=len;\
1185 bytesread+=len;\
1188 do {
1189 XREAD(&dkh, sizeof (dkh));
1190 if (dkh.nrLS == nrLS) break;
1192 curdata += dkh.nextkeyoff - sizeof(dkh);
1193 } while (curdata < next);
1195 if (dkh.nrLS != nrLS) return (NULL);
1197 if (nrgdb != dkh.nrMS) {
1198 return (NULL);
1201 assert((dkh.keynamelen<2) || curdata[0]);
1202 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1203 curdata += dkh.keynamelen;
1205 for (i=0;i< dkh.values; i++) {
1206 struct dkv dkv;
1207 LPBYTE data;
1208 int len;
1209 LPWSTR name;
1211 XREAD(&dkv,sizeof(dkv));
1213 name = strcvtA2W(curdata, dkv.valnamelen);
1214 curdata += dkv.valnamelen;
1216 if ((1 << dkv.type) & UNICONVMASK) {
1217 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1218 len = 2*(dkv.valdatalen + 1);
1219 } else {
1220 /* I don't think we want to NULL terminate all data */
1221 data = xmalloc(dkv.valdatalen);
1222 memcpy (data, curdata, dkv.valdatalen);
1223 len = dkv.valdatalen;
1226 curdata += dkv.valdatalen;
1228 _find_or_add_value(
1229 lpxkey,
1230 name,
1231 dkv.type,
1232 data,
1233 len,
1234 info->lastmodified
1239 return (lpxkey);
1242 static void
1243 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1246 /* Disk Key Entry structure (RGKN part) */
1247 struct dke {
1248 unsigned long x1;
1249 unsigned long x2;
1250 unsigned long x3;/*usually 0xFFFFFFFF */
1251 unsigned long prevlvl;
1252 unsigned long nextsub;
1253 unsigned long next;
1254 unsigned short nrLS;
1255 unsigned short nrMS;
1256 } *dke = (struct dke *)off;
1257 LPKEYSTRUCT lpxkey;
1259 if (dke == NULL) {
1260 dke = (struct dke *) ((char *)info->rgknbuffer);
1263 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1264 /* XXX <-- This is a hack*/
1265 if (!lpxkey) {
1266 lpxkey = prevkey;
1269 if (dke->nextsub != -1 &&
1270 ((dke->nextsub - 0x20) < info->rgknsize)
1271 && (dke->nextsub > 0x20)) {
1273 _w95_walkrgkn(lpxkey,
1274 info->rgknbuffer + dke->nextsub - 0x20,
1275 info);
1278 if (dke->next != -1 &&
1279 ((dke->next - 0x20) < info->rgknsize) &&
1280 (dke->next > 0x20)) {
1281 _w95_walkrgkn(prevkey,
1282 info->rgknbuffer + dke->next - 0x20,
1283 info);
1286 return;
1289 static void
1290 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1291 HFILE32 hfd;
1292 char magic[5];
1293 unsigned long where,version,rgdbsection,end;
1294 struct _w95_info info;
1295 OFSTRUCT ofs;
1296 BY_HANDLE_FILE_INFORMATION hfdinfo;
1298 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1299 hfd=OpenFile32(fn,&ofs,OF_READ);
1300 if (hfd==HFILE_ERROR32)
1301 return;
1302 magic[4]=0;
1303 if (4!=_lread32(hfd,magic,4))
1304 return;
1305 if (strcmp(magic,"CREG")) {
1306 WARN(reg,"%s is not a w95 registry.\n",fn);
1307 return;
1309 if (4!=_lread32(hfd,&version,4))
1310 return;
1311 if (4!=_lread32(hfd,&rgdbsection,4))
1312 return;
1313 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1314 return;
1315 if (4!=_lread32(hfd,magic,4))
1316 return;
1317 if (strcmp(magic,"RGKN")) {
1318 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1319 return;
1322 /* STEP 1: Keylink structures */
1323 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1324 return;
1325 where = 0x40;
1326 end = rgdbsection;
1328 info.rgknsize = end - where;
1329 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1330 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1331 return;
1333 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1334 return;
1336 end = hfdinfo.nFileSizeLow;
1337 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1339 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1340 return;
1342 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1343 info.rgdbsize = end - rgdbsection;
1345 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1346 return;
1347 _lclose32(hfd);
1349 _w95_walkrgkn(lpkey, NULL, &info);
1351 free (info.rgdbbuffer);
1352 free (info.rgknbuffer);
1356 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1359 reghack - windows 3.11 registry data format demo program.
1361 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1362 a combined hash table and tree description, and finally a text table.
1364 The header is obvious from the struct header. The taboff1 and taboff2
1365 fields are always 0x20, and their usage is unknown.
1367 The 8-byte entry table has various entry types.
1369 tabent[0] is a root index. The second word has the index of the root of
1370 the directory.
1371 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1372 the index of the key/value that has that hash. Data with the same
1373 hash value are on a circular list. The other three words in the
1374 hash entry are always zero.
1375 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1376 entry: dirent and keyent/valent. They are identified by context.
1377 tabent[freeidx] is the first free entry. The first word in a free entry
1378 is the index of the next free entry. The last has 0 as a link.
1379 The other three words in the free list are probably irrelevant.
1381 Entries in text table are preceeded by a word at offset-2. This word
1382 has the value (2*index)+1, where index is the referring keyent/valent
1383 entry in the table. I have no suggestion for the 2* and the +1.
1384 Following the word, there are N bytes of data, as per the keyent/valent
1385 entry length. The offset of the keyent/valent entry is from the start
1386 of the text table to the first data byte.
1388 This information is not available from Microsoft. The data format is
1389 deduced from the reg.dat file by me. Mistakes may
1390 have been made. I claim no rights and give no guarantees for this program.
1392 Tor Sjøwall, tor@sn.no
1395 /* reg.dat header format */
1396 struct _w31_header {
1397 char cookie[8]; /* 'SHCC3.10' */
1398 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1399 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1400 unsigned long tabcnt; /* number of entries in index table */
1401 unsigned long textoff; /* offset of text part */
1402 unsigned long textsize; /* byte size of text part */
1403 unsigned short hashsize; /* hash size */
1404 unsigned short freeidx; /* free index */
1407 /* generic format of table entries */
1408 struct _w31_tabent {
1409 unsigned short w0, w1, w2, w3;
1412 /* directory tabent: */
1413 struct _w31_dirent {
1414 unsigned short sibling_idx; /* table index of sibling dirent */
1415 unsigned short child_idx; /* table index of child dirent */
1416 unsigned short key_idx; /* table index of key keyent */
1417 unsigned short value_idx; /* table index of value valent */
1420 /* key tabent: */
1421 struct _w31_keyent {
1422 unsigned short hash_idx; /* hash chain index for string */
1423 unsigned short refcnt; /* reference count */
1424 unsigned short length; /* length of string */
1425 unsigned short string_off; /* offset of string in text table */
1428 /* value tabent: */
1429 struct _w31_valent {
1430 unsigned short hash_idx; /* hash chain index for string */
1431 unsigned short refcnt; /* reference count */
1432 unsigned short length; /* length of string */
1433 unsigned short string_off; /* offset of string in text table */
1436 /* recursive helper function to display a directory tree */
1437 void
1438 __w31_dumptree( unsigned short idx,
1439 unsigned char *txt,
1440 struct _w31_tabent *tab,
1441 struct _w31_header *head,
1442 LPKEYSTRUCT lpkey,
1443 time_t lastmodified,
1444 int level
1446 struct _w31_dirent *dir;
1447 struct _w31_keyent *key;
1448 struct _w31_valent *val;
1449 LPKEYSTRUCT xlpkey = NULL;
1450 LPWSTR name,value;
1451 static char tail[400];
1453 while (idx!=0) {
1454 dir=(struct _w31_dirent*)&tab[idx];
1456 if (dir->key_idx) {
1457 key = (struct _w31_keyent*)&tab[dir->key_idx];
1459 memcpy(tail,&txt[key->string_off],key->length);
1460 tail[key->length]='\0';
1461 /* all toplevel entries AND the entries in the
1462 * toplevel subdirectory belong to \SOFTWARE\Classes
1464 if (!level && !lstrcmp32A(tail,".classes")) {
1465 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1466 idx=dir->sibling_idx;
1467 continue;
1469 name=strdupA2W(tail);
1471 xlpkey=_find_or_add_key(lpkey,name);
1473 /* only add if leaf node or valued node */
1474 if (dir->value_idx!=0||dir->child_idx==0) {
1475 if (dir->value_idx) {
1476 val=(struct _w31_valent*)&tab[dir->value_idx];
1477 memcpy(tail,&txt[val->string_off],val->length);
1478 tail[val->length]='\0';
1479 value=strdupA2W(tail);
1480 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1483 } else {
1484 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1486 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1487 idx=dir->sibling_idx;
1492 /******************************************************************************
1493 * _w31_loadreg [Internal]
1495 void _w31_loadreg() {
1496 HFILE32 hf;
1497 struct _w31_header head;
1498 struct _w31_tabent *tab;
1499 unsigned char *txt;
1500 int len;
1501 OFSTRUCT ofs;
1502 BY_HANDLE_FILE_INFORMATION hfinfo;
1503 time_t lastmodified;
1504 LPKEYSTRUCT lpkey;
1506 TRACE(reg,"(void)\n");
1508 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1509 if (hf==HFILE_ERROR32)
1510 return;
1512 /* read & dump header */
1513 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1514 ERR(reg, "reg.dat is too short.\n");
1515 _lclose32(hf);
1516 return;
1518 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1519 ERR(reg, "reg.dat has bad signature.\n");
1520 _lclose32(hf);
1521 return;
1524 len = head.tabcnt * sizeof(struct _w31_tabent);
1525 /* read and dump index table */
1526 tab = xmalloc(len);
1527 if (len!=_lread32(hf,tab,len)) {
1528 ERR(reg,"couldn't read %d bytes.\n",len);
1529 free(tab);
1530 _lclose32(hf);
1531 return;
1534 /* read text */
1535 txt = xmalloc(head.textsize);
1536 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1537 ERR(reg,"couldn't seek to textblock.\n");
1538 free(tab);
1539 free(txt);
1540 _lclose32(hf);
1541 return;
1543 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1544 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1545 free(tab);
1546 free(txt);
1547 _lclose32(hf);
1548 return;
1551 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1552 ERR(reg,"GetFileInformationByHandle failed?.\n");
1553 free(tab);
1554 free(txt);
1555 _lclose32(hf);
1556 return;
1558 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1559 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1560 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1561 free(tab);
1562 free(txt);
1563 _lclose32(hf);
1564 return;
1568 /**********************************************************************************
1569 * SHELL_LoadRegistry [Internal]
1571 void SHELL_LoadRegistry( void )
1573 char *fn;
1574 struct passwd *pwd;
1575 LPKEYSTRUCT lpkey;
1576 HKEY hkey;
1578 TRACE(reg,"(void)\n");
1580 /* Load windows 3.1 entries */
1581 _w31_loadreg();
1582 /* Load windows 95 entries */
1583 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1584 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1585 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1587 /* the global user default is loaded under HKEY_USERS\\.Default */
1588 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1589 lpkey = lookup_hkey(hkey);
1590 if(!lpkey)
1591 WARN(reg,"Could not create global user default key\n");
1592 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1594 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1595 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1596 RegCloseKey(hkey);
1598 /* the global machine defaults */
1599 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1601 /* load the user saved registries */
1603 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1605 pwd=getpwuid(getuid());
1606 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1607 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1608 strcpy(fn,pwd->pw_dir);
1609 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1610 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1611 free(fn);
1612 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1613 strcpy(fn,pwd->pw_dir);
1614 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1615 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1616 free(fn);
1617 } else
1618 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1619 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1620 DWORD junk,type,len;
1621 char data[5];
1623 len=4;
1624 if (( RegQueryValueEx32A(
1625 hkey,
1626 VAL_SAVEUPDATED,
1627 &junk,
1628 &type,
1629 data,
1630 &len
1631 )!=ERROR_SUCCESS) ||
1632 type != REG_SZ
1634 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1635 RegCloseKey(hkey);
1640 /********************* API FUNCTIONS ***************************************/
1642 * Open Keys.
1644 * All functions are stubs to RegOpenKeyEx32W where all the
1645 * magic happens.
1647 * FIXME: security,options,desiredaccess,...
1649 * Callpath:
1650 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1651 * RegOpenKey32W -> RegOpenKeyEx32W
1655 /******************************************************************************
1656 * RegOpenKeyEx32W [ADVAPI32.150]
1657 * Opens the specified key
1659 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1661 * PARAMS
1662 * hkey [I] Handle of open key
1663 * lpszSubKey [I] Name of subkey to open
1664 * dwReserved [I] Reserved - must be zero
1665 * samDesired [I] Security access mask
1666 * retkey [O] Address of handle of open key
1668 * RETURNS
1669 * Success: ERROR_SUCCESS
1670 * Failure: Error code
1672 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1673 REGSAM samDesired, LPHKEY retkey )
1675 LPKEYSTRUCT lpNextKey,lpxkey;
1676 LPWSTR *wps;
1677 int wpc,i;
1679 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1680 samDesired,retkey);
1682 lpNextKey = lookup_hkey(hkey);
1683 if (!lpNextKey) {
1684 WARN(reg,"Invalid handle: %x\n",hkey);
1685 return ERROR_INVALID_HANDLE;
1688 if (!lpszSubKey || !*lpszSubKey) {
1689 /* Either NULL or pointer to empty string, so return a new handle
1690 to the original hkey */
1691 add_handle(++currenthandle,lpNextKey,samDesired);
1692 *retkey=currenthandle;
1693 return ERROR_SUCCESS;
1696 split_keypath(lpszSubKey,&wps,&wpc);
1697 i = 0;
1698 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1699 lpxkey = lpNextKey;
1701 while (wps[i]) {
1702 lpxkey=lpNextKey->nextsub;
1703 while (lpxkey) {
1704 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1705 break;
1707 lpxkey=lpxkey->next;
1710 if (!lpxkey) {
1711 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1712 FREE_KEY_PATH;
1713 return ERROR_BADKEY;
1715 i++;
1716 lpNextKey = lpxkey;
1719 add_handle(++currenthandle,lpxkey,samDesired);
1720 *retkey = currenthandle;
1721 TRACE(reg," Returning %x\n", currenthandle);
1722 FREE_KEY_PATH;
1723 return ERROR_SUCCESS;
1727 /******************************************************************************
1728 * RegOpenKey32W [ADVAPI32.151]
1730 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1732 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1733 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1737 /******************************************************************************
1738 * RegOpenKeyEx32A [ADVAPI32.149]
1740 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1741 REGSAM samDesired, LPHKEY retkey )
1743 LPWSTR lpszSubKeyW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
1744 DWORD ret;
1746 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1747 samDesired,retkey);
1749 ret = RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1750 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
1751 return ret;
1755 /******************************************************************************
1756 * RegOpenKey32A [ADVAPI32.148]
1758 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1760 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1761 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1765 /******************************************************************************
1766 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1768 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1770 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1771 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1776 * Create keys
1778 * All those functions convert their respective
1779 * arguments and call RegCreateKeyExW at the end.
1781 * FIXME: no security,no access attrib,no optionhandling yet.
1783 * Callpath:
1784 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1785 * RegCreateKey32W -> RegCreateKeyEx32W
1789 /******************************************************************************
1790 * RegCreateKeyEx32W [ADVAPI32.131]
1792 * PARAMS
1793 * ...
1794 * retkey [O] Address of buffer for opened handle
1795 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1797 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey,
1798 DWORD dwReserved, LPWSTR lpszClass,
1799 DWORD fdwOptions, REGSAM samDesired,
1800 LPSECURITY_ATTRIBUTES lpSecAttribs,
1801 LPHKEY retkey, LPDWORD lpDispos )
1803 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1804 LPWSTR *wps;
1805 int wpc,i;
1807 /*FIXME: handle security/access/whatever */
1809 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1810 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1811 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1813 lpNextKey = lookup_hkey(hkey);
1814 if (!lpNextKey)
1815 return ERROR_BADKEY;
1817 if (!lpszSubKey || !*lpszSubKey) {
1818 add_handle(++currenthandle,lpNextKey,samDesired);
1819 *retkey=currenthandle;
1820 TRACE(reg, "Returning %x\n", currenthandle);
1821 lpNextKey->flags|=REG_OPTION_TAINTED;
1822 return ERROR_SUCCESS;
1825 if (lpszSubKey[0] == '\\') {
1826 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1827 return ERROR_BAD_PATHNAME;
1830 split_keypath(lpszSubKey,&wps,&wpc);
1831 i = 0;
1832 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1833 lpxkey = lpNextKey;
1834 while (wps[i]) {
1835 lpxkey=lpNextKey->nextsub;
1836 while (lpxkey) {
1837 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1838 break;
1839 lpxkey=lpxkey->next;
1841 if (!lpxkey)
1842 break;
1843 i++;
1844 lpNextKey = lpxkey;
1846 if (lpxkey) {
1847 add_handle(++currenthandle,lpxkey,samDesired);
1848 lpxkey->flags |= REG_OPTION_TAINTED;
1849 *retkey = currenthandle;
1850 TRACE(reg, "Returning %x\n", currenthandle);
1851 if (lpDispos)
1852 *lpDispos = REG_OPENED_EXISTING_KEY;
1853 FREE_KEY_PATH;
1854 return ERROR_SUCCESS;
1857 /* Good. Now the hard part */
1858 while (wps[i]) {
1859 lplpPrevKey = &(lpNextKey->nextsub);
1860 lpxkey = *lplpPrevKey;
1861 while (lpxkey) {
1862 lplpPrevKey = &(lpxkey->next);
1863 lpxkey = *lplpPrevKey;
1865 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1866 if (!*lplpPrevKey) {
1867 FREE_KEY_PATH;
1868 TRACE(reg, "Returning OUTOFMEMORY\n");
1869 return ERROR_OUTOFMEMORY;
1871 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1872 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
1873 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1874 (*lplpPrevKey)->next = NULL;
1875 (*lplpPrevKey)->nextsub = NULL;
1876 (*lplpPrevKey)->values = NULL;
1877 (*lplpPrevKey)->nrofvalues = 0;
1878 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1879 if (lpszClass)
1880 (*lplpPrevKey)->class = strdupW(lpszClass);
1881 else
1882 (*lplpPrevKey)->class = NULL;
1883 lpNextKey = *lplpPrevKey;
1884 i++;
1886 add_handle(++currenthandle,lpNextKey,samDesired);
1888 /*FIXME: flag handling correct? */
1889 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1890 if (lpszClass)
1891 lpNextKey->class = strdupW(lpszClass);
1892 else
1893 lpNextKey->class = NULL;
1894 *retkey = currenthandle;
1895 TRACE(reg, "Returning %x\n", currenthandle);
1896 if (lpDispos)
1897 *lpDispos = REG_CREATED_NEW_KEY;
1898 FREE_KEY_PATH;
1899 return ERROR_SUCCESS;
1903 /******************************************************************************
1904 * RegCreateKey32W [ADVAPI32.132]
1906 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1908 DWORD junk;
1910 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
1911 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
1912 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL,
1913 retkey, &junk);
1917 /******************************************************************************
1918 * RegCreateKeyEx32A [ADVAPI32.130]
1920 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1921 LPSTR lpszClass, DWORD fdwOptions,
1922 REGSAM samDesired,
1923 LPSECURITY_ATTRIBUTES lpSecAttribs,
1924 LPHKEY retkey, LPDWORD lpDispos )
1926 LPWSTR lpszSubKeyW, lpszClassW;
1927 DWORD ret;
1929 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
1930 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
1931 retkey,lpDispos);
1933 lpszSubKeyW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
1935 if (lpszSubKey)
1936 lpszSubKeyW=strdupA2W(lpszSubKey);
1937 else
1938 lpszSubKeyW=NULL;
1940 if (lpszClass)
1941 lpszClassW=strdupA2W(lpszClass);
1942 else
1943 lpszClassW=NULL;
1944 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
1945 fdwOptions, samDesired, lpSecAttribs, retkey,
1946 lpDispos );
1947 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
1949 if (lpszSubKeyW)
1950 free(lpszSubKeyW);
1952 if (lpszClassW)
1953 free(lpszClassW);
1954 return ret;
1958 /******************************************************************************
1959 * RegCreateKey32A [ADVAPI32.129]
1961 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1963 DWORD junk;
1965 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1967 return RegCreateKeyEx32A(
1968 hkey, /* key handle */
1969 lpszSubKey, /* subkey name */
1970 0, /* reserved = 0 */
1971 NULL, /* lpszClass? FIXME: ? */
1972 REG_OPTION_NON_VOLATILE,/* options */
1973 KEY_ALL_ACCESS, /* desired access attribs */
1974 NULL, /* lpsecurity attributes */
1975 retkey, /* lpretkey */
1976 &junk /* disposition value */
1981 /******************************************************************************
1982 * RegCreateKey16 [SHELL.2] [KERNEL.218]
1984 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1986 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1987 return RegCreateKey32A( hkey, lpszSubKey, retkey );
1992 * Query Value Functions
1993 * Win32 differs between keynames and valuenames.
1994 * multiple values may belong to one key, the special value
1995 * with name NULL is the default value used by the win31
1996 * compat functions.
1998 * Callpath:
1999 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2000 * RegQueryValue32W -> RegQueryValueEx32W
2004 /******************************************************************************
2005 * RegQueryValueEx32W [ADVAPI32.158]
2006 * Retrieves type and data for a specified name associated with an open key
2008 * PARAMS
2009 * hkey [I] Handle of key to query
2010 * lpValueName [I] Name of value to query
2011 * lpdwReserved [I] Reserved - must be NULL
2012 * lpdwType [O] Address of buffer for value type. If NULL, the type
2013 * is not required.
2014 * lpbData [O] Address of data buffer. If NULL, the actual data is
2015 * not required.
2016 * lpcbData [I/O] Address of data buffer size
2018 * RETURNS
2019 * ERROR_SUCCESS: Success
2020 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2022 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2023 LPDWORD lpdwReserved, LPDWORD lpdwType,
2024 LPBYTE lpbData, LPDWORD lpcbData )
2026 LPKEYSTRUCT lpkey;
2027 int i;
2029 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey, debugstr_w(lpValueName),
2030 lpdwReserved, lpdwType, lpbData, lpcbData?*lpcbData:0);
2032 lpkey = lookup_hkey(hkey);
2033 if (!lpkey) {
2034 TRACE(reg, "Invalid handle(%x)\n",hkey);
2035 return ERROR_INVALID_HANDLE;
2038 /* An empty name string is equivalent to NULL */
2039 if (lpValueName && !*lpValueName)
2040 lpValueName = NULL;
2042 if (lpValueName==NULL) {
2043 /* Use key's unnamed or default value, if any */
2044 for (i=0;i<lpkey->nrofvalues;i++)
2045 if (lpkey->values[i].name==NULL)
2046 break;
2047 } else {
2048 /* Search for the key name */
2049 for (i=0;i<lpkey->nrofvalues;i++)
2050 if ( lpkey->values[i].name &&
2051 !lstrcmpi32W(lpValueName,lpkey->values[i].name)
2053 break;
2056 if (i==lpkey->nrofvalues) {
2057 TRACE(reg,"Key not found\n");
2058 if (lpValueName==NULL) {
2059 /* Empty keyname not found */
2060 if (lpbData) {
2061 *(WCHAR*)lpbData = 0;
2062 *lpcbData = 2;
2064 if (lpdwType)
2065 *lpdwType = REG_SZ;
2066 TRACE(reg, "Returning an empty string\n");
2067 return ERROR_SUCCESS;
2069 return ERROR_BADKEY; /* FIXME */
2072 if (lpdwType)
2073 *lpdwType = lpkey->values[i].type;
2075 if (lpbData==NULL) {
2076 /* Data is not required */
2077 if (lpcbData==NULL) {
2078 /* And data size is not required */
2079 /* So all that is returned is the type (set above) */
2080 return ERROR_SUCCESS;
2082 /* Set the size required and return success */
2083 *lpcbData = lpkey->values[i].len;
2084 return ERROR_SUCCESS;
2087 if (*lpcbData<lpkey->values[i].len) {
2088 /* The size was specified, but the data is too big for it */
2089 /* Instead of setting it to NULL, fill in with as much as possible */
2090 /* But the docs do not specify how to handle the lpbData here */
2091 /* *(WCHAR*)lpbData= 0; */
2092 memcpy(lpbData,lpkey->values[i].data,*lpcbData);
2093 *lpcbData = lpkey->values[i].len;
2094 return ERROR_MORE_DATA;
2097 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2099 /* Extra debugging output */
2100 if (lpdwType) {
2101 switch(*lpdwType){
2102 case REG_SZ:
2103 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
2104 break;
2105 case REG_DWORD:
2106 TRACE(reg," Data(dword)=%lx\n", (DWORD)*lpbData);
2107 break;
2108 case REG_BINARY:
2109 TRACE(reg," Data(binary)\n");
2110 /* Is there a way of printing this in readable form? */
2111 break;
2112 default:
2113 TRACE(reg, "Unknown data type %ld\n", *lpdwType);
2114 } /* switch */
2115 } /* if */
2117 /* Set the actual size */
2118 *lpcbData = lpkey->values[i].len;
2119 return ERROR_SUCCESS;
2123 /******************************************************************************
2124 * RegQueryValue32W [ADVAPI32.159]
2126 * NOTES
2127 * Why is this calling RegOpenKey32W?
2129 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2130 LPDWORD lpcbData )
2132 HKEY xhkey;
2133 DWORD ret,lpdwType;
2135 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2136 lpcbData?*lpcbData:0);
2138 /* only open subkey, if we really do descend */
2139 if (lpszSubKey && *lpszSubKey) {
2140 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2141 if (ret!=ERROR_SUCCESS)
2142 return ret;
2143 } else
2144 xhkey = hkey;
2146 lpdwType = REG_SZ;
2147 ret = RegQueryValueEx32W(
2148 xhkey,
2149 NULL, /* varname NULL -> compat */
2150 NULL, /* lpdwReserved, must be NULL */
2151 &lpdwType,
2152 (LPBYTE)lpszData,
2153 lpcbData
2155 if (xhkey!=hkey)
2156 RegCloseKey(xhkey);
2157 return ret;
2161 /******************************************************************************
2162 * RegQueryValueEx32A [ADVAPI32.157]
2164 * Can this use HEAP_strdupAtoW?
2166 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2167 LPDWORD lpdwReserved, LPDWORD lpdwType,
2168 LPBYTE lpbData, LPDWORD lpcbData )
2170 LPWSTR lpszValueNameW;
2171 LPBYTE buf;
2172 DWORD ret,myxlen;
2173 DWORD *mylen;
2174 DWORD type;
2176 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n", hkey,debugstr_a(lpszValueName),
2177 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2179 if (lpszValueName)
2180 lpszValueNameW=strdupA2W(lpszValueName);
2181 else
2182 lpszValueNameW=NULL;
2184 if (lpdwType)
2185 type=*lpdwType;
2187 if (lpbData) {
2188 myxlen = 0;
2189 mylen = &myxlen;
2190 buf = xmalloc(4);
2191 /* Only get the size for now */
2192 ret=RegQueryValueEx32W(
2193 hkey,
2194 lpszValueNameW,
2195 lpdwReserved,
2196 &type,
2197 buf,
2198 mylen
2200 free(buf);
2201 if (ret==ERROR_MORE_DATA) {
2202 buf = (LPBYTE)xmalloc(*mylen);
2203 } else {
2204 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2205 myxlen = 2*(*lpcbData);
2207 } else {
2208 buf=NULL;
2209 if (lpcbData) {
2210 myxlen = *lpcbData*2;
2211 mylen = &myxlen;
2212 } else
2213 mylen = NULL;
2215 /* Now get the data */
2216 ret=RegQueryValueEx32W(
2217 hkey,
2218 lpszValueNameW,
2219 lpdwReserved,
2220 &type,
2221 buf,
2222 mylen
2224 if (lpdwType)
2225 *lpdwType=type;
2227 if (ret==ERROR_SUCCESS) {
2228 if (buf) {
2229 if (UNICONVMASK & (1<<(type))) {
2230 /* convert UNICODE to ASCII */
2231 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2232 *lpcbData = myxlen/2;
2233 } else {
2234 if (myxlen>*lpcbData)
2235 ret = ERROR_MORE_DATA;
2236 else
2237 memcpy(lpbData,buf,myxlen);
2239 *lpcbData = myxlen;
2241 } else {
2242 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2243 *lpcbData = myxlen/2;
2245 } else {
2246 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2247 *lpcbData = myxlen/2;
2249 if (buf)
2250 free(buf);
2252 return ret;
2256 /******************************************************************************
2257 * RegQueryValueEx16 [KERNEL.225]
2259 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2260 LPDWORD lpdwReserved, LPDWORD lpdwType,
2261 LPBYTE lpbData, LPDWORD lpcbData )
2263 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2264 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2265 return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2266 lpbData, lpcbData );
2270 /******************************************************************************
2271 * RegQueryValue32A [ADVAPI32.156]
2273 * NOTES
2274 * Why is this calling RegOpenKey16?
2276 DWORD WINAPI RegQueryValue32A(
2277 HKEY hkey,
2278 LPSTR lpszSubKey,
2279 LPSTR lpszData,
2280 LPDWORD lpcbData
2282 HKEY xhkey;
2283 DWORD ret,lpdwType;
2285 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2286 lpcbData?*lpcbData:0);
2288 /* only open subkey, if we really do descend */
2289 if (lpszSubKey && *lpszSubKey) {
2290 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2291 if (ret!=ERROR_SUCCESS)
2292 return ret;
2293 } else
2294 xhkey = hkey;
2296 lpdwType = REG_SZ;
2297 ret = RegQueryValueEx32A(
2298 xhkey,
2299 NULL, /* lpszValueName NULL -> compat */
2300 NULL, /* lpdwReserved, must be NULL */
2301 &lpdwType,
2302 (LPBYTE)lpszData,
2303 lpcbData
2305 if (xhkey!=hkey)
2306 RegCloseKey(xhkey);
2307 return ret;
2311 /******************************************************************************
2312 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2314 * NOTES
2315 * Is this HACK still applicable?
2317 * HACK
2318 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2319 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2320 * Aldus FH4)
2322 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2323 LPDWORD lpcbData )
2325 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2326 lpcbData?*lpcbData:0);
2328 if (lpcbData)
2329 *lpcbData &= 0xFFFF;
2330 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2335 * Setting values of Registry keys
2337 * Callpath:
2338 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2339 * RegSetValue32W -> RegSetValueEx32W
2343 /******************************************************************************
2344 * RegSetValueEx32W [ADVAPI32.170]
2345 * Sets the data and type of a value under a register key
2347 * PARAMS
2348 * hkey [I] Handle of key to set value for
2349 * lpszValueName [I] Name of value to set
2350 * dwReserved [I] Reserved - must be zero
2351 * dwType [I] Flag for value type
2352 * lpbData [I] Address of value data
2353 * cbData [I] Size of value data
2355 * RETURNS
2356 * Success: ERROR_SUCCESS
2357 * Failure: Error code
2359 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2360 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2361 DWORD cbData)
2363 LPKEYSTRUCT lpkey;
2364 int i;
2366 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2367 dwReserved, dwType, lpbData, cbData);
2369 switch (dwType) {
2370 case REG_SZ:
2371 TRACE(reg," Data(sz)=%s\n", debugstr_w((LPCWSTR)lpbData));
2372 break;
2373 case REG_BINARY:
2374 TRACE(reg," Data(binary)\n");
2375 break;
2376 case REG_DWORD:
2377 TRACE(reg," Data(dword)=%lx\n", (DWORD)lpbData);
2378 break;
2379 default:
2380 TRACE(reg,"Unknown type: %ld\n", dwType);
2383 lpkey = lookup_hkey(hkey);
2384 if (!lpkey) {
2385 WARN(reg,"Returning badkey\n");
2386 return ERROR_INVALID_HANDLE;
2389 lpkey->flags |= REG_OPTION_TAINTED;
2391 if (lpszValueName==NULL) {
2392 /* Sets type and name for key's unnamed or default value */
2393 for (i=0;i<lpkey->nrofvalues;i++)
2394 if (lpkey->values[i].name==NULL)
2395 break;
2396 } else {
2397 for (i=0;i<lpkey->nrofvalues;i++)
2398 if ( lpkey->values[i].name &&
2399 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2401 break;
2403 if (i==lpkey->nrofvalues) {
2404 lpkey->values = (LPKEYVALUE)xrealloc(
2405 lpkey->values,
2406 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2408 lpkey->nrofvalues++;
2409 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2411 if (lpkey->values[i].name==NULL)
2412 if (lpszValueName)
2413 lpkey->values[i].name = strdupW(lpszValueName);
2414 else
2415 lpkey->values[i].name = NULL;
2416 lpkey->values[i].len = cbData;
2417 lpkey->values[i].type = dwType;
2418 if (lpkey->values[i].data !=NULL)
2419 free(lpkey->values[i].data);
2420 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2421 lpkey->values[i].lastmodified = time(NULL);
2422 memcpy(lpkey->values[i].data,lpbData,cbData);
2423 return ERROR_SUCCESS;
2427 /******************************************************************************
2428 * RegSetValueEx32A [ADVAPI32.169]
2430 * NOTES
2431 * Can this use the standard HEAP_strdupAtoW instead?
2433 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2434 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2435 DWORD cbData )
2437 LPBYTE buf;
2438 LPWSTR lpszValueNameW;
2439 DWORD ret;
2441 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2442 dwReserved,dwType,lpbData,cbData);
2444 if ((1<<dwType) & UNICONVMASK) {
2445 buf=(LPBYTE)strdupA2W(lpbData);
2446 cbData=2*strlen(lpbData)+2;
2447 } else
2448 buf=lpbData;
2449 if (lpszValueName)
2450 lpszValueNameW = strdupA2W(lpszValueName);
2451 else
2452 lpszValueNameW = NULL;
2453 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2454 if (lpszValueNameW)
2455 free(lpszValueNameW);
2456 if (buf!=lpbData)
2457 free(buf);
2458 return ret;
2462 /******************************************************************************
2463 * RegSetValueEx16 [KERNEL.226]
2465 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2466 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2468 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2469 dwReserved,dwType,lpbData,cbData);
2470 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2471 cbData );
2475 /******************************************************************************
2476 * RegSetValue32W [ADVAPI32.171]
2478 DWORD WINAPI RegSetValue32W(
2479 HKEY hkey,
2480 LPCWSTR lpszSubKey,
2481 DWORD dwType,
2482 LPCWSTR lpszData,
2483 DWORD cbData
2485 HKEY xhkey;
2486 DWORD ret;
2488 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2489 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2491 if (lpszSubKey && *lpszSubKey) {
2492 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2493 if (ret!=ERROR_SUCCESS)
2494 return ret;
2495 } else
2496 xhkey=hkey;
2497 if (dwType!=REG_SZ) {
2498 TRACE(reg,"RegSetValueX called with dwType=%ld!\n",dwType);
2499 dwType=REG_SZ;
2501 if (cbData!=2*lstrlen32W(lpszData)+2) {
2502 TRACE(reg,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2503 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2505 cbData=2*lstrlen32W(lpszData)+2;
2507 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2508 if (hkey!=xhkey)
2509 RegCloseKey(xhkey);
2510 return ret;
2514 /******************************************************************************
2515 * RegSetValue32A [ADVAPI32.168]
2517 * NOTES
2518 * Why is this calling RegCreateKey16?
2520 DWORD WINAPI RegSetValue32A(
2521 HKEY hkey,
2522 LPCSTR lpszSubKey,
2523 DWORD dwType,
2524 LPCSTR lpszData,
2525 DWORD cbData
2527 DWORD ret;
2528 HKEY xhkey;
2530 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2531 hkey,lpszSubKey,dwType,lpszData,cbData
2533 if (lpszSubKey && *lpszSubKey) {
2534 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2535 if (ret!=ERROR_SUCCESS)
2536 return ret;
2537 } else
2538 xhkey=hkey;
2540 if (dwType!=REG_SZ) {
2541 TRACE(reg,"RegSetValueA called with dwType=%ld!\n",dwType);
2542 dwType=REG_SZ;
2544 if (cbData!=strlen(lpszData)+1)
2545 cbData=strlen(lpszData)+1;
2546 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2547 if (xhkey!=hkey)
2548 RegCloseKey(xhkey);
2549 return ret;
2553 /******************************************************************************
2554 * RegSetValue16 [KERNEL.221] [SHELL.5]
2556 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2557 LPCSTR lpszData, DWORD cbData )
2559 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2560 debugstr_a(lpszData),cbData);
2561 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2566 * Key Enumeration
2568 * Callpath:
2569 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2570 * RegEnumKey32W -> RegEnumKeyEx32W
2574 /******************************************************************************
2575 * RegEnumKeyEx32W [ADVAPI32.139]
2577 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2578 LPDWORD lpcchName, LPDWORD lpdwReserved,
2579 LPWSTR lpszClass, LPDWORD lpcchClass,
2580 FILETIME *ft )
2582 LPKEYSTRUCT lpkey,lpxkey;
2584 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2585 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2587 lpkey = lookup_hkey(hkey);
2588 if (!lpkey)
2589 return ERROR_INVALID_HANDLE;
2591 if (!lpkey->nextsub)
2592 return ERROR_NO_MORE_ITEMS;
2593 lpxkey=lpkey->nextsub;
2594 while (iSubkey && lpxkey) {
2595 iSubkey--;
2596 lpxkey=lpxkey->next;
2598 if (iSubkey || !lpxkey)
2599 return ERROR_NO_MORE_ITEMS;
2600 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2601 return ERROR_MORE_DATA;
2602 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2603 if (lpszClass) {
2604 /* what should we write into it? */
2605 *lpszClass = 0;
2606 *lpcchClass = 2;
2608 return ERROR_SUCCESS;
2612 /******************************************************************************
2613 * RegEnumKey32W [ADVAPI32.140]
2615 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2616 DWORD lpcchName )
2618 FILETIME ft;
2620 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2621 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2625 /* RegEnumKeyExA [ADVAPI32.138] */
2626 DWORD WINAPI RegEnumKeyEx32A(
2627 HKEY hkey,
2628 DWORD iSubkey,
2629 LPSTR lpszName,
2630 LPDWORD lpcchName,
2631 LPDWORD lpdwReserved,
2632 LPSTR lpszClass,
2633 LPDWORD lpcchClass,
2634 FILETIME *ft
2636 DWORD ret,lpcchNameW,lpcchClassW;
2637 LPWSTR lpszNameW,lpszClassW;
2640 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2641 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2643 if (lpszName) {
2644 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2645 lpcchNameW = *lpcchName*2;
2646 } else {
2647 lpszNameW = NULL;
2648 lpcchNameW = 0;
2650 if (lpszClass) {
2651 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2652 lpcchClassW = *lpcchClass*2;
2653 } else {
2654 lpszClassW =0;
2655 lpcchClassW=0;
2657 ret=RegEnumKeyEx32W(
2658 hkey,
2659 iSubkey,
2660 lpszNameW,
2661 &lpcchNameW,
2662 lpdwReserved,
2663 lpszClassW,
2664 &lpcchClassW,
2667 if (ret==ERROR_SUCCESS) {
2668 lstrcpyWtoA(lpszName,lpszNameW);
2669 *lpcchName=strlen(lpszName);
2670 if (lpszClassW) {
2671 lstrcpyWtoA(lpszClass,lpszClassW);
2672 *lpcchClass=strlen(lpszClass);
2675 if (lpszNameW)
2676 free(lpszNameW);
2677 if (lpszClassW)
2678 free(lpszClassW);
2679 return ret;
2683 /******************************************************************************
2684 * RegEnumKey32A [ADVAPI32.137]
2686 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2687 DWORD lpcchName )
2689 FILETIME ft;
2691 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2692 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2693 NULL, &ft );
2697 /******************************************************************************
2698 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2700 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2701 DWORD lpcchName )
2703 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2704 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2709 * Enumerate Registry Values
2711 * Callpath:
2712 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2716 /******************************************************************************
2717 * RegEnumValue32W [ADVAPI32.142]
2719 DWORD WINAPI RegEnumValue32W(
2720 HKEY hkey,
2721 DWORD iValue,
2722 LPWSTR lpszValue,
2723 LPDWORD lpcchValue,
2724 LPDWORD lpdReserved,
2725 LPDWORD lpdwType,
2726 LPBYTE lpbData,
2727 LPDWORD lpcbData
2729 LPKEYSTRUCT lpkey;
2730 LPKEYVALUE val;
2732 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2733 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2735 lpkey = lookup_hkey(hkey);
2736 if (!lpkey)
2737 return ERROR_INVALID_HANDLE;
2739 if (lpkey->nrofvalues<=iValue)
2740 return ERROR_NO_MORE_ITEMS;
2741 val = lpkey->values+iValue;
2743 if (val->name) {
2744 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2745 *lpcchValue = lstrlen32W(val->name)*2+2;
2746 return ERROR_MORE_DATA;
2748 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2749 *lpcchValue=lstrlen32W(val->name)*2+2;
2750 } else {
2751 *lpszValue = 0;
2752 *lpcchValue = 0;
2754 if (lpdwType)
2755 *lpdwType=val->type;
2756 if (lpbData) {
2757 if (val->len>*lpcbData)
2758 return ERROR_MORE_DATA;
2759 memcpy(lpbData,val->data,val->len);
2760 *lpcbData = val->len;
2762 return ERROR_SUCCESS;
2766 /* RegEnumValueA [ADVAPI32.141] */
2767 DWORD WINAPI RegEnumValue32A(
2768 HKEY hkey,
2769 DWORD iValue,
2770 LPSTR lpszValue,
2771 LPDWORD lpcchValue,
2772 LPDWORD lpdReserved,
2773 LPDWORD lpdwType,
2774 LPBYTE lpbData,
2775 LPDWORD lpcbData
2777 LPWSTR lpszValueW;
2778 LPBYTE lpbDataW;
2779 DWORD ret,lpcbDataW;
2781 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2782 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2785 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2786 if (lpbData) {
2787 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2788 lpcbDataW = *lpcbData*2;
2789 } else
2790 lpbDataW = NULL;
2791 ret=RegEnumValue32W(
2792 hkey,
2793 iValue,
2794 lpszValueW,
2795 lpcchValue,
2796 lpdReserved,
2797 lpdwType,
2798 lpbDataW,
2799 &lpcbDataW
2802 if (ret==ERROR_SUCCESS) {
2803 lstrcpyWtoA(lpszValue,lpszValueW);
2804 if (lpbData) {
2805 if ((1<<*lpdwType) & UNICONVMASK) {
2806 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2807 } else {
2808 if (lpcbDataW > *lpcbData)
2809 ret = ERROR_MORE_DATA;
2810 else
2811 memcpy(lpbData,lpbDataW,lpcbDataW);
2813 *lpcbData = lpcbDataW;
2816 if (lpbDataW)
2817 free(lpbDataW);
2818 if (lpszValueW)
2819 free(lpszValueW);
2820 return ret;
2824 /******************************************************************************
2825 * RegEnumValue16 [KERNEL.223]
2827 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2828 LPDWORD lpcchValue, LPDWORD lpdReserved,
2829 LPDWORD lpdwType, LPBYTE lpbData,
2830 LPDWORD lpcbData )
2832 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2833 lpdReserved,lpdwType,lpbData,lpcbData);
2834 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2835 lpdwType, lpbData, lpcbData );
2839 /******************************************************************************
2840 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2841 * Releases the handle of the specified key
2843 * PARAMS
2844 * hkey [I] Handle of key to close
2846 * RETURNS
2847 * Success: ERROR_SUCCESS
2848 * Failure: Error code
2850 DWORD WINAPI RegCloseKey( HKEY hkey )
2852 TRACE(reg,"(%x)\n",hkey);
2853 return remove_handle(hkey);
2858 * Delete registry key
2860 * Callpath:
2861 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2865 /******************************************************************************
2866 * RegDeleteKey32W [ADVAPI32.134]
2868 * PARAMS
2869 * hkey [I]
2870 * lpszSubKey [I]
2872 * RETURNS
2873 * Success: ERROR_SUCCESS
2874 * Failure: Error code
2876 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
2878 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2879 LPWSTR *wps;
2880 int wpc,i;
2882 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
2884 lpNextKey = lookup_hkey(hkey);
2885 if (!lpNextKey) {
2886 TRACE(reg, " Invalid handle.\n");
2887 return ERROR_INVALID_HANDLE;
2890 /* we need to know the previous key in the hier. */
2891 if (!lpszSubKey || !*lpszSubKey) {
2892 TRACE(reg, " Badkey[2].\n");
2893 return ERROR_BADKEY;
2895 split_keypath(lpszSubKey,&wps,&wpc);
2896 i = 0;
2897 lpxkey = lpNextKey;
2898 while (i<wpc-1) {
2899 lpxkey=lpNextKey->nextsub;
2900 while (lpxkey) {
2901 TRACE(reg, " Scanning [%s]\n",
2902 debugstr_w(lpxkey->keyname));
2903 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2904 break;
2905 lpxkey=lpxkey->next;
2907 if (!lpxkey) {
2908 FREE_KEY_PATH;
2909 TRACE(reg, " Not found.\n");
2910 /* not found is success */
2911 return ERROR_SUCCESS;
2913 i++;
2914 lpNextKey = lpxkey;
2916 lpxkey = lpNextKey->nextsub;
2917 lplpPrevKey = &(lpNextKey->nextsub);
2918 while (lpxkey) {
2919 TRACE(reg, " Scanning [%s]\n",
2920 debugstr_w(lpxkey->keyname));
2921 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2922 break;
2923 lplpPrevKey = &(lpxkey->next);
2924 lpxkey = lpxkey->next;
2927 if (!lpxkey) {
2928 FREE_KEY_PATH;
2929 WARN(reg , " Not found.\n");
2930 return ERROR_FILE_NOT_FOUND;
2933 if (lpxkey->nextsub) {
2934 FREE_KEY_PATH;
2935 WARN(reg , " Not empty.\n");
2936 return ERROR_CANTWRITE;
2938 *lplpPrevKey = lpxkey->next;
2939 free(lpxkey->keyname);
2940 if (lpxkey->class)
2941 free(lpxkey->class);
2942 if (lpxkey->values)
2943 free(lpxkey->values);
2944 free(lpxkey);
2945 FREE_KEY_PATH;
2946 TRACE(reg, " Done.\n");
2947 return ERROR_SUCCESS;
2951 /******************************************************************************
2952 * RegDeleteKey32A [ADVAPI32.133]
2954 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
2956 LPWSTR lpszSubKeyW;
2957 DWORD ret;
2959 TRACE(reg,"(%x,%s)\n",hkey,lpszSubKey);
2960 lpszSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpszSubKey );
2961 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
2962 HeapFree( GetProcessHeap(), 0, lpszSubKeyW );
2963 return ret;
2967 /******************************************************************************
2968 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
2970 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
2972 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
2973 return RegDeleteKey32A( hkey, lpszSubKey );
2978 * Delete registry value
2980 * Callpath:
2981 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2985 /******************************************************************************
2986 * RegDeleteValue32W [ADVAPI32.136]
2988 * PARAMS
2989 * hkey [I]
2990 * lpszValue [I]
2992 * RETURNS
2994 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
2996 DWORD i;
2997 LPKEYSTRUCT lpkey;
2998 LPKEYVALUE val;
3000 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3002 lpkey = lookup_hkey(hkey);
3003 if (!lpkey)
3004 return ERROR_INVALID_HANDLE;
3006 if (lpszValue) {
3007 for (i=0;i<lpkey->nrofvalues;i++)
3008 if ( lpkey->values[i].name &&
3009 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3011 break;
3012 } else {
3013 for (i=0;i<lpkey->nrofvalues;i++)
3014 if (lpkey->values[i].name==NULL)
3015 break;
3018 if (i == lpkey->nrofvalues)
3019 return ERROR_FILE_NOT_FOUND;
3021 val = lpkey->values+i;
3022 if (val->name) free(val->name);
3023 if (val->data) free(val->data);
3024 memcpy(
3025 lpkey->values+i,
3026 lpkey->values+i+1,
3027 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3029 lpkey->values = (LPKEYVALUE)xrealloc(
3030 lpkey->values,
3031 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3033 lpkey->nrofvalues--;
3034 return ERROR_SUCCESS;
3038 /******************************************************************************
3039 * RegDeleteValue32A [ADVAPI32.135]
3041 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3043 LPWSTR lpszValueW;
3044 DWORD ret;
3046 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3047 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
3048 ret = RegDeleteValue32W( hkey, lpszValueW );
3049 HeapFree(GetProcessHeap(),0,lpszValueW);
3050 return ret;
3054 /******************************************************************************
3055 * RegDeleteValue16 [KERNEL.222]
3057 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3059 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3060 return RegDeleteValue32A(hkey,lpszValue);
3064 /******************************************************************************
3065 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3066 * Writes key to registry
3068 * PARAMS
3069 * hkey [I] Handle of key to write
3071 * RETURNS
3072 * Success: ERROR_SUCCESS
3073 * Failure: Error code
3075 DWORD WINAPI RegFlushKey( HKEY hkey )
3077 FIXME(reg, "(%x): stub\n", hkey);
3078 return ERROR_SUCCESS;
3082 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3084 /******************************************************************************
3085 * RegQueryInfoKey32W [ADVAPI32.153]
3087 DWORD WINAPI RegQueryInfoKey32W(
3088 HKEY hkey,
3089 LPWSTR lpszClass,
3090 LPDWORD lpcchClass,
3091 LPDWORD lpdwReserved,
3092 LPDWORD lpcSubKeys,
3093 LPDWORD lpcchMaxSubkey,
3094 LPDWORD lpcchMaxClass,
3095 LPDWORD lpcValues,
3096 LPDWORD lpcchMaxValueName,
3097 LPDWORD lpccbMaxValueData,
3098 LPDWORD lpcbSecurityDescriptor,
3099 FILETIME *ft
3101 LPKEYSTRUCT lpkey,lpxkey;
3102 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3103 int i;
3105 TRACE(reg,"(%x,......)\n",hkey);
3106 lpkey = lookup_hkey(hkey);
3107 if (!lpkey)
3108 return ERROR_INVALID_HANDLE;
3109 if (lpszClass) {
3110 if (lpkey->class) {
3111 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
3112 *lpcchClass=lstrlen32W(lpkey->class)*2;
3113 return ERROR_MORE_DATA;
3115 *lpcchClass=lstrlen32W(lpkey->class)*2;
3116 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
3117 } else {
3118 *lpszClass = 0;
3119 *lpcchClass = 0;
3121 } else {
3122 if (lpcchClass)
3123 *lpcchClass = lstrlen32W(lpkey->class)*2;
3125 lpxkey=lpkey->nextsub;
3126 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3127 while (lpxkey) {
3128 nrofkeys++;
3129 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3130 maxsubkey=lstrlen32W(lpxkey->keyname);
3131 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3132 maxclass=lstrlen32W(lpxkey->class);
3133 lpxkey=lpxkey->next;
3135 for (i=0;i<lpkey->nrofvalues;i++) {
3136 LPKEYVALUE val=lpkey->values+i;
3138 if (val->name && lstrlen32W(val->name)>maxvname)
3139 maxvname=lstrlen32W(val->name);
3140 if (val->len>maxvdata)
3141 maxvdata=val->len;
3143 if (!maxclass) maxclass = 1;
3144 if (!maxvname) maxvname = 1;
3145 if (lpcValues)
3146 *lpcValues = lpkey->nrofvalues;
3147 if (lpcSubKeys)
3148 *lpcSubKeys = nrofkeys;
3149 if (lpcchMaxSubkey)
3150 *lpcchMaxSubkey = maxsubkey*2;
3151 if (lpcchMaxClass)
3152 *lpcchMaxClass = maxclass*2;
3153 if (lpcchMaxValueName)
3154 *lpcchMaxValueName= maxvname;
3155 if (lpccbMaxValueData)
3156 *lpccbMaxValueData= maxvdata;
3157 return ERROR_SUCCESS;
3161 /* RegQueryInfoKeyA [ADVAPI32.152] */
3162 DWORD WINAPI RegQueryInfoKey32A(
3163 HKEY hkey,
3164 LPSTR lpszClass,
3165 LPDWORD lpcchClass,
3166 LPDWORD lpdwReserved,
3167 LPDWORD lpcSubKeys,
3168 LPDWORD lpcchMaxSubkey,
3169 LPDWORD lpcchMaxClass,
3170 LPDWORD lpcValues,
3171 LPDWORD lpcchMaxValueName,
3172 LPDWORD lpccbMaxValueData,
3173 LPDWORD lpcbSecurityDescriptor,
3174 FILETIME *ft
3176 LPWSTR lpszClassW;
3177 DWORD ret;
3179 TRACE(reg,"(%x,......)\n",hkey);
3180 if (lpszClass) {
3181 *lpcchClass*= 2;
3182 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
3184 } else
3185 lpszClassW = NULL;
3186 ret=RegQueryInfoKey32W(
3187 hkey,
3188 lpszClassW,
3189 lpcchClass,
3190 lpdwReserved,
3191 lpcSubKeys,
3192 lpcchMaxSubkey,
3193 lpcchMaxClass,
3194 lpcValues,
3195 lpcchMaxValueName,
3196 lpccbMaxValueData,
3197 lpcbSecurityDescriptor,
3200 if (ret==ERROR_SUCCESS && lpszClass)
3201 lstrcpyWtoA(lpszClass,lpszClassW);
3202 if (lpcchClass)
3203 *lpcchClass/=2;
3204 if (lpcchMaxSubkey)
3205 *lpcchMaxSubkey/=2;
3206 if (lpcchMaxClass)
3207 *lpcchMaxClass/=2;
3208 if (lpcchMaxValueName)
3209 *lpcchMaxValueName/=2;
3210 if (lpszClassW)
3211 free(lpszClassW);
3212 return ret;
3216 /******************************************************************************
3217 * RegConnectRegistry32W [ADVAPI32.128]
3219 LONG WINAPI RegConnectRegistry32W( LPCWSTR machine, HKEY hkey, LPHKEY reskey )
3221 FIXME(reg,"(%s,%x,%p): stub\n",debugstr_w(machine),hkey,reskey);
3222 return ERROR_BAD_NETPATH; /* FIXME */
3226 /******************************************************************************
3227 * RegConnectRegistry32A [ADVAPI32.127]
3229 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3231 DWORD ret;
3232 LPWSTR machineW = HEAP_strdupAtoW(GetProcessHeap(),0,machine);
3233 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3234 HeapFree(GetProcessHeap(),0,machineW);
3235 return ret;
3239 /******************************************************************************
3240 * RegGetKeySecurity [ADVAPI32.144]
3241 * Retrieves a copy of security descriptor protecting the registry key
3243 * RETURNS
3244 * Success: ERROR_SUCCESS
3245 * Failure: Error code
3247 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3248 SECURITY_INFORMATION SecurityInformation,
3249 LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3250 LPDWORD lpcbSecurityDescriptor )
3252 LPKEYSTRUCT lpkey;
3253 lpkey = lookup_hkey(hkey);
3254 if (!lpkey)
3255 return ERROR_INVALID_HANDLE;
3257 FIXME(reg, "(%d,%ld,%p,%p): stub\n", hkey, SecurityInformation,
3258 pSecurityDescriptor, lpcbSecurityDescriptor);
3259 return ERROR_SUCCESS;
3263 /******************************************************************************
3264 * RegLoadKey32W [ADVAPI32.???]
3266 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3268 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3269 debugstr_w(lpszFile));
3270 return ERROR_SUCCESS;
3274 /******************************************************************************
3275 * RegLoadKey32A [ADVAPI32.???]
3277 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3279 LONG ret;
3280 LPWSTR lpszSubKeyW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
3281 LPWSTR lpszFileW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszFile);
3282 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3283 HeapFree(GetProcessHeap(),0,lpszFileW);
3284 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
3285 return ret;
3289 /******************************************************************************
3290 * RegNotifyChangeKeyValue [ADVAPI32.???]
3292 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3293 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3294 BOOL32 fAsync )
3296 FIXME(reg,"(%x,%i,%ld,%d,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3297 hEvent,fAsync);
3298 return ERROR_SUCCESS;
3302 /******************************************************************************
3303 * RegUnLoadKey32W [ADVAPI32.173]
3305 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3307 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3308 return ERROR_SUCCESS;
3312 /******************************************************************************
3313 * RegUnLoadKey32A [ADVAPI32.172]
3315 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3317 LONG ret;
3318 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
3319 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3320 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
3321 return ret;
3325 /******************************************************************************
3326 * RegSetKeySecurity [ADVAPI32.167]
3328 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3329 LPSECURITY_DESCRIPTOR pSecurityDesc )
3331 FIXME(reg, "%x,%ld,%p): stub\n", hkey, SecurityInfo, pSecurityDesc);
3332 return ERROR_SUCCESS;
3336 /******************************************************************************
3337 * RegSaveKey32W [ADVAPI32.166]
3339 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3340 LPSECURITY_ATTRIBUTES sa )
3342 FIXME(reg, "%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3343 return ERROR_SUCCESS;
3347 /******************************************************************************
3348 * RegSaveKey32A [ADVAPI32.165]
3350 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3351 LPSECURITY_ATTRIBUTES sa )
3353 LONG ret;
3354 LPWSTR lpFileW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpFile);
3355 ret = RegSaveKey32W( hkey, lpFileW, sa );
3356 HeapFree( GetProcessHeap(), 0, lpFileW );
3357 return ret;
3361 /******************************************************************************
3362 * RegRestoreKey32W [ADVAPI32.164]
3364 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3366 FIXME(reg, "%x,%s,%ld): stub\n", hkey, debugstr_w(lpFile), dwFlags);
3367 return ERROR_SUCCESS;
3371 /******************************************************************************
3372 * RegRestoreKey32A [ADVAPI32.163]
3374 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3376 LONG ret;
3377 LPWSTR lpFileW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpFile);
3378 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3379 HeapFree( GetProcessHeap(), 0, lpFileW );
3380 return ret;
3384 /******************************************************************************
3385 * RegReplaceKey32W [ADVAPI32.162]
3387 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3388 LPCWSTR lpOldFile )
3390 FIXME(reg, "%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3391 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3392 return ERROR_SUCCESS;
3396 /******************************************************************************
3397 * RegReplaceKey32A [ADVAPI32.161]
3399 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3400 LPCSTR lpOldFile )
3402 LONG ret;
3403 LPWSTR lpSubKeyW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpSubKey);
3404 LPWSTR lpNewFileW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpNewFile);
3405 LPWSTR lpOldFileW = HEAP_strdupAtoW(GetProcessHeap(), 0, lpOldFile);
3406 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3407 HeapFree( GetProcessHeap(), 0, lpOldFileW );
3408 HeapFree( GetProcessHeap(), 0, lpNewFileW );
3409 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
3410 return ret;