Release 960824
[wine/multimedia.git] / misc / registry.c
blob62bc558a1ba2e3a27c15b1d582fb5c9b1f3c9be8
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <malloc.h>
11 #include <unistd.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
16 #include <sys/stat.h>
17 #include <pwd.h>
18 #include <time.h>
19 #include "windows.h"
20 #include "win.h"
21 #include "winerror.h"
22 #include "file.h"
23 #include "string32.h"
24 #include "stddebug.h"
25 #include "debug.h"
26 #include "xmalloc.h"
27 #include "winreg.h"
29 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
31 /* FIXME: following defines should be configured global ... */
33 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
34 #define WINE_PREFIX "/.wine"
35 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
36 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
38 /* relative in ~user/.wine/ : */
39 #define SAVE_CURRENT_USER "user.reg"
40 #define SAVE_LOCAL_MACHINE "system.reg"
42 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
43 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
45 /* one value of a key */
46 typedef struct tagKEYVALUE
48 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
49 DWORD type; /* type of value */
50 DWORD len; /* length of data */
51 DWORD lastmodified; /* time of seconds since 1.1.1970 */
52 LPBYTE data; /* content, may be strings, binaries, etc. */
53 } KEYVALUE,*LPKEYVALUE;
55 /* a registry key */
56 typedef struct tagKEYSTRUCT
58 LPWSTR keyname; /* name of THIS key (UNICODE) */
59 DWORD flags; /* flags. */
60 LPWSTR class;
61 /* values */
62 DWORD nrofvalues; /* nr of values in THIS key */
63 LPKEYVALUE values; /* values in THIS key */
64 /* key management pointers */
65 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
66 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
67 } KEYSTRUCT, *LPKEYSTRUCT;
70 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
71 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
72 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
73 static KEYSTRUCT *key_users=NULL; /* all users? */
75 /* dynamic, not saved */
76 static KEYSTRUCT *key_performance_data=NULL;
77 static KEYSTRUCT *key_current_config=NULL;
78 static KEYSTRUCT *key_dyn_data=NULL;
80 /* what valuetypes do we need to convert? */
81 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
83 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
84 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
85 #define strdupW(x) STRING32_strdupW(x)
86 #define strcmpniW(a,b) STRING32_lstrcmpniW(a,b)
87 #define strchrW(a,c) STRING32_lstrchrW(a,c)
88 #define strcpyWA(a,b) STRING32_UniToAnsi(a,b)
90 static struct openhandle {
91 LPKEYSTRUCT lpkey;
92 HKEY hkey;
93 REGSAM accessmask;
94 } *openhandles=NULL;
95 static int nrofopenhandles=0;
96 static int currenthandle=1;
98 static void
99 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
100 int i;
102 for (i=0;i<nrofopenhandles;i++) {
103 if (openhandles[i].lpkey==lpkey) {
104 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
106 if (openhandles[i].hkey==hkey) {
107 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
110 openhandles=xrealloc( openhandles,
111 sizeof(struct openhandle)*(nrofopenhandles+1)
113 openhandles[i].lpkey = lpkey;
114 openhandles[i].hkey = hkey;
115 openhandles[i].accessmask= accessmask;
116 nrofopenhandles++;
119 static LPKEYSTRUCT
120 get_handle(HKEY hkey) {
121 int i;
123 for (i=0;i<nrofopenhandles;i++)
124 if (openhandles[i].hkey==hkey)
125 return openhandles[i].lpkey;
126 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
127 return NULL;
130 static void
131 remove_handle(HKEY hkey) {
132 int i;
134 for (i=0;i<nrofopenhandles;i++)
135 if (openhandles[i].hkey==hkey)
136 break;
137 if (i==nrofopenhandles) {
138 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
139 return;
141 memcpy( openhandles+i,
142 openhandles+i+1,
143 sizeof(struct openhandle)*(nrofopenhandles-i-1)
145 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
146 nrofopenhandles--;
147 return;
151 /* debug function, converts a unicode into a static memory area
152 * (sub for using two static strings, in case we need them in a single call)
154 LPSTR
155 W2C(LPCWSTR x,int sub) {
156 static LPSTR unicodedebug[2]={NULL,NULL};
157 if (x==NULL)
158 return "<NULL>";
159 if (sub!=0 && sub!=1)
160 return "<W2C:bad sub>";
161 if (unicodedebug[sub]) free(unicodedebug[sub]);
162 unicodedebug[sub] = strdupW2A(x);
163 return unicodedebug[sub];
166 static LPKEYSTRUCT
167 lookup_hkey(HKEY hkey) {
168 switch (hkey) {
169 case 0x00000000:
170 case 0x00000001:
171 case HKEY_CLASSES_ROOT:
172 return key_classes_root;
173 case HKEY_CURRENT_USER:
174 return key_current_user;
175 case HKEY_LOCAL_MACHINE:
176 return key_local_machine;
177 case HKEY_USERS:
178 return key_users;
179 case HKEY_PERFORMANCE_DATA:
180 return key_performance_data;
181 case HKEY_DYN_DATA:
182 return key_dyn_data;
183 case HKEY_CURRENT_CONFIG:
184 return key_current_config;
185 default:
186 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
187 (LONG)hkey
189 return get_handle(hkey);
191 /*NOTREACHED*/
195 * splits the unicode string 'wp' into an array of strings.
196 * the array is allocated by this function.
197 * the number of components will be stored in 'wpc'
198 * Free the array using FREE_KEY_PATH
200 static void
201 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
202 int i,j,len;
203 LPWSTR ws;
205 ws = strdupW(wp);
206 *wpc = 1;
207 for (i=0;ws[i];i++) {
208 if (ws[i]=='\\') {
209 ws[i]=0;
210 (*wpc)++;
213 len = i;
214 *wpv = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2));
215 (*wpv)[0]= ws;
216 j = 1;
217 for (i=1;i<len;i++)
218 if (ws[i-1]==0)
219 (*wpv)[j++]=ws+i;
220 (*wpv)[j]=NULL;
222 #define FREE_KEY_PATH free(wps[0]);free(wps);
225 * Shell initialisation, allocates keys.
227 void
228 SHELL_Init() {
229 struct passwd *pwd;
231 HKEY cl_r_hkey,c_u_hkey;
232 #define ADD_ROOT_KEY(xx) \
233 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
234 memset(xx,'\0',sizeof(KEYSTRUCT));\
235 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
237 ADD_ROOT_KEY(key_local_machine);
238 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
239 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
240 exit(1);
242 key_classes_root = lookup_hkey(cl_r_hkey);
244 ADD_ROOT_KEY(key_users);
246 #if 0
247 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
248 * (later, when a win32 registry editing tool becomes avail.)
250 while (pwd=getpwent()) {
251 if (pwd->pw_name == NULL)
252 continue;
253 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
254 RegCloseKey(c_u_hkey);
256 #endif
257 pwd=getpwuid(getuid());
258 if (pwd && pwd->pw_name) {
259 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
260 key_current_user = lookup_hkey(c_u_hkey);
261 } else {
262 ADD_ROOT_KEY(key_current_user);
264 ADD_ROOT_KEY(key_performance_data);
265 ADD_ROOT_KEY(key_current_config);
266 ADD_ROOT_KEY(key_dyn_data);
267 #undef ADD_ROOT_KEY
270 /************************ SAVE Registry Function ****************************/
272 #define REGISTRY_SAVE_VERSION 0x00000001
274 /* Registry saveformat:
275 * If you change it, increase above number by 1, which will flush
276 * old registry database files.
278 * Global:
279 * "WINE REGISTRY Version %d"
280 * subkeys....
281 * Subkeys:
282 * keyname
283 * valuename=lastmodified,type,data
284 * ...
285 * subkeys
286 * ...
287 * keyname,valuename,stringdata:
288 * the usual ascii characters from 0x00-0xff (well, not 0x00)
289 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
290 * ( "=\\\t" escaped in \uXXXX form.)
291 * type,lastmodified:
292 * int
294 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
296 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
297 * SaveOnlyUpdatedKeys=yes
299 static int
300 _save_check_tainted(LPKEYSTRUCT lpkey) {
301 int tainted;
303 if (!lpkey)
304 return 0;
305 if (lpkey->flags & REG_OPTION_TAINTED)
306 tainted = 1;
307 else
308 tainted = 0;
309 while (lpkey) {
310 if (_save_check_tainted(lpkey->nextsub)) {
311 lpkey->flags |= REG_OPTION_TAINTED;
312 tainted = 1;
314 lpkey = lpkey->next;
316 return tainted;
319 static void
320 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
321 LPWSTR s;
322 int doescape;
324 if (wstr==NULL)
325 return;
326 s=wstr;
327 while (*s) {
328 doescape=0;
329 if (*s>0xff)
330 doescape = 1;
331 if (*s=='\n')
332 doescape = 1;
333 if (escapeeq && *s=='=')
334 doescape = 1;
335 if (*s=='\\')
336 fputc(*s,F); /* if \\ than put it twice. */
337 if (doescape)
338 fprintf(F,"\\u%04x",*((unsigned short*)s));
339 else
340 fputc(*s,F);
341 s++;
345 static int
346 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
347 LPKEYSTRUCT lpxkey;
348 int i,tabs,j;
350 lpxkey = lpkey;
351 while (lpxkey) {
352 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
353 (all || (lpxkey->flags & REG_OPTION_TAINTED))
355 for (tabs=level;tabs--;)
356 fputc('\t',F);
357 _save_USTRING(F,lpxkey->keyname,1);
358 fputs("\n",F);
359 for (i=0;i<lpxkey->nrofvalues;i++) {
360 LPKEYVALUE val=lpxkey->values+i;
362 for (tabs=level+1;tabs--;)
363 fputc('\t',F);
364 _save_USTRING(F,val->name,0);
365 fputc('=',F);
366 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
367 if ((1<<val->type) & UNICONVMASK)
368 _save_USTRING(F,(LPWSTR)val->data,0);
369 else
370 for (j=0;j<val->len;j++)
371 fprintf(F,"%02x",*((unsigned char*)val->data+j));
372 fputs("\n",F);
374 /* descend recursively */
375 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
376 return 0;
378 lpxkey=lpxkey->next;
380 return 1;
383 static int
384 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
385 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
386 _save_check_tainted(lpkey->nextsub);
387 return _savesubkey(F,lpkey->nextsub,0,all);
390 static void
391 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
392 FILE *F;
394 F=fopen(fn,"w");
395 if (F==NULL) {
396 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
397 fn,strerror(errno)
399 return;
401 if (!_savesubreg(F,lpkey,all)) {
402 fclose(F);
403 unlink(fn);
404 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
405 return;
407 fclose(F);
410 void
411 SHELL_SaveRegistry() {
412 char *fn;
413 struct passwd *pwd;
414 char buf[4];
415 HKEY hkey;
416 int all;
418 all=0;
419 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
420 strcpy(buf,"yes");
421 } else {
422 DWORD len,junk,type;
424 len=4;
425 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
426 hkey,
427 VAL_SAVEUPDATED,
428 &junk,
429 &type,
430 buf,
431 &len
432 ))|| (type!=REG_SZ)
434 strcpy(buf,"yes");
435 RegCloseKey(hkey);
437 if (lstrcmpi32A(buf,"yes"))
438 all=1;
439 pwd=getpwuid(getuid());
440 if (pwd!=NULL && pwd->pw_dir!=NULL) {
441 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_USERS_DEFAULT)+2);
442 strcpy(fn,pwd->pw_dir);
443 strcat(fn,WINE_PREFIX);
444 /* create the directory. don't care about errorcodes. */
445 mkdir(fn,0755); /* drwxr-xr-x */
446 strcat(fn,"/"SAVE_CURRENT_USER);
447 _savereg(key_current_user,fn,all);
448 free(fn);
449 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
450 strcpy(fn,pwd->pw_dir);
451 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
452 _savereg(key_local_machine,fn,all);
453 free(fn);
454 } else
455 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
458 /************************ LOAD Registry Function ****************************/
460 static LPKEYSTRUCT
461 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
462 LPKEYSTRUCT lpxkey,*lplpkey;
464 lplpkey= &(lpkey->nextsub);
465 lpxkey = *lplpkey;
466 while (lpxkey) {
467 if (!lstrcmp32W(lpxkey->keyname,keyname))
468 break;
469 lplpkey = &(lpxkey->next);
470 lpxkey = *lplpkey;
472 if (lpxkey==NULL) {
473 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
474 lpxkey = *lplpkey;
475 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
476 lpxkey->keyname = keyname;
477 } else
478 free(keyname);
479 return lpxkey;
482 static void
483 _find_or_add_value(
484 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
485 DWORD lastmodified
487 LPKEYVALUE val=NULL;
488 int i;
490 for (i=0;i<lpkey->nrofvalues;i++) {
491 val=lpkey->values+i;
492 if (name==NULL) {
493 if (val->name==NULL)
494 break;
495 } else {
496 if ( val->name!=NULL &&
497 !lstrcmp32W(val->name,name)
499 break;
502 if (i==lpkey->nrofvalues) {
503 lpkey->values = xrealloc(
504 lpkey->values,
505 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
507 val=lpkey->values+i;
508 memset(val,'\0',sizeof(KEYVALUE));
509 val->name = name;
510 } else {
511 if (name)
512 free(name);
514 if (val->lastmodified<lastmodified) {
515 val->lastmodified=lastmodified;
516 val->type = type;
517 val->len = len;
518 if (val->data)
519 free(val->data);
520 val->data = data;
521 } else
522 free(data);
526 /* reads a line including dynamically enlarging the readbuffer and throwing
527 * away comments
529 static int
530 _wine_read_line(FILE *F,char **buf,int *len) {
531 char *s,*curread;
532 int mylen,curoff;
534 curread = *buf;
535 mylen = *len;
536 **buf = '\0';
537 while (1) {
538 while (1) {
539 s=fgets(curread,mylen,F);
540 if (s==NULL)
541 return 0; /* EOF */
542 if (NULL==(s=strchr(curread,'\n'))) {
543 /* buffer wasn't large enough */
544 curoff = strlen(*buf);
545 *buf = xrealloc(*buf,*len*2);
546 curread = *buf + curoff;
547 mylen = *len; /* we filled up the buffer and
548 * got new '*len' bytes to fill
550 *len = *len * 2;
551 } else {
552 *s='\0';
553 break;
556 /* throw away comments */
557 if (**buf=='#' || **buf==';') {
558 curread = *buf;
559 mylen = *len;
560 continue;
562 if (s) /* got end of line */
563 break;
565 return 1;
568 /* converts a char* into a UNICODE string (up to a special char)
569 * and returns the position exactly after that string
571 static char*
572 _wine_read_USTRING(char *buf,LPWSTR *str) {
573 char *s;
574 LPWSTR ws;
576 /* read up to "=" or "\0" or "\n" */
577 s = buf;
578 if (*s == '=') {
579 /* empty string is the win3.1 default value(NULL)*/
580 *str = NULL;
581 return s;
583 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
584 ws = *str;
585 while (*s && (*s!='\n') && (*s!='=')) {
586 if (*s!='\\')
587 *ws++=*((unsigned char*)s++);
588 else {
589 s++;
590 if (*s=='\\') {
591 *ws+='\\';
592 s++;
593 continue;
595 if (*s!='u') {
596 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
597 *ws++='\\';
598 *ws++=*s++;
599 } else {
600 char xbuf[5];
601 int wc;
603 s++;
604 memcpy(xbuf,s,4);xbuf[4]='\0';
605 if (!sscanf(xbuf,"%x",&wc))
606 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
607 s+=4;
608 *ws++ =(unsigned short)wc;
612 *ws = 0;
613 ws = *str;
614 *str = strdupW(*str);
615 free(ws);
616 return s;
619 static int
620 _wine_loadsubkey(
621 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
623 LPKEYSTRUCT lpxkey;
624 int i;
625 char *s;
626 LPWSTR name;
628 lpkey->flags |= optflag;
630 /* good. we already got a line here ... so parse it */
631 lpxkey = NULL;
632 while (1) {
633 i=0;s=*buf;
634 while (*s=='\t') {
635 s++;
636 i++;
638 if (i>level) {
639 if (lpxkey==NULL) {
640 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
641 return 0;
643 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
644 continue;
646 /* let the caller handle this line */
647 if (i<level || **buf=='\0')
648 return 1;
650 /* it can be: a value or a keyname. Parse the name first */
651 s=_wine_read_USTRING(s,&name);
653 /* switch() default: hack to avoid gotos */
654 switch (0) {
655 default:
656 if (*s=='\0') {
657 lpxkey=_find_or_add_key(lpkey,name);
658 } else {
659 LPBYTE data;
660 int len,lastmodified,type;
662 if (*s!='=') {
663 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
664 break;
666 s++;
667 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
668 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
669 break;
671 /* skip the 2 , */
672 s=strchr(s,',');s++;
673 s=strchr(s,',');s++;
674 if ((1<<type) & UNICONVMASK) {
675 s=_wine_read_USTRING(s,(LPWSTR*)&data);
676 if (data)
677 len = lstrlen32W((LPWSTR)data)*2+2;
678 else
679 len = 0;
680 } else {
681 len=strlen(s)/2;
682 data = (LPBYTE)xmalloc(len+1);
683 for (i=0;i<len;i++) {
684 data[i]=0;
685 if (*s>='0' && *s<='9')
686 data[i]=(*s-'0')<<4;
687 if (*s>='a' && *s<='f')
688 data[i]=(*s-'a')<<4;
689 if (*s>='A' && *s<='F')
690 data[i]=(*s-'A')<<4;
691 s++;
692 if (*s>='0' && *s<='9')
693 data[i]|=*s-'0';
694 if (*s>='a' && *s<='f')
695 data[i]|=*s-'a';
696 if (*s>='A' && *s<='F')
697 data[i]|=*s-'A';
698 s++;
701 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
704 /* read the next line */
705 if (!_wine_read_line(F,buf,buflen))
706 return 1;
708 return 1;
711 static int
712 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
713 int ver;
714 char *buf;
715 int buflen;
717 buf=xmalloc(10);buflen=10;
718 if (!_wine_read_line(F,&buf,&buflen)) {
719 free(buf);
720 return 0;
722 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
723 free(buf);
724 return 0;
726 if (ver!=REGISTRY_SAVE_VERSION) {
727 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
728 free(buf);
729 return 0;
731 if (!_wine_read_line(F,&buf,&buflen)) {
732 free(buf);
733 return 0;
735 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
736 free(buf);
737 return 0;
739 free(buf);
740 return 1;
743 static void
744 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
745 FILE *F;
747 F=fopen(fn,"rb");
748 if (F==NULL) {
749 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
750 fn,strerror(errno)
752 return;
754 if (!_wine_loadsubreg(F,lpkey,optflag)) {
755 fclose(F);
756 unlink(fn);
757 return;
759 fclose(F);
762 static void
763 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
764 LPKEYSTRUCT lpxkey;
765 int j;
766 LPKEYVALUE valfrom;
768 from=from->nextsub;
769 while (from) {
770 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
772 for (j=0;j<from->nrofvalues;j++) {
773 LPWSTR name;
774 LPBYTE data;
776 valfrom = from->values+j;
777 name=valfrom->name;
778 if (name) name=strdupW(name);
779 data=(LPBYTE)malloc(valfrom->len);
780 memcpy(data,valfrom->data,valfrom->len);
782 _find_or_add_value(
783 lpxkey,
784 name,
785 valfrom->type,
786 data,
787 valfrom->len,
788 valfrom->lastmodified
791 _copy_registry(from,lpxkey);
792 from = from->next;
796 /* WINDOWS 95 REGISTRY LOADER */
798 * Structure of a win95 registry database.
799 * main header:
800 * 0 : "CREG" - magic
801 * 4 : DWORD version
802 * 8 : DWORD offset_of_RGDB_part
803 * 0C..1F: ? (someone fill in please)
805 * 20: RGKN_section:
806 * header:
807 * 0 : "RGKN" - magic
808 * 4..0x1B: ? (fill in)
809 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
811 * Disk Key Entry Structure:
812 * 00: DWORD - unknown
813 * 04: DWORD - unknown
814 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
815 * 0C: DWORD - disk address of PreviousLevel Key.
816 * 10: DWORD - disk address of Next Sublevel Key.
817 * 14: DWORD - disk address of Next Key (on same level).
818 * DKEP>18: WORD - Nr, Low Significant part.
819 * 1A: WORD - Nr, High Significant part.
821 * The disk address always points to the nr part of the previous key entry
822 * of the referenced key. Don't ask me why, or even if I got this correct
823 * from staring at 1kg of hexdumps. (DKEP)
825 * The number of the entry is the low byte of the Low Significant Part ored
826 * with 0x100 * (low byte of the High Significant part)
827 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
829 * There are two minor corrections to the position of that structure.
830 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
831 * the DKE reread from there.
832 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
833 * (FIXME: slightly better explanation needed here)
835 * RGDB_section:
836 * 00: "RGDB" - magic
837 * 04: DWORD offset to next RGDB section (perhaps WORD)
838 * 08...1F: ?
839 * 20.....: disk keys
841 * disk key:
842 * 00: DWORD nextkeyoffset - offset to the next disk key structure
843 * 08: WORD nrLS - low significant part of NR
844 * 0A: WORD nrHS - high significant part of NR
845 * 0C: DWORD bytesused - bytes used in this structure.
846 * 10: WORD name_len - length of name in bytes. without \0
847 * 12: WORD nr_of_values - number of values.
848 * 14: char name[name_len] - name string. No \0.
849 * 14+name_len: disk values
850 * nextkeyoffset: ... next disk key
852 * disk value:
853 * 00: DWORD type - value type (hmm, could be WORD too)
854 * 04: DWORD - unknown, usually 0
855 * 08: WORD namelen - length of Name. 0 means name=NULL
856 * 0C: WORD datalen - length of Data.
857 * 10: char name[namelen] - name, no \0
858 * 10+namelen: BYTE data[datalen] - data, without \0 if string
859 * 10+namelen+datalen: next values or disk key
861 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
862 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
863 * structure) and reading another RGDB_section.
864 * repeat until end of file.
866 * FIXME: this description needs some serious help, yes.
869 struct _w95keyvalue {
870 unsigned long type;
871 unsigned short datalen;
872 char *name;
873 unsigned char *data;
874 unsigned long x1;
875 int lastmodified;
878 struct _w95key {
879 char *name;
880 int nrofvals;
881 struct _w95keyvalue *values;
882 unsigned long dkeaddr;
883 unsigned long x1;
884 unsigned long x2;
885 unsigned long x3;
886 unsigned long xx1;
887 struct _w95key *prevlvl;
888 struct _w95key *nextsub;
889 struct _w95key *next;
892 /* fast lookup table dkeaddr->nr */
893 struct _w95nr2da {
894 unsigned long dkeaddr;
895 unsigned long nr;
899 static void
900 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
901 int i;
902 LPKEYSTRUCT lpxkey;
903 LPWSTR name;
905 while (key) {
906 if (key->name == NULL) {
907 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
908 key->dkeaddr
910 return;
912 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
914 if (key->nrofvals<0) {
915 /* shouldn't happen */
916 fprintf(stderr,"key %s already processed!\n",key->name);
917 key = key->next;
918 continue;
920 for (i=0;i<key->nrofvals;i++) {
921 LPBYTE data;
922 int len;
924 name = strdupA2W(key->values[i].name);
925 if (!*name) name = NULL;
926 free(key->values[i].name);
928 len = key->values[i].datalen;
929 data = key->values[i].data;
930 if ((1<<key->values[i].type) & UNICONVMASK) {
931 data = (BYTE*)strdupA2W(data);
932 len = lstrlen32W((LPWSTR)data)*2+2;
933 free(key->values[i].data);
935 _find_or_add_value(
936 lpxkey,
937 name,
938 key->values[i].type,
939 data,
940 len,
941 key->values[i].lastmodified
944 if (key->values) {
945 free(key->values);
946 key->values = NULL;
948 key->nrofvals=-key->nrofvals-1;
949 _w95_walk_tree(lpxkey,key->nextsub);
950 key=key->next;
954 /* small helper function to adjust address offset (dkeaddrs) */
955 static unsigned long
956 _w95_adj_da(unsigned long dkeaddr) {
957 if ((dkeaddr&0xFFF)<0x018) {
958 int diff;
960 diff=0x1C-(dkeaddr&0xFFF);
961 return dkeaddr+diff;
963 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
964 /* readjust to 0x000,
965 * but ONLY if we are >0x1000 already
967 if (dkeaddr & ~0xFFF)
968 return dkeaddr & ~0xFFF;
970 return dkeaddr;
973 static int
974 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
976 static struct _w95key*
977 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
978 int i,off;
980 if (dkeaddr == 0xFFFFFFFF)
981 return NULL;
982 if (dkeaddr<0x20)
983 return NULL;
984 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
985 off = (dkeaddr-0x3c)/0x1c;
986 for (i=0;i<n;i++)
987 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
988 return keys+nr2da[(i+off)%n].nr;
989 /* 0x3C happens often, just report unusual values */
990 if (dkeaddr!=0x3c)
991 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
992 return NULL;
995 static void
996 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
997 /* Disk Key Entry structure (RGKN part) */
998 struct dke {
999 unsigned long x1;
1000 unsigned long x2;
1001 unsigned long x3;/*usually 0xFFFFFFFF */
1002 unsigned long prevlvl;
1003 unsigned long nextsub;
1004 unsigned long next;
1005 unsigned short nrLS;
1006 unsigned short nrMS;
1008 /* Disk Key Header structure (RGDB part) */
1009 struct dkh {
1010 unsigned long nextkeyoff;
1011 unsigned short nrLS;
1012 unsigned short nrMS;
1013 unsigned long bytesused;
1014 unsigned short keynamelen;
1015 unsigned short values;
1016 unsigned long xx1;
1017 /* keyname */
1018 /* disk key values or nothing */
1020 /* Disk Key Value structure */
1021 struct dkv {
1022 unsigned long type;
1023 unsigned long x1;
1024 unsigned short valnamelen;
1025 unsigned short valdatalen;
1026 /* valname, valdata */
1028 struct _w95nr2da *nr2da;
1030 HFILE hfd;
1031 int fd,lastmodified;
1032 char magic[5];
1033 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1034 struct _w95key *keys;
1035 int nrofdkes;
1036 unsigned char *data,*curdata,*nextrgdb;
1037 OFSTRUCT ofs;
1038 struct stat stbuf;
1040 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1041 hfd=OpenFile(fn,&ofs,OF_READ);
1042 if (hfd==HFILE_ERROR)
1043 return;
1044 fd = FILE_GetUnixHandle(hfd);
1045 magic[4]=0;
1046 if (4!=read(fd,magic,4))
1047 return;
1048 if (strcmp(magic,"CREG")) {
1049 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1050 return;
1052 if (4!=read(fd,&version,4))
1053 return;
1054 if (4!=read(fd,&rgdbsection,4))
1055 return;
1056 if (-1==lseek(fd,0x20,SEEK_SET))
1057 return;
1058 if (4!=read(fd,magic,4))
1059 return;
1060 if (strcmp(magic,"RGKN")) {
1061 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1062 return;
1065 /* STEP 1: Keylink structures */
1066 if (-1==lseek(fd,0x40,SEEK_SET))
1067 return;
1068 where = 0x40;
1069 end = rgdbsection;
1071 nrofdkes = (end-where)/sizeof(struct dke)+100;
1072 data = (char*)xmalloc(end-where);
1073 if ((end-where)!=read(fd,data,end-where))
1074 return;
1075 curdata = data;
1077 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1078 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1079 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1080 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1082 for (i=0;i<nrofdkes;i++) {
1083 struct dke dke;
1084 unsigned long dkeaddr;
1086 pos=curdata-data+0x40;
1087 memcpy(&dke,curdata,sizeof(dke));
1088 curdata+=sizeof(dke);
1089 nr = dke.nrLS + (dke.nrMS<<8);
1090 dkeaddr=pos-4;
1091 if ((dkeaddr&0xFFF)<0x018) {
1092 int diff;
1094 diff=0x1C-(dkeaddr&0xFFF);
1095 dkeaddr+=diff;
1096 curdata+=diff-sizeof(dke);
1097 memcpy(&dke,curdata,sizeof(dke));
1098 nr = dke.nrLS + (dke.nrMS<<8);
1099 curdata+=sizeof(dke);
1101 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1102 /* readjust to 0x000,
1103 * but ONLY if we are >0x1000 already
1105 if (dkeaddr & ~0xFFF)
1106 dkeaddr = dkeaddr & ~0xFFF;
1108 if (nr>nrofdkes) {
1109 /* 0xFFFFFFFF happens often, just report unusual values */
1110 if (nr!=0xFFFFFFFF)
1111 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1112 continue;
1114 if (keys[nr].dkeaddr) {
1115 int x;
1117 for (x=sizeof(dke);x--;)
1118 if (((char*)&dke)[x])
1119 break;
1120 if (x==-1)
1121 break; /* finished reading if we got only 0 */
1122 if (nr) {
1123 if ( (dke.next!=(long)keys[nr].next) ||
1124 (dke.nextsub!=(long)keys[nr].nextsub) ||
1125 (dke.prevlvl!=(long)keys[nr].prevlvl)
1127 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1129 continue;
1131 nr2da[i].nr = nr;
1132 nr2da[i].dkeaddr = dkeaddr;
1134 keys[nr].dkeaddr = dkeaddr;
1135 keys[nr].x1 = dke.x1;
1136 keys[nr].x2 = dke.x2;
1137 keys[nr].x3 = dke.x3;
1138 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1139 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1140 keys[nr].next = (struct _w95key*)dke.next;
1142 free(data);
1144 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),_w95dkecomp);
1146 /* STEP 2: keydata & values */
1147 if (-1==fstat(fd,&stbuf))
1148 return;
1149 end = stbuf.st_size;
1150 lastmodified = stbuf.st_mtime;
1152 if (-1==lseek(fd,rgdbsection,SEEK_SET))
1153 return;
1154 data = (char*)xmalloc(end-rgdbsection);
1155 if ((end-rgdbsection)!=read(fd,data,end-rgdbsection))
1156 return;
1157 _lclose(hfd);
1158 curdata = data;
1159 memcpy(magic,curdata,4);
1160 memcpy(&off_next_rgdb,curdata+4,4);
1161 nextrgdb = curdata+off_next_rgdb;
1162 if (strcmp(magic,"RGDB")) {
1163 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1164 return;
1166 curdata=data+0x20;
1167 while (1) {
1168 struct dkh dkh;
1169 int bytesread;
1170 struct _w95key *key,xkey;
1172 bytesread = 0;
1173 if (curdata>=nextrgdb) {
1174 curdata = nextrgdb;
1175 if (!strncmp(curdata,"RGDB",4)) {
1176 memcpy(&off_next_rgdb,curdata+4,4);
1177 nextrgdb = curdata+off_next_rgdb;
1178 curdata+=0x20;
1179 } else {
1180 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1181 break;
1184 #define XREAD(whereto,len) \
1185 if ((curdata-data+len)<end) {\
1186 memcpy(whereto,curdata,len);\
1187 curdata+=len;\
1188 bytesread+=len;\
1191 XREAD(&dkh,sizeof(dkh));
1192 nr = dkh.nrLS + (dkh.nrMS<<8);
1193 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1194 if (dkh.nrLS == 0xFFFF) {
1195 /* skip over key using nextkeyoff */
1196 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1197 continue;
1199 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1200 key = &xkey;
1201 memset(key,'\0',sizeof(xkey));
1202 } else {
1203 key = keys+nr;
1204 if (!key->dkeaddr)
1205 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1207 key->nrofvals = dkh.values;
1208 key->name = (char*)xmalloc(dkh.keynamelen+1);
1209 key->xx1 = dkh.xx1;
1210 XREAD(key->name,dkh.keynamelen);
1211 key->name[dkh.keynamelen]=0;
1212 if (key->nrofvals) {
1213 key->values = (struct _w95keyvalue*)xmalloc(
1214 sizeof(struct _w95keyvalue)*key->nrofvals
1216 for (i=0;i<key->nrofvals;i++) {
1217 struct dkv dkv;
1219 XREAD(&dkv,sizeof(dkv));
1220 key->values[i].type = dkv.type;
1221 key->values[i].name = (char*)xmalloc(
1222 dkv.valnamelen+1
1224 key->values[i].datalen = dkv.valdatalen;
1225 key->values[i].data = (unsigned char*)xmalloc(
1226 dkv.valdatalen+1
1228 key->values[i].x1 = dkv.x1;
1229 XREAD(key->values[i].name,dkv.valnamelen);
1230 XREAD(key->values[i].data,dkv.valdatalen);
1231 key->values[i].data[dkv.valdatalen]=0;
1232 key->values[i].name[dkv.valnamelen]=0;
1233 key->values[i].lastmodified=lastmodified;
1236 if (bytesread != dkh.nextkeyoff) {
1237 if (dkh.bytesused != bytesread)
1238 dprintf_reg(stddeb,
1239 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1240 dkh.bytesused
1242 curdata += dkh.nextkeyoff-bytesread;
1244 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1245 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1246 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1247 if (!bytesread)
1248 break;
1250 free(data);
1251 _w95_walk_tree(lpkey,keys);
1252 free(keys);
1255 void
1256 SHELL_LoadRegistry() {
1257 char *fn;
1258 struct passwd *pwd;
1259 LPKEYSTRUCT lpkey;
1260 HKEY hkey;
1263 if (key_classes_root==NULL)
1264 SHELL_Init();
1266 /* Load windows 95 entries */
1267 _w95_loadreg("C:\\system.1st", key_local_machine);
1268 _w95_loadreg("system.dat", key_local_machine);
1269 _w95_loadreg("user.dat", key_users);
1271 /* FIXME: win3.1 reg.dat loader still missing */
1273 /* the global user default is loaded under HKEY_USERS\\.Default */
1274 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1275 lpkey = lookup_hkey(hkey);
1276 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1278 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1279 _copy_registry(lpkey,key_current_user);
1280 RegCloseKey(hkey);
1282 /* the global machine defaults */
1283 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1285 /* load the user saved registries */
1287 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1289 pwd=getpwuid(getuid());
1290 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1291 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1292 strcpy(fn,pwd->pw_dir);
1293 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1294 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1295 free(fn);
1296 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1297 strcpy(fn,pwd->pw_dir);
1298 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1299 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1300 free(fn);
1301 } else
1302 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1303 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1304 DWORD junk,type,len;
1305 char data[5];
1307 len=4;
1308 if (( RegQueryValueEx32A(
1309 hkey,
1310 VAL_SAVEUPDATED,
1311 &junk,
1312 &type,
1313 data,
1314 &len
1315 )!=ERROR_SUCCESS) ||
1316 type != REG_SZ
1318 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1319 RegCloseKey(hkey);
1324 /********************* API FUNCTIONS ***************************************/
1326 * Open Keys.
1328 * All functions are stubs to RegOpenKeyEx32W where all the
1329 * magic happens.
1331 * FIXME: security,options,desiredaccess,...
1333 * Callpath:
1334 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1335 * RegOpenKey32W -> RegOpenKeyEx32W
1338 /* RegOpenKeyExW [ADVAPI32.150] */
1339 DWORD RegOpenKeyEx32W(
1340 HKEY hkey,
1341 LPCWSTR lpszSubKey,
1342 DWORD dwReserved,
1343 REGSAM samDesired,
1344 LPHKEY retkey
1346 LPKEYSTRUCT lpNextKey,lpxkey;
1347 LPWSTR *wps;
1348 int wpc,i;
1349 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1350 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1353 lpNextKey = lookup_hkey(hkey);
1354 if (!lpNextKey)
1355 return SHELL_ERROR_BADKEY;
1356 if (!lpszSubKey || !*lpszSubKey) {
1357 add_handle(++currenthandle,lpNextKey,samDesired);
1358 *retkey=currenthandle;
1359 return SHELL_ERROR_SUCCESS;
1361 split_keypath(lpszSubKey,&wps,&wpc);
1362 i = 0;
1363 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1364 lpxkey = lpNextKey;
1365 while (i<wpc) {
1366 lpxkey=lpNextKey->nextsub;
1367 while (lpxkey) {
1368 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1369 break;
1370 lpxkey=lpxkey->next;
1372 if (!lpxkey) {
1373 FREE_KEY_PATH;
1374 return SHELL_ERROR_BADKEY;
1376 i++;
1377 lpNextKey = lpxkey;
1379 add_handle(++currenthandle,lpxkey,samDesired);
1380 *retkey = currenthandle;
1381 FREE_KEY_PATH;
1382 return SHELL_ERROR_SUCCESS;
1385 /* RegOpenKeyW [ADVAPI32.151] */
1386 DWORD RegOpenKey32W(
1387 HKEY hkey,
1388 LPCWSTR lpszSubKey,
1389 LPHKEY retkey
1391 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1392 (LONG)hkey,W2C(lpszSubKey,0),retkey
1394 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1398 /* RegOpenKeyExA [ADVAPI32.149] */
1399 DWORD RegOpenKeyEx32A(
1400 HKEY hkey,
1401 LPCSTR lpszSubKey,
1402 DWORD dwReserved,
1403 REGSAM samDesired,
1404 LPHKEY retkey
1406 LPWSTR lpszSubKeyW;
1407 DWORD ret;
1409 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1410 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1412 if (lpszSubKey)
1413 lpszSubKeyW=strdupA2W(lpszSubKey);
1414 else
1415 lpszSubKeyW=NULL;
1416 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1417 if (lpszSubKeyW)
1418 free(lpszSubKeyW);
1419 return ret;
1422 /* RegOpenKeyA [ADVAPI32.148] */
1423 DWORD RegOpenKey32A(
1424 HKEY hkey,
1425 LPCSTR lpszSubKey,
1426 LPHKEY retkey
1428 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1429 (LONG)hkey,lpszSubKey,retkey
1431 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1434 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1435 DWORD RegOpenKey16(
1436 HKEY hkey,
1437 LPCSTR lpszSubKey,
1438 LPHKEY retkey
1440 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1441 (LONG)hkey,lpszSubKey,retkey
1443 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1447 * Create keys
1449 * All those functions convert their respective
1450 * arguments and call RegCreateKeyExW at the end.
1452 * FIXME: no security,no access attrib,no optionhandling yet.
1454 * Callpath:
1455 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1456 * RegCreateKey32W -> RegCreateKeyEx32W
1459 /* RegCreateKeyExW [ADVAPI32.131] */
1460 DWORD RegCreateKeyEx32W(
1461 HKEY hkey,
1462 LPCWSTR lpszSubKey,
1463 DWORD dwReserved,
1464 LPWSTR lpszClass,
1465 DWORD fdwOptions,
1466 REGSAM samDesired,
1467 LPSECURITY_ATTRIBUTES lpSecAttribs,
1468 LPHKEY retkey,
1469 LPDWORD lpDispos
1471 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1472 LPWSTR *wps;
1473 int wpc,i;
1475 /*FIXME: handle security/access/whatever */
1476 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1477 (LONG)hkey,
1478 W2C(lpszSubKey,0),
1479 dwReserved,
1480 W2C(lpszClass,1),
1481 fdwOptions,
1482 samDesired,
1483 lpSecAttribs,
1484 retkey,
1485 lpDispos
1488 lpNextKey = lookup_hkey(hkey);
1489 if (!lpNextKey)
1490 return SHELL_ERROR_BADKEY;
1491 if (!lpszSubKey || !*lpszSubKey) {
1492 add_handle(++currenthandle,lpNextKey,samDesired);
1493 *retkey=currenthandle;
1494 return SHELL_ERROR_SUCCESS;
1496 split_keypath(lpszSubKey,&wps,&wpc);
1497 i = 0;
1498 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1499 lpxkey = lpNextKey;
1500 while (i<wpc) {
1501 lpxkey=lpNextKey->nextsub;
1502 while (lpxkey) {
1503 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1504 break;
1505 lpxkey=lpxkey->next;
1507 if (!lpxkey)
1508 break;
1509 i++;
1510 lpNextKey = lpxkey;
1512 if (lpxkey) {
1513 add_handle(++currenthandle,lpxkey,samDesired);
1514 *retkey = currenthandle;
1515 *lpDispos = REG_OPENED_EXISTING_KEY;
1516 FREE_KEY_PATH;
1517 return SHELL_ERROR_SUCCESS;
1519 /* good. now the hard part */
1520 while (i<wpc) {
1521 lplpPrevKey = &(lpNextKey->nextsub);
1522 lpxkey = *lplpPrevKey;
1523 while (lpxkey) {
1524 lplpPrevKey = &(lpxkey->next);
1525 lpxkey = *lplpPrevKey;
1527 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1528 if (!*lplpPrevKey) {
1529 FREE_KEY_PATH;
1530 return SHELL_ERROR_OUTOFMEMORY;
1532 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1533 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1534 (*lplpPrevKey)->next = NULL;
1535 (*lplpPrevKey)->nextsub = NULL;
1536 (*lplpPrevKey)->values = NULL;
1537 (*lplpPrevKey)->nrofvalues = 0;
1538 if (lpszClass)
1539 (*lplpPrevKey)->class = strdupW(lpszClass);
1540 else
1541 (*lplpPrevKey)->class = NULL;
1542 lpNextKey = *lplpPrevKey;
1543 i++;
1545 add_handle(++currenthandle,lpNextKey,samDesired);
1547 /*FIXME: flag handling correct? */
1548 lpNextKey->flags= fdwOptions;
1549 if (lpszClass)
1550 lpNextKey->class = strdupW(lpszClass);
1551 else
1552 lpNextKey->class = NULL;
1553 lpNextKey->flags|=REG_OPTION_TAINTED;
1554 *retkey = currenthandle;
1555 *lpDispos = REG_CREATED_NEW_KEY;
1556 FREE_KEY_PATH;
1557 return SHELL_ERROR_SUCCESS;
1560 /* RegCreateKeyW [ADVAPI32.132] */
1561 DWORD RegCreateKey32W(
1562 HKEY hkey,
1563 LPCWSTR lpszSubKey,
1564 LPHKEY retkey
1566 DWORD junk,ret;
1568 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1569 (LONG)hkey,W2C(lpszSubKey,0),retkey
1571 ret=RegCreateKeyEx32W(
1572 hkey, /* key handle */
1573 lpszSubKey, /* subkey name */
1574 0, /* reserved = 0 */
1575 NULL, /* lpszClass? FIXME: ? */
1576 REG_OPTION_NON_VOLATILE, /* options */
1577 KEY_ALL_ACCESS, /* desired access attribs */
1578 NULL, /* lpsecurity attributes */
1579 retkey, /* lpretkey */
1580 &junk /* disposition value */
1582 return ret;
1585 /* RegCreateKeyExA [ADVAPI32.130] */
1586 DWORD RegCreateKeyEx32A(
1587 HKEY hkey,
1588 LPCSTR lpszSubKey,
1589 DWORD dwReserved,
1590 LPSTR lpszClass,
1591 DWORD fdwOptions,
1592 REGSAM samDesired,
1593 LPSECURITY_ATTRIBUTES lpSecAttribs,
1594 LPHKEY retkey,
1595 LPDWORD lpDispos
1597 LPWSTR lpszSubKeyW,lpszClassW;
1598 DWORD ret;
1600 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1601 (LONG)hkey,
1602 lpszSubKey,
1603 dwReserved,
1604 lpszClass,
1605 fdwOptions,
1606 samDesired,
1607 lpSecAttribs,
1608 retkey,
1609 lpDispos
1611 if (lpszSubKey)
1612 lpszSubKeyW=strdupA2W(lpszSubKey);
1613 else
1614 lpszSubKeyW=NULL;
1615 if (lpszClass)
1616 lpszClassW=strdupA2W(lpszClass);
1617 else
1618 lpszClassW=NULL;
1619 ret=RegCreateKeyEx32W(
1620 hkey,
1621 lpszSubKeyW,
1622 dwReserved,
1623 lpszClassW,
1624 fdwOptions,
1625 samDesired,
1626 lpSecAttribs,
1627 retkey,
1628 lpDispos
1630 if (lpszSubKeyW)
1631 free(lpszSubKeyW);
1632 if (lpszClassW)
1633 free(lpszClassW);
1634 return ret;
1637 /* RegCreateKeyA [ADVAPI32.129] */
1638 DWORD RegCreateKey32A(
1639 HKEY hkey,
1640 LPCSTR lpszSubKey,
1641 LPHKEY retkey
1643 DWORD junk;
1645 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1646 (LONG)hkey,lpszSubKey,retkey
1648 return RegCreateKeyEx32A(
1649 hkey, /* key handle */
1650 lpszSubKey, /* subkey name */
1651 0, /* reserved = 0 */
1652 NULL, /* lpszClass? FIXME: ? */
1653 REG_OPTION_NON_VOLATILE,/* options */
1654 KEY_ALL_ACCESS, /* desired access attribs */
1655 NULL, /* lpsecurity attributes */
1656 retkey, /* lpretkey */
1657 &junk /* disposition value */
1661 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1662 DWORD RegCreateKey16(
1663 HKEY hkey,
1664 LPCSTR lpszSubKey,
1665 LPHKEY retkey
1667 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1668 (LONG)hkey,lpszSubKey,retkey
1670 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1674 * Query Value Functions
1675 * Win32 differs between keynames and valuenames.
1676 * multiple values may belong to one key, the special value
1677 * with name NULL is the default value used by the win31
1678 * compat functions.
1680 * Callpath:
1681 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1682 * RegQueryValue32W -> RegQueryValueEx32W
1685 /* RegQueryValueExW [ADVAPI32.158] */
1686 DWORD RegQueryValueEx32W(
1687 HKEY hkey,
1688 LPWSTR lpszValueName,
1689 LPDWORD lpdwReserved,
1690 LPDWORD lpdwType,
1691 LPBYTE lpbData,
1692 LPDWORD lpcbData
1694 LPKEYSTRUCT lpkey;
1695 int i;
1697 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1698 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1699 lpcbData?*lpcbData:0
1702 lpkey = lookup_hkey(hkey);
1703 if (!lpkey)
1704 return SHELL_ERROR_BADKEY;
1705 if (lpszValueName==NULL) {
1706 for (i=0;i<lpkey->nrofvalues;i++)
1707 if (lpkey->values[i].name==NULL)
1708 break;
1709 } else {
1710 for (i=0;i<lpkey->nrofvalues;i++)
1711 if ( lpkey->values[i].name &&
1712 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1714 break;
1716 if (i==lpkey->nrofvalues) {
1717 if (lpszValueName==NULL) {
1718 if (lpbData) {
1719 *(WCHAR*)lpbData = 0;
1720 *lpcbData = 2;
1722 if (lpdwType)
1723 *lpdwType = REG_SZ;
1724 return SHELL_ERROR_SUCCESS;
1726 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1728 if (lpdwType)
1729 *lpdwType = lpkey->values[i].type;
1730 if (lpbData==NULL) {
1731 if (lpcbData==NULL)
1732 return SHELL_ERROR_SUCCESS;
1733 *lpcbData = lpkey->values[i].len;
1734 return SHELL_ERROR_SUCCESS;
1736 if (*lpcbData<lpkey->values[i].len) {
1737 *(WCHAR*)lpbData
1738 = 0;
1739 *lpcbData = lpkey->values[i].len;
1740 return ERROR_MORE_DATA;
1742 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1743 *lpcbData = lpkey->values[i].len;
1744 return SHELL_ERROR_SUCCESS;
1747 /* RegQueryValueW [ADVAPI32.159] */
1748 DWORD RegQueryValue32W(
1749 HKEY hkey,
1750 LPWSTR lpszSubKey,
1751 LPWSTR lpszData,
1752 LPDWORD lpcbData
1754 HKEY xhkey;
1755 DWORD ret,lpdwType;
1757 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1758 hkey,W2C(lpszSubKey,0),lpszData,
1759 lpcbData?*lpcbData:0
1762 /* only open subkey, if we really do descend */
1763 if (lpszSubKey && *lpszSubKey) {
1764 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1765 if (ret!=ERROR_SUCCESS)
1766 return ret;
1767 } else
1768 xhkey = hkey;
1770 lpdwType = REG_SZ;
1771 ret = RegQueryValueEx32W(
1772 xhkey,
1773 NULL, /* varname NULL -> compat */
1774 NULL, /* lpdwReserved, must be NULL */
1775 &lpdwType,
1776 (LPBYTE)lpszData,
1777 lpcbData
1779 if (xhkey!=hkey)
1780 RegCloseKey(xhkey);
1781 return ret;
1784 /* RegQueryValueExA [ADVAPI32.157] */
1785 DWORD RegQueryValueEx32A(
1786 HKEY hkey,
1787 LPSTR lpszValueName,
1788 LPDWORD lpdwReserved,
1789 LPDWORD lpdwType,
1790 LPBYTE lpbData,
1791 LPDWORD lpcbData
1793 LPWSTR lpszValueNameW;
1794 LPBYTE buf;
1795 DWORD ret,myxlen;
1796 DWORD *mylen;
1797 DWORD type;
1799 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
1800 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1801 lpcbData?*lpcbData:0
1803 if (lpbData) {
1804 /* double buffer */
1805 buf = (LPBYTE)xmalloc((*lpcbData)*2);
1806 myxlen = *lpcbData*2;
1807 mylen = &myxlen;
1808 } else {
1809 buf=NULL;
1810 if (lpcbData) {
1811 myxlen = *lpcbData*2;
1812 mylen = &myxlen;
1813 } else
1814 mylen = NULL;
1816 if (lpszValueName)
1817 lpszValueNameW=strdupA2W(lpszValueName);
1818 else
1819 lpszValueNameW=NULL;
1821 if (lpdwType)
1822 type=*lpdwType;
1823 ret=RegQueryValueEx32W(
1824 hkey,
1825 lpszValueNameW,
1826 lpdwReserved,
1827 &type,
1828 buf,
1829 mylen
1831 if (lpdwType)
1832 *lpdwType=type;
1833 if (ret==ERROR_SUCCESS) {
1834 if (buf) {
1835 if (UNICONVMASK & (1<<(type))) {
1836 /* convert UNICODE to ASCII */
1837 strcpyWA(lpbData,(LPWSTR)buf);
1838 *lpcbData = myxlen/2;
1839 } else {
1840 if (myxlen>*lpcbData)
1841 ret = ERROR_MORE_DATA;
1842 else
1843 memcpy(lpbData,buf,myxlen);
1845 *lpcbData = myxlen;
1847 } else {
1848 if ((UNICONVMASK & (1<<(type))) && lpcbData)
1849 *lpcbData = myxlen/2;
1851 } else {
1852 if ((UNICONVMASK & (1<<(type))) && lpcbData)
1853 *lpcbData = myxlen/2;
1855 if (buf)
1856 free(buf);
1857 return ret;
1860 /* RegQueryValueEx [KERNEL.225] */
1861 DWORD RegQueryValueEx16(
1862 HKEY hkey,
1863 LPSTR lpszValueName,
1864 LPDWORD lpdwReserved,
1865 LPDWORD lpdwType,
1866 LPBYTE lpbData,
1867 LPDWORD lpcbData
1869 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
1870 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1871 lpcbData?*lpcbData:0
1873 return RegQueryValueEx32A(
1874 hkey,
1875 lpszValueName,
1876 lpdwReserved,
1877 lpdwType,
1878 lpbData,
1879 lpcbData
1883 /* RegQueryValueA [ADVAPI32.156] */
1884 DWORD RegQueryValue32A(
1885 HKEY hkey,
1886 LPSTR lpszSubKey,
1887 LPSTR lpszData,
1888 LPDWORD lpcbData
1890 HKEY xhkey;
1891 DWORD ret,lpdwType;
1893 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
1894 hkey,lpszSubKey,lpszData,
1895 lpcbData?*lpcbData:0
1898 /* only open subkey, if we really do descend */
1899 if (lpszSubKey && *lpszSubKey) {
1900 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
1901 if (ret!=ERROR_SUCCESS)
1902 return ret;
1903 } else
1904 xhkey = hkey;
1906 lpdwType = REG_SZ;
1907 ret = RegQueryValueEx32A(
1908 xhkey,
1909 NULL, /* lpszValueName NULL -> compat */
1910 NULL, /* lpdwReserved, must be NULL */
1911 &lpdwType,
1912 (LPBYTE)lpszData,
1913 lpcbData
1915 if (xhkey!=hkey)
1916 RegCloseKey(xhkey);
1917 return ret;
1920 /* RegQueryValue [SHELL.6] [KERNEL.224] */
1921 DWORD RegQueryValue16(
1922 HKEY hkey,
1923 LPSTR lpszSubKey,
1924 LPSTR lpszData,
1925 LPDWORD lpcbData
1927 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
1928 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
1930 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
1931 * anyway, so we just mask out the high 16 bit.
1932 * (this (not so much incidently;) hopefully fixes Aldus FH4)
1934 if (lpcbData)
1935 *lpcbData &= 0xFFFF;
1936 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
1940 * Setting values of Registry keys
1942 * Callpath:
1943 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
1944 * RegSetValue32W -> RegSetValueEx32W
1947 /* RegSetValueExW [ADVAPI32.170] */
1948 DWORD RegSetValueEx32W(
1949 HKEY hkey,
1950 LPWSTR lpszValueName,
1951 DWORD dwReserved,
1952 DWORD dwType,
1953 LPBYTE lpbData,
1954 DWORD cbData
1956 LPKEYSTRUCT lpkey;
1957 int i;
1959 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
1960 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
1962 /* we no longer care about the lpbData type here... */
1963 lpkey = lookup_hkey(hkey);
1964 if (!lpkey)
1965 return SHELL_ERROR_BADKEY;
1967 lpkey->flags |= REG_OPTION_TAINTED;
1969 if (lpszValueName==NULL) {
1970 for (i=0;i<lpkey->nrofvalues;i++)
1971 if (lpkey->values[i].name==NULL)
1972 break;
1973 } else {
1974 for (i=0;i<lpkey->nrofvalues;i++)
1975 if ( lpkey->values[i].name &&
1976 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1978 break;
1980 if (i==lpkey->nrofvalues) {
1981 lpkey->values = (LPKEYVALUE)xrealloc(
1982 lpkey->values,
1983 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
1985 lpkey->nrofvalues++;
1986 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
1988 if (lpkey->values[i].name==NULL)
1989 if (lpszValueName)
1990 lpkey->values[i].name = strdupW(lpszValueName);
1991 else
1992 lpkey->values[i].name = NULL;
1993 lpkey->values[i].len = cbData;
1994 lpkey->values[i].type = dwType;
1995 if (lpkey->values[i].data !=NULL)
1996 free(lpkey->values[i].data);
1997 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
1998 lpkey->values[i].lastmodified = time(NULL);
1999 memcpy(lpkey->values[i].data,lpbData,cbData);
2000 return SHELL_ERROR_SUCCESS;
2003 /* RegSetValueExA [ADVAPI32.169] */
2004 DWORD RegSetValueEx32A(
2005 HKEY hkey,
2006 LPSTR lpszValueName,
2007 DWORD dwReserved,
2008 DWORD dwType,
2009 LPBYTE lpbData,
2010 DWORD cbData
2012 LPBYTE buf;
2013 LPWSTR lpszValueNameW;
2014 DWORD ret;
2016 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2017 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2019 if ((1<<dwType) & UNICONVMASK) {
2020 buf=(LPBYTE)strdupA2W(lpbData);
2021 cbData=2*strlen(lpbData)+2;
2022 } else
2023 buf=lpbData;
2024 if (lpszValueName)
2025 lpszValueNameW = strdupA2W(lpszValueName);
2026 else
2027 lpszValueNameW = NULL;
2028 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2029 if (lpszValueNameW)
2030 free(lpszValueNameW);
2031 if (buf!=lpbData)
2032 free(buf);
2033 return ret;
2036 /* RegSetValueEx [KERNEL.226] */
2037 DWORD RegSetValueEx16(
2038 HKEY hkey,
2039 LPSTR lpszValueName,
2040 DWORD dwReserved,
2041 DWORD dwType,
2042 LPBYTE lpbData,
2043 DWORD cbData
2045 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2046 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2048 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2051 /* RegSetValueW [ADVAPI32.171] */
2052 DWORD RegSetValue32W(
2053 HKEY hkey,
2054 LPCWSTR lpszSubKey,
2055 DWORD dwType,
2056 LPCWSTR lpszData,
2057 DWORD cbData
2059 HKEY xhkey;
2060 DWORD ret;
2062 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2063 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2065 if (lpszSubKey && *lpszSubKey) {
2066 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2067 if (ret!=ERROR_SUCCESS)
2068 return ret;
2069 } else
2070 xhkey=hkey;
2071 if (dwType!=REG_SZ) {
2072 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2073 dwType=REG_SZ;
2075 if (cbData!=2*lstrlen32W(lpszData)+2) {
2076 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2077 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2079 cbData=2*lstrlen32W(lpszData)+2;
2081 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2082 if (hkey!=xhkey)
2083 RegCloseKey(xhkey);
2084 return ret;
2087 /* RegSetValueA [ADVAPI32.168] */
2088 DWORD RegSetValue32A(
2089 HKEY hkey,
2090 LPCSTR lpszSubKey,
2091 DWORD dwType,
2092 LPCSTR lpszData,
2093 DWORD cbData
2095 DWORD ret;
2096 HKEY xhkey;
2098 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2099 hkey,lpszSubKey,dwType,lpszData,cbData
2101 if (lpszSubKey && *lpszSubKey) {
2102 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2103 if (ret!=ERROR_SUCCESS)
2104 return ret;
2105 } else
2106 xhkey=hkey;
2108 if (dwType!=REG_SZ) {
2109 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2110 dwType=REG_SZ;
2112 if (cbData!=strlen(lpszData)+1)
2113 cbData=strlen(lpszData)+1;
2114 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2115 if (xhkey!=hkey)
2116 RegCloseKey(xhkey);
2117 return ret;
2120 /* RegSetValue [KERNEL.221] [SHELL.5] */
2121 DWORD RegSetValue16(
2122 HKEY hkey,
2123 LPCSTR lpszSubKey,
2124 DWORD dwType,
2125 LPCSTR lpszData,
2126 DWORD cbData
2128 DWORD ret;
2129 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2130 hkey,lpszSubKey,dwType,lpszData,cbData
2132 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2133 return ret;
2137 * Key Enumeration
2139 * Callpath:
2140 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2141 * RegEnumKey32W -> RegEnumKeyEx32W
2144 /* RegEnumKeyExW [ADVAPI32.139] */
2145 DWORD RegEnumKeyEx32W(
2146 HKEY hkey,
2147 DWORD iSubkey,
2148 LPWSTR lpszName,
2149 LPDWORD lpcchName,
2150 LPDWORD lpdwReserved,
2151 LPWSTR lpszClass,
2152 LPDWORD lpcchClass,
2153 FILETIME *ft
2155 LPKEYSTRUCT lpkey,lpxkey;
2157 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2158 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2160 lpkey=lookup_hkey(hkey);
2161 if (!lpkey)
2162 return SHELL_ERROR_BADKEY;
2163 if (!lpkey->nextsub)
2164 return ERROR_NO_MORE_ITEMS;
2165 lpxkey=lpkey->nextsub;
2166 while (iSubkey && lpxkey) {
2167 iSubkey--;
2168 lpxkey=lpxkey->next;
2170 if (iSubkey || !lpxkey)
2171 return ERROR_NO_MORE_ITEMS;
2172 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2173 return ERROR_MORE_DATA;
2174 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2175 if (lpszClass) {
2176 /* what should we write into it? */
2177 *lpszClass = 0;
2178 *lpcchClass = 2;
2180 return ERROR_SUCCESS;
2184 /* RegEnumKeyW [ADVAPI32.140] */
2185 DWORD RegEnumKey32W(
2186 HKEY hkey,
2187 DWORD iSubkey,
2188 LPWSTR lpszName,
2189 DWORD lpcchName
2191 FILETIME ft;
2193 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2194 hkey,iSubkey,lpszName,lpcchName
2196 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2198 /* RegEnumKeyExA [ADVAPI32.138] */
2199 DWORD RegEnumKeyEx32A(
2200 HKEY hkey,
2201 DWORD iSubkey,
2202 LPSTR lpszName,
2203 LPDWORD lpcchName,
2204 LPDWORD lpdwReserved,
2205 LPSTR lpszClass,
2206 LPDWORD lpcchClass,
2207 FILETIME *ft
2209 DWORD ret,lpcchNameW,lpcchClassW;
2210 LPWSTR lpszNameW,lpszClassW;
2213 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2214 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2216 if (lpszName) {
2217 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2218 lpcchNameW = *lpcchName*2;
2219 } else {
2220 lpszNameW = NULL;
2221 lpcchNameW = 0;
2223 if (lpszClass) {
2224 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2225 lpcchClassW = *lpcchClass*2;
2226 } else {
2227 lpszClassW =0;
2228 lpcchClassW=0;
2230 ret=RegEnumKeyEx32W(
2231 hkey,
2232 iSubkey,
2233 lpszNameW,
2234 &lpcchNameW,
2235 lpdwReserved,
2236 lpszClassW,
2237 &lpcchClassW,
2240 if (ret==ERROR_SUCCESS) {
2241 strcpyWA(lpszName,lpszNameW);
2242 *lpcchName=strlen(lpszName);
2243 if (lpszClassW) {
2244 strcpyWA(lpszClass,lpszClassW);
2245 *lpcchClass=strlen(lpszClass);
2248 if (lpszNameW)
2249 free(lpszNameW);
2250 if (lpszClassW)
2251 free(lpszClassW);
2252 return ret;
2255 /* RegEnumKeyA [ADVAPI32.137] */
2256 DWORD RegEnumKey32A(
2257 HKEY hkey,
2258 DWORD iSubkey,
2259 LPSTR lpszName,
2260 DWORD lpcchName
2262 FILETIME ft;
2264 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2265 hkey,iSubkey,lpszName,lpcchName
2267 return RegEnumKeyEx32A(
2268 hkey,
2269 iSubkey,
2270 lpszName,
2271 &lpcchName,
2272 NULL,
2273 NULL,
2274 NULL,
2279 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2280 DWORD RegEnumKey16(
2281 HKEY hkey,
2282 DWORD iSubkey,
2283 LPSTR lpszName,
2284 DWORD lpcchName
2286 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2287 hkey,iSubkey,lpszName,lpcchName
2289 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2293 * Enumerate Registry Values
2295 * Callpath:
2296 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2299 /* RegEnumValueW [ADVAPI32.142] */
2300 DWORD RegEnumValue32W(
2301 HKEY hkey,
2302 DWORD iValue,
2303 LPWSTR lpszValue,
2304 LPDWORD lpcchValue,
2305 LPDWORD lpdReserved,
2306 LPDWORD lpdwType,
2307 LPBYTE lpbData,
2308 LPDWORD lpcbData
2310 LPKEYSTRUCT lpkey;
2311 LPKEYVALUE val;
2313 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2314 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2316 lpkey = lookup_hkey(hkey);
2317 if (!lpkey)
2318 return SHELL_ERROR_BADKEY;
2319 if (lpkey->nrofvalues<=iValue)
2320 return ERROR_NO_MORE_ITEMS;
2321 val = lpkey->values+iValue;
2323 if (val->name) {
2324 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2325 *lpcchValue = lstrlen32W(val->name)*2+2;
2326 return ERROR_MORE_DATA;
2328 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2329 *lpcchValue=lstrlen32W(val->name)*2+2;
2330 } else {
2331 /* how to handle NULL value? */
2332 *lpszValue = 0;
2333 *lpcchValue = 2;
2335 *lpdwType=val->type;
2336 if (lpbData) {
2337 if (val->len>*lpcbData)
2338 return ERROR_MORE_DATA;
2339 memcpy(lpbData,val->data,val->len);
2340 *lpcbData = val->len;
2342 return SHELL_ERROR_SUCCESS;
2345 /* RegEnumValueA [ADVAPI32.141] */
2346 DWORD RegEnumValue32A(
2347 HKEY hkey,
2348 DWORD iValue,
2349 LPSTR lpszValue,
2350 LPDWORD lpcchValue,
2351 LPDWORD lpdReserved,
2352 LPDWORD lpdwType,
2353 LPBYTE lpbData,
2354 LPDWORD lpcbData
2356 LPWSTR lpszValueW;
2357 LPBYTE lpbDataW;
2358 DWORD ret,lpcbDataW;
2360 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2361 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2364 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2365 if (lpbData) {
2366 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2367 lpcbDataW = *lpcbData*2;
2368 } else
2369 lpbDataW = NULL;
2370 ret=RegEnumValue32W(
2371 hkey,
2372 iValue,
2373 lpszValueW,
2374 lpcchValue,
2375 lpdReserved,
2376 lpdwType,
2377 lpbDataW,
2378 &lpcbDataW
2381 if (ret==ERROR_SUCCESS) {
2382 strcpyWA(lpszValue,lpszValueW);
2383 if (lpbData) {
2384 if ((1<<*lpdwType) & UNICONVMASK) {
2385 strcpyWA(lpbData,(LPWSTR)lpbDataW);
2386 } else {
2387 if (lpcbDataW > *lpcbData)
2388 ret = ERROR_MORE_DATA;
2389 else
2390 memcpy(lpbData,lpbDataW,lpcbDataW);
2392 *lpcbData = lpcbDataW;
2395 if (lpbDataW)
2396 free(lpbDataW);
2397 if (lpszValueW)
2398 free(lpszValueW);
2399 return ret;
2402 /* RegEnumValue [KERNEL.223] */
2403 DWORD RegEnumValue16(
2404 HKEY hkey,
2405 DWORD iValue,
2406 LPSTR lpszValue,
2407 LPDWORD lpcchValue,
2408 LPDWORD lpdReserved,
2409 LPDWORD lpdwType,
2410 LPBYTE lpbData,
2411 LPDWORD lpcbData
2413 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2414 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2416 return RegEnumValue32A(
2417 hkey,
2418 iValue,
2419 lpszValue,
2420 lpcchValue,
2421 lpdReserved,
2422 lpdwType,
2423 lpbData,
2424 lpcbData
2429 * Close registry key
2431 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2432 DWORD RegCloseKey(HKEY hkey) {
2433 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2434 remove_handle(hkey);
2435 return ERROR_SUCCESS;
2438 * Delete registry key
2440 * Callpath:
2441 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2443 /* RegDeleteKeyW [ADVAPI32.134] */
2444 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2445 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2446 LPWSTR *wps;
2447 int wpc,i;
2449 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2450 hkey,W2C(lpszSubKey,0)
2452 lpNextKey = lookup_hkey(hkey);
2453 if (!lpNextKey)
2454 return SHELL_ERROR_BADKEY;
2455 /* we need to know the previous key in the hier. */
2456 if (!lpszSubKey || !*lpszSubKey)
2457 return SHELL_ERROR_BADKEY;
2458 split_keypath(lpszSubKey,&wps,&wpc);
2459 i = 0;
2460 lpxkey = lpNextKey;
2461 while (i<wpc-1) {
2462 lpxkey=lpNextKey->nextsub;
2463 while (lpxkey) {
2464 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2465 break;
2466 lpxkey=lpxkey->next;
2468 if (!lpxkey) {
2469 FREE_KEY_PATH;
2470 /* not found is success */
2471 return SHELL_ERROR_SUCCESS;
2473 i++;
2474 lpNextKey = lpxkey;
2476 lpxkey = lpNextKey->nextsub;
2477 lplpPrevKey = &(lpNextKey->nextsub);
2478 while (lpxkey) {
2479 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2480 break;
2481 lplpPrevKey = &(lpxkey->next);
2482 lpxkey = lpxkey->next;
2484 if (!lpxkey)
2485 return SHELL_ERROR_SUCCESS;
2486 if (lpxkey->nextsub)
2487 return SHELL_ERROR_CANTWRITE;
2488 *lplpPrevKey = lpxkey->next;
2489 free(lpxkey->keyname);
2490 if (lpxkey->class)
2491 free(lpxkey->class);
2492 if (lpxkey->values)
2493 free(lpxkey->values);
2494 free(lpxkey);
2495 FREE_KEY_PATH;
2496 return SHELL_ERROR_SUCCESS;
2499 /* RegDeleteKeyA [ADVAPI32.133] */
2500 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2501 LPWSTR lpszSubKeyW;
2502 DWORD ret;
2504 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2505 hkey,lpszSubKey
2507 lpszSubKeyW=strdupA2W(lpszSubKey);
2508 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2509 free(lpszSubKeyW);
2510 return ret;
2513 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2514 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2515 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2516 hkey,lpszSubKey
2518 return RegDeleteKey32A(hkey,lpszSubKey);
2522 * Delete registry value
2524 * Callpath:
2525 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2527 /* RegDeleteValueW [ADVAPI32.136] */
2528 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2529 DWORD i;
2530 LPKEYSTRUCT lpkey;
2531 LPKEYVALUE val;
2533 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2534 hkey,W2C(lpszValue,0)
2536 lpkey=lookup_hkey(hkey);
2537 if (!lpkey)
2538 return SHELL_ERROR_BADKEY;
2539 if (lpszValue) {
2540 for (i=0;i<lpkey->nrofvalues;i++)
2541 if ( lpkey->values[i].name &&
2542 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2544 break;
2545 } else {
2546 for (i=0;i<lpkey->nrofvalues;i++)
2547 if (lpkey->values[i].name==NULL)
2548 break;
2550 if (i==lpkey->nrofvalues)
2551 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2552 val = lpkey->values+i;
2553 if (val->name) free(val->name);
2554 if (val->data) free(val->data);
2555 memcpy(
2556 lpkey->values+i,
2557 lpkey->values+i+1,
2558 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2560 lpkey->values = (LPKEYVALUE)xrealloc(
2561 lpkey->values,
2562 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2564 lpkey->nrofvalues--;
2565 return SHELL_ERROR_SUCCESS;
2568 /* RegDeleteValueA [ADVAPI32.135] */
2569 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2570 LPWSTR lpszValueW;
2571 DWORD ret;
2573 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2574 if (lpszValue)
2575 lpszValueW=strdupA2W(lpszValue);
2576 else
2577 lpszValueW=NULL;
2578 ret=RegDeleteValue32W(hkey,lpszValueW);
2579 if (lpszValueW)
2580 free(lpszValueW);
2581 return ret;
2584 /* RegDeleteValue [KERNEL.222] */
2585 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2586 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2587 return RegDeleteValue32A(hkey,lpszValue);
2590 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2591 DWORD RegFlushKey(HKEY hkey) {
2592 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2593 return SHELL_ERROR_SUCCESS;
2596 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2598 /* RegQueryInfoKeyW [ADVAPI32.153] */
2599 DWORD RegQueryInfoKey32W(
2600 HKEY hkey,
2601 LPWSTR lpszClass,
2602 LPDWORD lpcchClass,
2603 LPDWORD lpdwReserved,
2604 LPDWORD lpcSubKeys,
2605 LPDWORD lpcchMaxSubkey,
2606 LPDWORD lpcchMaxClass,
2607 LPDWORD lpcValues,
2608 LPDWORD lpcchMaxValueName,
2609 LPDWORD lpccbMaxValueData,
2610 LPDWORD lpcbSecurityDescriptor,
2611 FILETIME *ft
2613 LPKEYSTRUCT lpkey,lpxkey;
2614 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2615 int i;
2617 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2618 lpkey=lookup_hkey(hkey);
2619 if (!lpkey)
2620 return SHELL_ERROR_BADKEY;
2621 if (lpszClass) {
2622 if (lpkey->class) {
2623 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2624 *lpcchClass=lstrlen32W(lpkey->class)*2;
2625 return ERROR_MORE_DATA;
2627 *lpcchClass=lstrlen32W(lpkey->class)*2;
2628 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2629 } else {
2630 *lpszClass = 0;
2631 *lpcchClass = 0;
2633 } else {
2634 if (lpcchClass)
2635 *lpcchClass = lstrlen32W(lpkey->class)*2;
2637 lpxkey=lpkey->nextsub;
2638 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2639 while (lpxkey) {
2640 nrofkeys++;
2641 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2642 maxsubkey=lstrlen32W(lpxkey->keyname);
2643 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2644 maxclass=lstrlen32W(lpxkey->class);
2645 if (lpxkey->nrofvalues>maxvalues)
2646 maxvalues=lpxkey->nrofvalues;
2647 for (i=0;i<lpxkey->nrofvalues;i++) {
2648 LPKEYVALUE val=lpxkey->values+i;
2650 if (val->name && lstrlen32W(val->name)>maxvname)
2651 maxvname=lstrlen32W(val->name);
2652 if (val->len>maxvdata)
2653 maxvdata=val->len;
2655 lpxkey=lpxkey->next;
2657 if (!maxclass) maxclass = 1;
2658 if (!maxvname) maxvname = 1;
2659 if (lpcSubKeys)
2660 *lpcSubKeys = nrofkeys;
2661 if (lpcchMaxSubkey)
2662 *lpcchMaxSubkey = maxsubkey*2;
2663 if (lpcchMaxClass)
2664 *lpcchMaxClass = maxclass*2;
2665 if (lpcValues)
2666 *lpcValues = maxvalues;
2667 if (lpcchMaxValueName)
2668 *lpcchMaxValueName= maxvname;
2669 if (lpccbMaxValueData)
2670 *lpccbMaxValueData= maxvdata;
2671 return SHELL_ERROR_SUCCESS;
2674 /* RegQueryInfoKeyA [ADVAPI32.152] */
2675 DWORD RegQueryInfoKey32A(
2676 HKEY hkey,
2677 LPSTR lpszClass,
2678 LPDWORD lpcchClass,
2679 LPDWORD lpdwReserved,
2680 LPDWORD lpcSubKeys,
2681 LPDWORD lpcchMaxSubkey,
2682 LPDWORD lpcchMaxClass,
2683 LPDWORD lpcValues,
2684 LPDWORD lpcchMaxValueName,
2685 LPDWORD lpccbMaxValueData,
2686 LPDWORD lpcbSecurityDescriptor,
2687 FILETIME *ft
2689 LPWSTR lpszClassW;
2690 DWORD ret;
2692 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2693 if (lpszClass) {
2694 *lpcchClass*= 2;
2695 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2697 } else
2698 lpszClassW = NULL;
2699 ret=RegQueryInfoKey32W(
2700 hkey,
2701 lpszClassW,
2702 lpcchClass,
2703 lpdwReserved,
2704 lpcSubKeys,
2705 lpcchMaxSubkey,
2706 lpcchMaxClass,
2707 lpcValues,
2708 lpcchMaxValueName,
2709 lpccbMaxValueData,
2710 lpcbSecurityDescriptor,
2713 if (ret==ERROR_SUCCESS)
2714 strcpyWA(lpszClass,lpszClassW);
2715 if (lpcchClass)
2716 *lpcchClass/=2;
2717 if (lpcchMaxSubkey)
2718 *lpcchMaxSubkey/=2;
2719 if (lpcchMaxClass)
2720 *lpcchMaxClass/=2;
2721 if (lpcchMaxValueName)
2722 *lpcchMaxValueName/=2;
2723 if (lpszClassW)
2724 free(lpszClassW);
2725 return ret;