Release 961208
[wine.git] / misc / registry.c
blob90c001a44798f10c7485391b919fc8fb470fee36
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 "dos_fs.h"
24 #include "string32.h"
25 #include "stddebug.h"
26 #include "debug.h"
27 #include "xmalloc.h"
28 #include "winreg.h"
30 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
32 /* FIXME: following defines should be configured global ... */
34 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
35 #define WINE_PREFIX "/.wine"
36 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
37 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
39 /* relative in ~user/.wine/ : */
40 #define SAVE_CURRENT_USER "user.reg"
41 #define SAVE_LOCAL_MACHINE "system.reg"
43 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
44 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
46 /* one value of a key */
47 typedef struct tagKEYVALUE
49 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
50 DWORD type; /* type of value */
51 DWORD len; /* length of data */
52 DWORD lastmodified; /* time of seconds since 1.1.1970 */
53 LPBYTE data; /* content, may be strings, binaries, etc. */
54 } KEYVALUE,*LPKEYVALUE;
56 /* a registry key */
57 typedef struct tagKEYSTRUCT
59 LPWSTR keyname; /* name of THIS key (UNICODE) */
60 DWORD flags; /* flags. */
61 LPWSTR class;
62 /* values */
63 DWORD nrofvalues; /* nr of values in THIS key */
64 LPKEYVALUE values; /* values in THIS key */
65 /* key management pointers */
66 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
67 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
68 } KEYSTRUCT, *LPKEYSTRUCT;
71 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
72 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
73 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
74 static KEYSTRUCT *key_users=NULL; /* all users? */
76 /* dynamic, not saved */
77 static KEYSTRUCT *key_performance_data=NULL;
78 static KEYSTRUCT *key_current_config=NULL;
79 static KEYSTRUCT *key_dyn_data=NULL;
81 /* what valuetypes do we need to convert? */
82 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
84 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
85 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
86 #define strdupW(x) STRING32_strdupW(x)
87 #define strcmpniW(a,b) STRING32_lstrcmpniW(a,b)
88 #define strchrW(a,c) STRING32_lstrchrW(a,c)
89 #define strcpyWA(a,b) STRING32_UniToAnsi(a,b)
91 static struct openhandle {
92 LPKEYSTRUCT lpkey;
93 HKEY hkey;
94 REGSAM accessmask;
95 } *openhandles=NULL;
96 static int nrofopenhandles=0;
97 static int currenthandle=1;
99 static void
100 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
101 int i;
103 for (i=0;i<nrofopenhandles;i++) {
104 if (openhandles[i].lpkey==lpkey) {
105 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
107 if (openhandles[i].hkey==hkey) {
108 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
111 openhandles=xrealloc( openhandles,
112 sizeof(struct openhandle)*(nrofopenhandles+1)
114 openhandles[i].lpkey = lpkey;
115 openhandles[i].hkey = hkey;
116 openhandles[i].accessmask= accessmask;
117 nrofopenhandles++;
120 static LPKEYSTRUCT
121 get_handle(HKEY hkey) {
122 int i;
124 for (i=0;i<nrofopenhandles;i++)
125 if (openhandles[i].hkey==hkey)
126 return openhandles[i].lpkey;
127 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
128 return NULL;
131 static void
132 remove_handle(HKEY hkey) {
133 int i;
135 for (i=0;i<nrofopenhandles;i++)
136 if (openhandles[i].hkey==hkey)
137 break;
138 if (i==nrofopenhandles) {
139 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
140 return;
142 memcpy( openhandles+i,
143 openhandles+i+1,
144 sizeof(struct openhandle)*(nrofopenhandles-i-1)
146 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
147 nrofopenhandles--;
148 return;
152 /* debug function, converts a unicode into a static memory area
153 * (sub for using two static strings, in case we need them in a single call)
155 LPSTR
156 W2C(LPCWSTR x,int sub) {
157 static LPSTR unicodedebug[2]={NULL,NULL};
158 if (x==NULL)
159 return "<NULL>";
160 if (sub!=0 && sub!=1)
161 return "<W2C:bad sub>";
162 if (unicodedebug[sub]) free(unicodedebug[sub]);
163 unicodedebug[sub] = strdupW2A(x);
164 return unicodedebug[sub];
167 static LPKEYSTRUCT
168 lookup_hkey(HKEY hkey) {
169 switch (hkey) {
170 case 0x00000000:
171 case 0x00000001:
172 case HKEY_CLASSES_ROOT:
173 return key_classes_root;
174 case HKEY_CURRENT_USER:
175 return key_current_user;
176 case HKEY_LOCAL_MACHINE:
177 return key_local_machine;
178 case HKEY_USERS:
179 return key_users;
180 case HKEY_PERFORMANCE_DATA:
181 return key_performance_data;
182 case HKEY_DYN_DATA:
183 return key_dyn_data;
184 case HKEY_CURRENT_CONFIG:
185 return key_current_config;
186 default:
187 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
188 (LONG)hkey
190 return get_handle(hkey);
192 /*NOTREACHED*/
196 * splits the unicode string 'wp' into an array of strings.
197 * the array is allocated by this function.
198 * the number of components will be stored in 'wpc'
199 * Free the array using FREE_KEY_PATH
201 static void
202 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
203 int i,j,len;
204 LPWSTR ws;
206 ws = strdupW(wp);
207 *wpc = 1;
208 for (i=0;ws[i];i++) {
209 if (ws[i]=='\\') {
210 ws[i]=0;
211 (*wpc)++;
214 len = i;
215 *wpv = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2));
216 (*wpv)[0]= ws;
217 j = 1;
218 for (i=1;i<len;i++)
219 if (ws[i-1]==0)
220 (*wpv)[j++]=ws+i;
221 (*wpv)[j]=NULL;
223 #define FREE_KEY_PATH free(wps[0]);free(wps);
226 * Shell initialisation, allocates keys.
228 void SHELL_StartupRegistry();
229 void
230 SHELL_Init() {
231 struct passwd *pwd;
233 HKEY cl_r_hkey,c_u_hkey;
234 #define ADD_ROOT_KEY(xx) \
235 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
236 memset(xx,'\0',sizeof(KEYSTRUCT));\
237 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
239 ADD_ROOT_KEY(key_local_machine);
240 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
241 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
242 exit(1);
244 key_classes_root = lookup_hkey(cl_r_hkey);
246 ADD_ROOT_KEY(key_users);
248 #if 0
249 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
250 * (later, when a win32 registry editing tool becomes avail.)
252 while (pwd=getpwent()) {
253 if (pwd->pw_name == NULL)
254 continue;
255 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
256 RegCloseKey(c_u_hkey);
258 #endif
259 pwd=getpwuid(getuid());
260 if (pwd && pwd->pw_name) {
261 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
262 key_current_user = lookup_hkey(c_u_hkey);
263 } else {
264 ADD_ROOT_KEY(key_current_user);
266 ADD_ROOT_KEY(key_performance_data);
267 ADD_ROOT_KEY(key_current_config);
268 ADD_ROOT_KEY(key_dyn_data);
269 #undef ADD_ROOT_KEY
270 SHELL_StartupRegistry();
274 void
275 SHELL_StartupRegistry() {
276 HKEY hkey,xhkey=0;
277 FILE *F;
278 char buf[200],cpubuf[200];
280 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
281 RegCloseKey(xhkey);
282 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
283 #ifdef linux
284 F=fopen("/proc/cpuinfo","r");
285 if (F) {
286 int procnr=-1,x;
287 while (NULL!=fgets(buf,200,F)) {
288 if (sscanf(buf,"processor\t: %d",&x)) {
289 sprintf(buf,"%d",x);
290 if (xhkey)
291 RegCloseKey(xhkey);
292 procnr=x;
293 RegCreateKey16(hkey,buf,&xhkey);
295 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
296 sprintf(buf,"CPU %s",cpubuf);
297 if (xhkey)
298 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
301 fclose(F);
303 if (xhkey)
304 RegCloseKey(xhkey);
305 RegCloseKey(hkey);
306 #else
307 /* FIXME */
308 RegCreateKey16(hkey,"0",&xhkey);
309 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
310 #endif
311 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
312 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
313 RegCloseKey(hkey);
314 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
315 * CurrentVersion
316 * CurrentBuildNumber
317 * CurrentType
318 * string RegisteredOwner
319 * string RegisteredOrganization
322 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
323 * string SysContact
324 * string SysLocation
325 * SysServices
327 if (-1!=gethostname(buf,200)) {
328 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
329 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
330 RegCloseKey(xhkey);
333 /************************ SAVE Registry Function ****************************/
335 #define REGISTRY_SAVE_VERSION 0x00000001
337 /* Registry saveformat:
338 * If you change it, increase above number by 1, which will flush
339 * old registry database files.
341 * Global:
342 * "WINE REGISTRY Version %d"
343 * subkeys....
344 * Subkeys:
345 * keyname
346 * valuename=lastmodified,type,data
347 * ...
348 * subkeys
349 * ...
350 * keyname,valuename,stringdata:
351 * the usual ascii characters from 0x00-0xff (well, not 0x00)
352 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
353 * ( "=\\\t" escaped in \uXXXX form.)
354 * type,lastmodified:
355 * int
357 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
359 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
360 * SaveOnlyUpdatedKeys=yes
362 static int
363 _save_check_tainted(LPKEYSTRUCT lpkey) {
364 int tainted;
366 if (!lpkey)
367 return 0;
368 if (lpkey->flags & REG_OPTION_TAINTED)
369 tainted = 1;
370 else
371 tainted = 0;
372 while (lpkey) {
373 if (_save_check_tainted(lpkey->nextsub)) {
374 lpkey->flags |= REG_OPTION_TAINTED;
375 tainted = 1;
377 lpkey = lpkey->next;
379 return tainted;
382 static void
383 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
384 LPWSTR s;
385 int doescape;
387 if (wstr==NULL)
388 return;
389 s=wstr;
390 while (*s) {
391 doescape=0;
392 if (*s>0xff)
393 doescape = 1;
394 if (*s=='\n')
395 doescape = 1;
396 if (escapeeq && *s=='=')
397 doescape = 1;
398 if (*s=='\\')
399 fputc(*s,F); /* if \\ than put it twice. */
400 if (doescape)
401 fprintf(F,"\\u%04x",*((unsigned short*)s));
402 else
403 fputc(*s,F);
404 s++;
408 static int
409 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
410 LPKEYSTRUCT lpxkey;
411 int i,tabs,j;
413 lpxkey = lpkey;
414 while (lpxkey) {
415 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
416 (all || (lpxkey->flags & REG_OPTION_TAINTED))
418 for (tabs=level;tabs--;)
419 fputc('\t',F);
420 _save_USTRING(F,lpxkey->keyname,1);
421 fputs("\n",F);
422 for (i=0;i<lpxkey->nrofvalues;i++) {
423 LPKEYVALUE val=lpxkey->values+i;
425 for (tabs=level+1;tabs--;)
426 fputc('\t',F);
427 _save_USTRING(F,val->name,0);
428 fputc('=',F);
429 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
430 if ((1<<val->type) & UNICONVMASK)
431 _save_USTRING(F,(LPWSTR)val->data,0);
432 else
433 for (j=0;j<val->len;j++)
434 fprintf(F,"%02x",*((unsigned char*)val->data+j));
435 fputs("\n",F);
437 /* descend recursively */
438 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
439 return 0;
441 lpxkey=lpxkey->next;
443 return 1;
446 static int
447 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
448 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
449 _save_check_tainted(lpkey->nextsub);
450 return _savesubkey(F,lpkey->nextsub,0,all);
453 static BOOL32
454 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
455 FILE *F;
457 F=fopen(fn,"w");
458 if (F==NULL) {
459 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
460 fn,strerror(errno)
462 return FALSE;
464 if (!_savesubreg(F,lpkey,all)) {
465 fclose(F);
466 unlink(fn);
467 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
468 return FALSE;
470 fclose(F);
471 return TRUE;
474 void
475 SHELL_SaveRegistry() {
476 char *fn;
477 struct passwd *pwd;
478 char buf[4];
479 HKEY hkey;
480 int all;
482 all=0;
483 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
484 strcpy(buf,"yes");
485 } else {
486 DWORD len,junk,type;
488 len=4;
489 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
490 hkey,
491 VAL_SAVEUPDATED,
492 &junk,
493 &type,
494 buf,
495 &len
496 ))|| (type!=REG_SZ)
498 strcpy(buf,"yes");
499 RegCloseKey(hkey);
501 if (lstrcmpi32A(buf,"yes"))
502 all=1;
503 pwd=getpwuid(getuid());
504 if (pwd!=NULL && pwd->pw_dir!=NULL)
506 char *tmp = tmpnam(NULL);
507 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
508 strlen(SAVE_CURRENT_USER) + 2 );
509 strcpy(fn,pwd->pw_dir);
510 strcat(fn,WINE_PREFIX);
511 /* create the directory. don't care about errorcodes. */
512 mkdir(fn,0755); /* drwxr-xr-x */
513 strcat(fn,"/"SAVE_CURRENT_USER);
514 if (_savereg(key_current_user,tmp,all)) rename(tmp,fn);
515 free(fn);
516 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
517 strcpy(fn,pwd->pw_dir);
518 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
519 if (_savereg(key_local_machine,tmp,all)) rename(tmp,fn);
520 free(fn);
521 } else
522 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
525 /************************ LOAD Registry Function ****************************/
527 static LPKEYSTRUCT
528 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
529 LPKEYSTRUCT lpxkey,*lplpkey;
531 lplpkey= &(lpkey->nextsub);
532 lpxkey = *lplpkey;
533 while (lpxkey) {
534 if (!lstrcmp32W(lpxkey->keyname,keyname))
535 break;
536 lplpkey = &(lpxkey->next);
537 lpxkey = *lplpkey;
539 if (lpxkey==NULL) {
540 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
541 lpxkey = *lplpkey;
542 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
543 lpxkey->keyname = keyname;
544 } else
545 free(keyname);
546 return lpxkey;
549 static void
550 _find_or_add_value(
551 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
552 DWORD lastmodified
554 LPKEYVALUE val=NULL;
555 int i;
557 for (i=0;i<lpkey->nrofvalues;i++) {
558 val=lpkey->values+i;
559 if (name==NULL) {
560 if (val->name==NULL)
561 break;
562 } else {
563 if ( val->name!=NULL &&
564 !lstrcmp32W(val->name,name)
566 break;
569 if (i==lpkey->nrofvalues) {
570 lpkey->values = xrealloc(
571 lpkey->values,
572 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
574 val=lpkey->values+i;
575 memset(val,'\0',sizeof(KEYVALUE));
576 val->name = name;
577 } else {
578 if (name)
579 free(name);
581 if (val->lastmodified<lastmodified) {
582 val->lastmodified=lastmodified;
583 val->type = type;
584 val->len = len;
585 if (val->data)
586 free(val->data);
587 val->data = data;
588 } else
589 free(data);
593 /* reads a line including dynamically enlarging the readbuffer and throwing
594 * away comments
596 static int
597 _wine_read_line(FILE *F,char **buf,int *len) {
598 char *s,*curread;
599 int mylen,curoff;
601 curread = *buf;
602 mylen = *len;
603 **buf = '\0';
604 while (1) {
605 while (1) {
606 s=fgets(curread,mylen,F);
607 if (s==NULL)
608 return 0; /* EOF */
609 if (NULL==(s=strchr(curread,'\n'))) {
610 /* buffer wasn't large enough */
611 curoff = strlen(*buf);
612 *buf = xrealloc(*buf,*len*2);
613 curread = *buf + curoff;
614 mylen = *len; /* we filled up the buffer and
615 * got new '*len' bytes to fill
617 *len = *len * 2;
618 } else {
619 *s='\0';
620 break;
623 /* throw away comments */
624 if (**buf=='#' || **buf==';') {
625 curread = *buf;
626 mylen = *len;
627 continue;
629 if (s) /* got end of line */
630 break;
632 return 1;
635 /* converts a char* into a UNICODE string (up to a special char)
636 * and returns the position exactly after that string
638 static char*
639 _wine_read_USTRING(char *buf,LPWSTR *str) {
640 char *s;
641 LPWSTR ws;
643 /* read up to "=" or "\0" or "\n" */
644 s = buf;
645 if (*s == '=') {
646 /* empty string is the win3.1 default value(NULL)*/
647 *str = NULL;
648 return s;
650 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
651 ws = *str;
652 while (*s && (*s!='\n') && (*s!='=')) {
653 if (*s!='\\')
654 *ws++=*((unsigned char*)s++);
655 else {
656 s++;
657 if (*s=='\\') {
658 *ws+='\\';
659 s++;
660 continue;
662 if (*s!='u') {
663 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
664 *ws++='\\';
665 *ws++=*s++;
666 } else {
667 char xbuf[5];
668 int wc;
670 s++;
671 memcpy(xbuf,s,4);xbuf[4]='\0';
672 if (!sscanf(xbuf,"%x",&wc))
673 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
674 s+=4;
675 *ws++ =(unsigned short)wc;
679 *ws = 0;
680 ws = *str;
681 *str = strdupW(*str);
682 free(ws);
683 return s;
686 static int
687 _wine_loadsubkey(
688 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
690 LPKEYSTRUCT lpxkey;
691 int i;
692 char *s;
693 LPWSTR name;
695 lpkey->flags |= optflag;
697 /* good. we already got a line here ... so parse it */
698 lpxkey = NULL;
699 while (1) {
700 i=0;s=*buf;
701 while (*s=='\t') {
702 s++;
703 i++;
705 if (i>level) {
706 if (lpxkey==NULL) {
707 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
708 return 0;
710 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
711 continue;
713 /* let the caller handle this line */
714 if (i<level || **buf=='\0')
715 return 1;
717 /* it can be: a value or a keyname. Parse the name first */
718 s=_wine_read_USTRING(s,&name);
720 /* switch() default: hack to avoid gotos */
721 switch (0) {
722 default:
723 if (*s=='\0') {
724 lpxkey=_find_or_add_key(lpkey,name);
725 } else {
726 LPBYTE data;
727 int len,lastmodified,type;
729 if (*s!='=') {
730 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
731 break;
733 s++;
734 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
735 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
736 break;
738 /* skip the 2 , */
739 s=strchr(s,',');s++;
740 s=strchr(s,',');s++;
741 if ((1<<type) & UNICONVMASK) {
742 s=_wine_read_USTRING(s,(LPWSTR*)&data);
743 if (data)
744 len = lstrlen32W((LPWSTR)data)*2+2;
745 else
746 len = 0;
747 } else {
748 len=strlen(s)/2;
749 data = (LPBYTE)xmalloc(len+1);
750 for (i=0;i<len;i++) {
751 data[i]=0;
752 if (*s>='0' && *s<='9')
753 data[i]=(*s-'0')<<4;
754 if (*s>='a' && *s<='f')
755 data[i]=(*s-'a')<<4;
756 if (*s>='A' && *s<='F')
757 data[i]=(*s-'A')<<4;
758 s++;
759 if (*s>='0' && *s<='9')
760 data[i]|=*s-'0';
761 if (*s>='a' && *s<='f')
762 data[i]|=*s-'a';
763 if (*s>='A' && *s<='F')
764 data[i]|=*s-'A';
765 s++;
768 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
771 /* read the next line */
772 if (!_wine_read_line(F,buf,buflen))
773 return 1;
775 return 1;
778 static int
779 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
780 int ver;
781 char *buf;
782 int buflen;
784 buf=xmalloc(10);buflen=10;
785 if (!_wine_read_line(F,&buf,&buflen)) {
786 free(buf);
787 return 0;
789 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
790 free(buf);
791 return 0;
793 if (ver!=REGISTRY_SAVE_VERSION) {
794 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
795 free(buf);
796 return 0;
798 if (!_wine_read_line(F,&buf,&buflen)) {
799 free(buf);
800 return 0;
802 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
803 free(buf);
804 return 0;
806 free(buf);
807 return 1;
810 static void
811 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
812 FILE *F;
814 F=fopen(fn,"rb");
815 if (F==NULL) {
816 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
817 fn,strerror(errno)
819 return;
821 if (!_wine_loadsubreg(F,lpkey,optflag)) {
822 fclose(F);
823 unlink(fn);
824 return;
826 fclose(F);
829 static void
830 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
831 LPKEYSTRUCT lpxkey;
832 int j;
833 LPKEYVALUE valfrom;
835 from=from->nextsub;
836 while (from) {
837 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
839 for (j=0;j<from->nrofvalues;j++) {
840 LPWSTR name;
841 LPBYTE data;
843 valfrom = from->values+j;
844 name=valfrom->name;
845 if (name) name=strdupW(name);
846 data=(LPBYTE)malloc(valfrom->len);
847 memcpy(data,valfrom->data,valfrom->len);
849 _find_or_add_value(
850 lpxkey,
851 name,
852 valfrom->type,
853 data,
854 valfrom->len,
855 valfrom->lastmodified
858 _copy_registry(from,lpxkey);
859 from = from->next;
863 /* WINDOWS 95 REGISTRY LOADER */
865 * Structure of a win95 registry database.
866 * main header:
867 * 0 : "CREG" - magic
868 * 4 : DWORD version
869 * 8 : DWORD offset_of_RGDB_part
870 * 0C..1F: ? (someone fill in please)
872 * 20: RGKN_section:
873 * header:
874 * 0 : "RGKN" - magic
875 * 4..0x1B: ? (fill in)
876 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
878 * Disk Key Entry Structure:
879 * 00: DWORD - unknown
880 * 04: DWORD - unknown
881 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
882 * 0C: DWORD - disk address of PreviousLevel Key.
883 * 10: DWORD - disk address of Next Sublevel Key.
884 * 14: DWORD - disk address of Next Key (on same level).
885 * DKEP>18: WORD - Nr, Low Significant part.
886 * 1A: WORD - Nr, High Significant part.
888 * The disk address always points to the nr part of the previous key entry
889 * of the referenced key. Don't ask me why, or even if I got this correct
890 * from staring at 1kg of hexdumps. (DKEP)
892 * The number of the entry is the low byte of the Low Significant Part ored
893 * with 0x100 * (low byte of the High Significant part)
894 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
896 * There are two minor corrections to the position of that structure.
897 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
898 * the DKE reread from there.
899 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
900 * (FIXME: slightly better explanation needed here)
902 * RGDB_section:
903 * 00: "RGDB" - magic
904 * 04: DWORD offset to next RGDB section (perhaps WORD)
905 * 08...1F: ?
906 * 20.....: disk keys
908 * disk key:
909 * 00: DWORD nextkeyoffset - offset to the next disk key structure
910 * 08: WORD nrLS - low significant part of NR
911 * 0A: WORD nrHS - high significant part of NR
912 * 0C: DWORD bytesused - bytes used in this structure.
913 * 10: WORD name_len - length of name in bytes. without \0
914 * 12: WORD nr_of_values - number of values.
915 * 14: char name[name_len] - name string. No \0.
916 * 14+name_len: disk values
917 * nextkeyoffset: ... next disk key
919 * disk value:
920 * 00: DWORD type - value type (hmm, could be WORD too)
921 * 04: DWORD - unknown, usually 0
922 * 08: WORD namelen - length of Name. 0 means name=NULL
923 * 0C: WORD datalen - length of Data.
924 * 10: char name[namelen] - name, no \0
925 * 10+namelen: BYTE data[datalen] - data, without \0 if string
926 * 10+namelen+datalen: next values or disk key
928 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
929 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
930 * structure) and reading another RGDB_section.
931 * repeat until end of file.
933 * FIXME: this description needs some serious help, yes.
936 struct _w95keyvalue {
937 unsigned long type;
938 unsigned short datalen;
939 char *name;
940 unsigned char *data;
941 unsigned long x1;
942 int lastmodified;
945 struct _w95key {
946 char *name;
947 int nrofvals;
948 struct _w95keyvalue *values;
949 unsigned long dkeaddr;
950 unsigned long x1;
951 unsigned long x2;
952 unsigned long x3;
953 unsigned long xx1;
954 struct _w95key *prevlvl;
955 struct _w95key *nextsub;
956 struct _w95key *next;
959 /* fast lookup table dkeaddr->nr */
960 struct _w95nr2da {
961 unsigned long dkeaddr;
962 unsigned long nr;
966 static void
967 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
968 int i;
969 LPKEYSTRUCT lpxkey;
970 LPWSTR name;
972 while (key) {
973 if (key->name == NULL) {
974 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
975 key->dkeaddr
977 return;
979 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
981 if (key->nrofvals<0) {
982 /* shouldn't happen */
983 fprintf(stderr,"key %s already processed!\n",key->name);
984 key = key->next;
985 continue;
987 for (i=0;i<key->nrofvals;i++) {
988 LPBYTE data;
989 int len;
991 name = strdupA2W(key->values[i].name);
992 if (!*name) name = NULL;
993 free(key->values[i].name);
995 len = key->values[i].datalen;
996 data = key->values[i].data;
997 if ((1<<key->values[i].type) & UNICONVMASK) {
998 data = (BYTE*)strdupA2W(data);
999 len = lstrlen32W((LPWSTR)data)*2+2;
1000 free(key->values[i].data);
1002 _find_or_add_value(
1003 lpxkey,
1004 name,
1005 key->values[i].type,
1006 data,
1007 len,
1008 key->values[i].lastmodified
1011 if (key->values) {
1012 free(key->values);
1013 key->values = NULL;
1015 key->nrofvals=-key->nrofvals-1;
1016 _w95_walk_tree(lpxkey,key->nextsub);
1017 key=key->next;
1021 /* small helper function to adjust address offset (dkeaddrs) */
1022 static unsigned long
1023 _w95_adj_da(unsigned long dkeaddr) {
1024 if ((dkeaddr&0xFFF)<0x018) {
1025 int diff;
1027 diff=0x1C-(dkeaddr&0xFFF);
1028 return dkeaddr+diff;
1030 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1031 /* readjust to 0x000,
1032 * but ONLY if we are >0x1000 already
1034 if (dkeaddr & ~0xFFF)
1035 return dkeaddr & ~0xFFF;
1037 return dkeaddr;
1040 static int
1041 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1043 static struct _w95key*
1044 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1045 int i,off;
1047 if (dkeaddr == 0xFFFFFFFF)
1048 return NULL;
1049 if (dkeaddr<0x20)
1050 return NULL;
1051 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1052 off = (dkeaddr-0x3c)/0x1c;
1053 for (i=0;i<n;i++)
1054 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1055 return keys+nr2da[(i+off)%n].nr;
1056 /* 0x3C happens often, just report unusual values */
1057 if (dkeaddr!=0x3c)
1058 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1059 return NULL;
1062 static void
1063 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1064 /* Disk Key Entry structure (RGKN part) */
1065 struct dke {
1066 unsigned long x1;
1067 unsigned long x2;
1068 unsigned long x3;/*usually 0xFFFFFFFF */
1069 unsigned long prevlvl;
1070 unsigned long nextsub;
1071 unsigned long next;
1072 unsigned short nrLS;
1073 unsigned short nrMS;
1075 /* Disk Key Header structure (RGDB part) */
1076 struct dkh {
1077 unsigned long nextkeyoff;
1078 unsigned short nrLS;
1079 unsigned short nrMS;
1080 unsigned long bytesused;
1081 unsigned short keynamelen;
1082 unsigned short values;
1083 unsigned long xx1;
1084 /* keyname */
1085 /* disk key values or nothing */
1087 /* Disk Key Value structure */
1088 struct dkv {
1089 unsigned long type;
1090 unsigned long x1;
1091 unsigned short valnamelen;
1092 unsigned short valdatalen;
1093 /* valname, valdata */
1095 struct _w95nr2da *nr2da;
1097 HFILE hfd;
1098 int lastmodified;
1099 char magic[5];
1100 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1101 struct _w95key *keys;
1102 int nrofdkes;
1103 unsigned char *data,*curdata,*nextrgdb;
1104 OFSTRUCT ofs;
1105 BY_HANDLE_FILE_INFORMATION hfdinfo;
1107 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1108 hfd=OpenFile(fn,&ofs,OF_READ);
1109 if (hfd==HFILE_ERROR)
1110 return;
1111 magic[4]=0;
1112 if (4!=_lread32(hfd,magic,4))
1113 return;
1114 if (strcmp(magic,"CREG")) {
1115 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1116 return;
1118 if (4!=_lread32(hfd,&version,4))
1119 return;
1120 if (4!=_lread32(hfd,&rgdbsection,4))
1121 return;
1122 if (-1==_llseek(hfd,0x20,SEEK_SET))
1123 return;
1124 if (4!=_lread32(hfd,magic,4))
1125 return;
1126 if (strcmp(magic,"RGKN")) {
1127 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1128 return;
1131 /* STEP 1: Keylink structures */
1132 if (-1==_llseek(hfd,0x40,SEEK_SET))
1133 return;
1134 where = 0x40;
1135 end = rgdbsection;
1137 nrofdkes = (end-where)/sizeof(struct dke)+100;
1138 data = (char*)xmalloc(end-where);
1139 if ((end-where)!=_lread32(hfd,data,end-where))
1140 return;
1141 curdata = data;
1143 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1144 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1145 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1146 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1148 for (i=0;i<nrofdkes;i++) {
1149 struct dke dke;
1150 unsigned long dkeaddr;
1152 pos=curdata-data+0x40;
1153 memcpy(&dke,curdata,sizeof(dke));
1154 curdata+=sizeof(dke);
1155 nr = dke.nrLS + (dke.nrMS<<8);
1156 dkeaddr=pos-4;
1157 if ((dkeaddr&0xFFF)<0x018) {
1158 int diff;
1160 diff=0x1C-(dkeaddr&0xFFF);
1161 dkeaddr+=diff;
1162 curdata+=diff-sizeof(dke);
1163 memcpy(&dke,curdata,sizeof(dke));
1164 nr = dke.nrLS + (dke.nrMS<<8);
1165 curdata+=sizeof(dke);
1167 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1168 /* readjust to 0x000,
1169 * but ONLY if we are >0x1000 already
1171 if (dkeaddr & ~0xFFF)
1172 dkeaddr = dkeaddr & ~0xFFF;
1174 if (nr>nrofdkes) {
1175 /* 0xFFFFFFFF happens often, just report unusual values */
1176 if (nr!=0xFFFFFFFF)
1177 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1178 continue;
1180 if (keys[nr].dkeaddr) {
1181 int x;
1183 for (x=sizeof(dke);x--;)
1184 if (((char*)&dke)[x])
1185 break;
1186 if (x==-1)
1187 break; /* finished reading if we got only 0 */
1188 if (nr) {
1189 if ( (dke.next!=(long)keys[nr].next) ||
1190 (dke.nextsub!=(long)keys[nr].nextsub) ||
1191 (dke.prevlvl!=(long)keys[nr].prevlvl)
1193 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1195 continue;
1197 nr2da[i].nr = nr;
1198 nr2da[i].dkeaddr = dkeaddr;
1200 keys[nr].dkeaddr = dkeaddr;
1201 keys[nr].x1 = dke.x1;
1202 keys[nr].x2 = dke.x2;
1203 keys[nr].x3 = dke.x3;
1204 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1205 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1206 keys[nr].next = (struct _w95key*)dke.next;
1208 free(data);
1210 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1211 (int(*)(const void *,const void*))_w95dkecomp);
1213 /* STEP 2: keydata & values */
1214 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1215 return;
1216 end = hfdinfo.nFileSizeLow;
1217 lastmodified = DOSFS_FileTimeToUnixTime(&(hfdinfo.ftLastWriteTime));
1219 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1220 return;
1221 data = (char*)xmalloc(end-rgdbsection);
1222 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1223 return;
1224 _lclose(hfd);
1225 curdata = data;
1226 memcpy(magic,curdata,4);
1227 memcpy(&off_next_rgdb,curdata+4,4);
1228 nextrgdb = curdata+off_next_rgdb;
1229 if (strcmp(magic,"RGDB")) {
1230 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1231 return;
1233 curdata=data+0x20;
1234 while (1) {
1235 struct dkh dkh;
1236 int bytesread;
1237 struct _w95key *key,xkey;
1239 bytesread = 0;
1240 if (curdata>=nextrgdb) {
1241 curdata = nextrgdb;
1242 if (!strncmp(curdata,"RGDB",4)) {
1243 memcpy(&off_next_rgdb,curdata+4,4);
1244 nextrgdb = curdata+off_next_rgdb;
1245 curdata+=0x20;
1246 } else {
1247 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1248 break;
1251 #define XREAD(whereto,len) \
1252 if ((curdata-data+len)<end) {\
1253 memcpy(whereto,curdata,len);\
1254 curdata+=len;\
1255 bytesread+=len;\
1258 XREAD(&dkh,sizeof(dkh));
1259 nr = dkh.nrLS + (dkh.nrMS<<8);
1260 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1261 if (dkh.nrLS == 0xFFFF) {
1262 /* skip over key using nextkeyoff */
1263 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1264 continue;
1266 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1267 key = &xkey;
1268 memset(key,'\0',sizeof(xkey));
1269 } else {
1270 key = keys+nr;
1271 if (!key->dkeaddr)
1272 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1274 key->nrofvals = dkh.values;
1275 key->name = (char*)xmalloc(dkh.keynamelen+1);
1276 key->xx1 = dkh.xx1;
1277 XREAD(key->name,dkh.keynamelen);
1278 key->name[dkh.keynamelen]=0;
1279 if (key->nrofvals) {
1280 key->values = (struct _w95keyvalue*)xmalloc(
1281 sizeof(struct _w95keyvalue)*key->nrofvals
1283 for (i=0;i<key->nrofvals;i++) {
1284 struct dkv dkv;
1286 XREAD(&dkv,sizeof(dkv));
1287 key->values[i].type = dkv.type;
1288 key->values[i].name = (char*)xmalloc(
1289 dkv.valnamelen+1
1291 key->values[i].datalen = dkv.valdatalen;
1292 key->values[i].data = (unsigned char*)xmalloc(
1293 dkv.valdatalen+1
1295 key->values[i].x1 = dkv.x1;
1296 XREAD(key->values[i].name,dkv.valnamelen);
1297 XREAD(key->values[i].data,dkv.valdatalen);
1298 key->values[i].data[dkv.valdatalen]=0;
1299 key->values[i].name[dkv.valnamelen]=0;
1300 key->values[i].lastmodified=lastmodified;
1303 if (bytesread != dkh.nextkeyoff) {
1304 if (dkh.bytesused != bytesread)
1305 dprintf_reg(stddeb,
1306 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1307 dkh.bytesused
1309 curdata += dkh.nextkeyoff-bytesread;
1311 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1312 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1313 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1314 if (!bytesread)
1315 break;
1317 free(data);
1318 _w95_walk_tree(lpkey,keys);
1319 free(keys);
1322 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1325 reghack - windows 3.11 registry data format demo program.
1327 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1328 a combined hash table and tree description, and finally a text table.
1330 The header is obvious from the struct header. The taboff1 and taboff2
1331 fields are always 0x20, and their usage is unknown.
1333 The 8-byte entry table has various entry types.
1335 tabent[0] is a root index. The second word has the index of the root of
1336 the directory.
1337 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1338 the index of the key/value that has that hash. Data with the same
1339 hash value are on a circular list. The other three words in the
1340 hash entry are always zero.
1341 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1342 entry: dirent and keyent/valent. They are identified by context.
1343 tabent[freeidx] is the first free entry. The first word in a free entry
1344 is the index of the next free entry. The last has 0 as a link.
1345 The other three words in the free list are probably irrelevant.
1347 Entries in text table are preceeded by a word at offset-2. This word
1348 has the value (2*index)+1, where index is the referring keyent/valent
1349 entry in the table. I have no suggestion for the 2* and the +1.
1350 Following the word, there are N bytes of data, as per the keyent/valent
1351 entry length. The offset of the keyent/valent entry is from the start
1352 of the text table to the first data byte.
1354 This information is not available from Microsoft. The data format is
1355 deduced from the reg.dat file by me. Mistakes may
1356 have been made. I claim no rights and give no guarantees for this program.
1358 Tor Sjøwall, tor@sn.no
1361 /* reg.dat header format */
1362 struct _w31_header {
1363 char cookie[8]; /* 'SHCC3.10' */
1364 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1365 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1366 unsigned long tabcnt; /* number of entries in index table */
1367 unsigned long textoff; /* offset of text part */
1368 unsigned long textsize; /* byte size of text part */
1369 unsigned short hashsize; /* hash size */
1370 unsigned short freeidx; /* free index */
1373 /* generic format of table entries */
1374 struct _w31_tabent {
1375 unsigned short w0, w1, w2, w3;
1378 /* directory tabent: */
1379 struct _w31_dirent {
1380 unsigned short sibling_idx; /* table index of sibling dirent */
1381 unsigned short child_idx; /* table index of child dirent */
1382 unsigned short key_idx; /* table index of key keyent */
1383 unsigned short value_idx; /* table index of value valent */
1386 /* key tabent: */
1387 struct _w31_keyent {
1388 unsigned short hash_idx; /* hash chain index for string */
1389 unsigned short refcnt; /* reference count */
1390 unsigned short length; /* length of string */
1391 unsigned short string_off; /* offset of string in text table */
1394 /* value tabent: */
1395 struct _w31_valent {
1396 unsigned short hash_idx; /* hash chain index for string */
1397 unsigned short refcnt; /* reference count */
1398 unsigned short length; /* length of string */
1399 unsigned short string_off; /* offset of string in text table */
1402 /* recursive helper function to display a directory tree */
1403 void
1404 __w31_dumptree( unsigned short idx,
1405 unsigned char *txt,
1406 struct _w31_tabent *tab,
1407 struct _w31_header *head,
1408 LPKEYSTRUCT lpkey,
1409 time_t lastmodified,
1410 int level
1412 struct _w31_dirent *dir;
1413 struct _w31_keyent *key;
1414 struct _w31_valent *val;
1415 LPKEYSTRUCT xlpkey;
1416 LPWSTR name,value;
1417 static char tail[400];
1419 while (idx!=0) {
1420 dir=(struct _w31_dirent*)&tab[idx];
1422 if (dir->key_idx) {
1423 key = (struct _w31_keyent*)&tab[dir->key_idx];
1425 memcpy(tail,&txt[key->string_off],key->length);
1426 tail[key->length]='\0';
1427 /* all toplevel entries AND the entries in the
1428 * toplevel subdirectory belong to \SOFTWARE\Classes
1430 if (!level && !lstrcmp32A(tail,".classes")) {
1431 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1432 idx=dir->sibling_idx;
1433 continue;
1435 name=STRING32_DupAnsiToUni(tail);
1437 xlpkey=_find_or_add_key(lpkey,name);
1439 /* only add if leaf node or valued node */
1440 if (dir->value_idx!=0||dir->child_idx==0) {
1441 if (dir->value_idx) {
1442 val=(struct _w31_valent*)&tab[dir->value_idx];
1443 memcpy(tail,&txt[val->string_off],val->length);
1444 tail[val->length]='\0';
1445 value=STRING32_DupAnsiToUni(tail);
1446 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1449 } else {
1450 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1452 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1453 idx=dir->sibling_idx;
1457 void
1458 _w31_loadreg() {
1459 HFILE hf;
1460 struct _w31_header head;
1461 struct _w31_tabent *tab;
1462 unsigned char *txt;
1463 int len;
1464 OFSTRUCT ofs;
1465 BY_HANDLE_FILE_INFORMATION hfinfo;
1466 time_t lastmodified;
1467 HKEY hkey;
1468 LPKEYSTRUCT lpkey;
1470 hf = OpenFile("reg.dat",&ofs,OF_READ);
1471 if (hf==HFILE_ERROR)
1472 return;
1474 /* read & dump header */
1475 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1476 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1477 _lclose(hf);
1478 return;
1480 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1481 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1482 _lclose(hf);
1483 return;
1486 len = head.tabcnt * sizeof(struct _w31_tabent);
1487 /* read and dump index table */
1488 tab = xmalloc(len);
1489 if (len!=_lread32(hf,tab,len)) {
1490 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1491 free(tab);
1492 _lclose(hf);
1493 return;
1496 /* read text */
1497 txt = xmalloc(head.textsize);
1498 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1499 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1500 free(tab);
1501 free(txt);
1502 _lclose(hf);
1503 return;
1505 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1506 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1507 free(tab);
1508 free(txt);
1509 _lclose(hf);
1510 return;
1513 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1514 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1515 free(tab);
1516 free(txt);
1517 _lclose(hf);
1518 return;
1520 lastmodified = DOSFS_FileTimeToUnixTime(&(hfinfo.ftLastWriteTime));
1522 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1523 return;
1524 lpkey = lookup_hkey(hkey);
1525 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1526 free(tab);
1527 free(txt);
1528 _lclose(hf);
1529 return;
1532 void
1533 SHELL_LoadRegistry() {
1534 char *fn;
1535 struct passwd *pwd;
1536 LPKEYSTRUCT lpkey;
1537 HKEY hkey;
1540 if (key_classes_root==NULL)
1541 SHELL_Init();
1543 /* Load windows 3.1 entries */
1544 _w31_loadreg();
1545 /* Load windows 95 entries */
1546 _w95_loadreg("C:\\system.1st", key_local_machine);
1547 _w95_loadreg("system.dat", key_local_machine);
1548 _w95_loadreg("user.dat", key_users);
1550 /* the global user default is loaded under HKEY_USERS\\.Default */
1551 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1552 lpkey = lookup_hkey(hkey);
1553 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1555 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1556 _copy_registry(lpkey,key_current_user);
1557 RegCloseKey(hkey);
1559 /* the global machine defaults */
1560 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1562 /* load the user saved registries */
1564 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1566 pwd=getpwuid(getuid());
1567 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1568 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1569 strcpy(fn,pwd->pw_dir);
1570 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1571 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1572 free(fn);
1573 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1574 strcpy(fn,pwd->pw_dir);
1575 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1576 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1577 free(fn);
1578 } else
1579 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1580 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1581 DWORD junk,type,len;
1582 char data[5];
1584 len=4;
1585 if (( RegQueryValueEx32A(
1586 hkey,
1587 VAL_SAVEUPDATED,
1588 &junk,
1589 &type,
1590 data,
1591 &len
1592 )!=ERROR_SUCCESS) ||
1593 type != REG_SZ
1595 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1596 RegCloseKey(hkey);
1601 /********************* API FUNCTIONS ***************************************/
1603 * Open Keys.
1605 * All functions are stubs to RegOpenKeyEx32W where all the
1606 * magic happens.
1608 * FIXME: security,options,desiredaccess,...
1610 * Callpath:
1611 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1612 * RegOpenKey32W -> RegOpenKeyEx32W
1615 /* RegOpenKeyExW [ADVAPI32.150] */
1616 DWORD RegOpenKeyEx32W(
1617 HKEY hkey,
1618 LPCWSTR lpszSubKey,
1619 DWORD dwReserved,
1620 REGSAM samDesired,
1621 LPHKEY retkey
1623 LPKEYSTRUCT lpNextKey,lpxkey;
1624 LPWSTR *wps;
1625 int wpc,i;
1626 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1627 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1630 lpNextKey = lookup_hkey(hkey);
1631 if (!lpNextKey)
1632 return SHELL_ERROR_BADKEY;
1633 if (!lpszSubKey || !*lpszSubKey) {
1634 add_handle(++currenthandle,lpNextKey,samDesired);
1635 *retkey=currenthandle;
1636 return SHELL_ERROR_SUCCESS;
1638 split_keypath(lpszSubKey,&wps,&wpc);
1639 i = 0;
1640 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1641 lpxkey = lpNextKey;
1642 while (i<wpc) {
1643 lpxkey=lpNextKey->nextsub;
1644 while (lpxkey) {
1645 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1646 break;
1647 lpxkey=lpxkey->next;
1649 if (!lpxkey) {
1650 FREE_KEY_PATH;
1651 return SHELL_ERROR_BADKEY;
1653 i++;
1654 lpNextKey = lpxkey;
1656 add_handle(++currenthandle,lpxkey,samDesired);
1657 *retkey = currenthandle;
1658 FREE_KEY_PATH;
1659 return SHELL_ERROR_SUCCESS;
1662 /* RegOpenKeyW [ADVAPI32.151] */
1663 DWORD RegOpenKey32W(
1664 HKEY hkey,
1665 LPCWSTR lpszSubKey,
1666 LPHKEY retkey
1668 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1669 (LONG)hkey,W2C(lpszSubKey,0),retkey
1671 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1675 /* RegOpenKeyExA [ADVAPI32.149] */
1676 DWORD RegOpenKeyEx32A(
1677 HKEY hkey,
1678 LPCSTR lpszSubKey,
1679 DWORD dwReserved,
1680 REGSAM samDesired,
1681 LPHKEY retkey
1683 LPWSTR lpszSubKeyW;
1684 DWORD ret;
1686 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1687 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1689 if (lpszSubKey)
1690 lpszSubKeyW=strdupA2W(lpszSubKey);
1691 else
1692 lpszSubKeyW=NULL;
1693 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1694 if (lpszSubKeyW)
1695 free(lpszSubKeyW);
1696 return ret;
1699 /* RegOpenKeyA [ADVAPI32.148] */
1700 DWORD RegOpenKey32A(
1701 HKEY hkey,
1702 LPCSTR lpszSubKey,
1703 LPHKEY retkey
1705 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1706 (LONG)hkey,lpszSubKey,retkey
1708 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1711 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1712 DWORD RegOpenKey16(
1713 HKEY hkey,
1714 LPCSTR lpszSubKey,
1715 LPHKEY retkey
1717 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1718 (LONG)hkey,lpszSubKey,retkey
1720 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1724 * Create keys
1726 * All those functions convert their respective
1727 * arguments and call RegCreateKeyExW at the end.
1729 * FIXME: no security,no access attrib,no optionhandling yet.
1731 * Callpath:
1732 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1733 * RegCreateKey32W -> RegCreateKeyEx32W
1736 /* RegCreateKeyExW [ADVAPI32.131] */
1737 DWORD RegCreateKeyEx32W(
1738 HKEY hkey,
1739 LPCWSTR lpszSubKey,
1740 DWORD dwReserved,
1741 LPWSTR lpszClass,
1742 DWORD fdwOptions,
1743 REGSAM samDesired,
1744 LPSECURITY_ATTRIBUTES lpSecAttribs,
1745 LPHKEY retkey,
1746 LPDWORD lpDispos
1748 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1749 LPWSTR *wps;
1750 int wpc,i;
1752 /*FIXME: handle security/access/whatever */
1753 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1754 (LONG)hkey,
1755 W2C(lpszSubKey,0),
1756 dwReserved,
1757 W2C(lpszClass,1),
1758 fdwOptions,
1759 samDesired,
1760 lpSecAttribs,
1761 retkey,
1762 lpDispos
1765 lpNextKey = lookup_hkey(hkey);
1766 if (!lpNextKey)
1767 return SHELL_ERROR_BADKEY;
1768 if (!lpszSubKey || !*lpszSubKey) {
1769 add_handle(++currenthandle,lpNextKey,samDesired);
1770 *retkey=currenthandle;
1771 lpNextKey->flags|=REG_OPTION_TAINTED;
1772 return SHELL_ERROR_SUCCESS;
1774 split_keypath(lpszSubKey,&wps,&wpc);
1775 i = 0;
1776 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1777 lpxkey = lpNextKey;
1778 while (wps[i]) {
1779 lpxkey=lpNextKey->nextsub;
1780 while (lpxkey) {
1781 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1782 break;
1783 lpxkey=lpxkey->next;
1785 if (!lpxkey)
1786 break;
1787 i++;
1788 lpNextKey = lpxkey;
1790 if (lpxkey) {
1791 add_handle(++currenthandle,lpxkey,samDesired);
1792 lpxkey->flags |= REG_OPTION_TAINTED;
1793 *retkey = currenthandle;
1794 if (lpDispos)
1795 *lpDispos = REG_OPENED_EXISTING_KEY;
1796 FREE_KEY_PATH;
1797 return SHELL_ERROR_SUCCESS;
1799 /* good. now the hard part */
1800 while (wps[i]) {
1801 lplpPrevKey = &(lpNextKey->nextsub);
1802 lpxkey = *lplpPrevKey;
1803 while (lpxkey) {
1804 lplpPrevKey = &(lpxkey->next);
1805 lpxkey = *lplpPrevKey;
1807 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1808 if (!*lplpPrevKey) {
1809 FREE_KEY_PATH;
1810 return SHELL_ERROR_OUTOFMEMORY;
1812 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1813 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1814 (*lplpPrevKey)->next = NULL;
1815 (*lplpPrevKey)->nextsub = NULL;
1816 (*lplpPrevKey)->values = NULL;
1817 (*lplpPrevKey)->nrofvalues = 0;
1818 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1819 if (lpszClass)
1820 (*lplpPrevKey)->class = strdupW(lpszClass);
1821 else
1822 (*lplpPrevKey)->class = NULL;
1823 lpNextKey = *lplpPrevKey;
1824 i++;
1826 add_handle(++currenthandle,lpNextKey,samDesired);
1828 /*FIXME: flag handling correct? */
1829 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1830 if (lpszClass)
1831 lpNextKey->class = strdupW(lpszClass);
1832 else
1833 lpNextKey->class = NULL;
1834 *retkey = currenthandle;
1835 if (lpDispos)
1836 *lpDispos = REG_CREATED_NEW_KEY;
1837 FREE_KEY_PATH;
1838 return SHELL_ERROR_SUCCESS;
1841 /* RegCreateKeyW [ADVAPI32.132] */
1842 DWORD RegCreateKey32W(
1843 HKEY hkey,
1844 LPCWSTR lpszSubKey,
1845 LPHKEY retkey
1847 DWORD junk,ret;
1849 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1850 (LONG)hkey,W2C(lpszSubKey,0),retkey
1852 ret=RegCreateKeyEx32W(
1853 hkey, /* key handle */
1854 lpszSubKey, /* subkey name */
1855 0, /* reserved = 0 */
1856 NULL, /* lpszClass? FIXME: ? */
1857 REG_OPTION_NON_VOLATILE, /* options */
1858 KEY_ALL_ACCESS, /* desired access attribs */
1859 NULL, /* lpsecurity attributes */
1860 retkey, /* lpretkey */
1861 &junk /* disposition value */
1863 return ret;
1866 /* RegCreateKeyExA [ADVAPI32.130] */
1867 DWORD RegCreateKeyEx32A(
1868 HKEY hkey,
1869 LPCSTR lpszSubKey,
1870 DWORD dwReserved,
1871 LPSTR lpszClass,
1872 DWORD fdwOptions,
1873 REGSAM samDesired,
1874 LPSECURITY_ATTRIBUTES lpSecAttribs,
1875 LPHKEY retkey,
1876 LPDWORD lpDispos
1878 LPWSTR lpszSubKeyW,lpszClassW;
1879 DWORD ret;
1881 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1882 (LONG)hkey,
1883 lpszSubKey,
1884 dwReserved,
1885 lpszClass,
1886 fdwOptions,
1887 samDesired,
1888 lpSecAttribs,
1889 retkey,
1890 lpDispos
1892 if (lpszSubKey)
1893 lpszSubKeyW=strdupA2W(lpszSubKey);
1894 else
1895 lpszSubKeyW=NULL;
1896 if (lpszClass)
1897 lpszClassW=strdupA2W(lpszClass);
1898 else
1899 lpszClassW=NULL;
1900 ret=RegCreateKeyEx32W(
1901 hkey,
1902 lpszSubKeyW,
1903 dwReserved,
1904 lpszClassW,
1905 fdwOptions,
1906 samDesired,
1907 lpSecAttribs,
1908 retkey,
1909 lpDispos
1911 if (lpszSubKeyW)
1912 free(lpszSubKeyW);
1913 if (lpszClassW)
1914 free(lpszClassW);
1915 return ret;
1918 /* RegCreateKeyA [ADVAPI32.129] */
1919 DWORD RegCreateKey32A(
1920 HKEY hkey,
1921 LPCSTR lpszSubKey,
1922 LPHKEY retkey
1924 DWORD junk;
1926 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1927 (LONG)hkey,lpszSubKey,retkey
1929 return RegCreateKeyEx32A(
1930 hkey, /* key handle */
1931 lpszSubKey, /* subkey name */
1932 0, /* reserved = 0 */
1933 NULL, /* lpszClass? FIXME: ? */
1934 REG_OPTION_NON_VOLATILE,/* options */
1935 KEY_ALL_ACCESS, /* desired access attribs */
1936 NULL, /* lpsecurity attributes */
1937 retkey, /* lpretkey */
1938 &junk /* disposition value */
1942 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1943 DWORD RegCreateKey16(
1944 HKEY hkey,
1945 LPCSTR lpszSubKey,
1946 LPHKEY retkey
1948 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1949 (LONG)hkey,lpszSubKey,retkey
1951 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1955 * Query Value Functions
1956 * Win32 differs between keynames and valuenames.
1957 * multiple values may belong to one key, the special value
1958 * with name NULL is the default value used by the win31
1959 * compat functions.
1961 * Callpath:
1962 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1963 * RegQueryValue32W -> RegQueryValueEx32W
1966 /* RegQueryValueExW [ADVAPI32.158] */
1967 DWORD RegQueryValueEx32W(
1968 HKEY hkey,
1969 LPWSTR lpszValueName,
1970 LPDWORD lpdwReserved,
1971 LPDWORD lpdwType,
1972 LPBYTE lpbData,
1973 LPDWORD lpcbData
1975 LPKEYSTRUCT lpkey;
1976 int i;
1978 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1979 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1980 lpcbData?*lpcbData:0
1983 lpkey = lookup_hkey(hkey);
1984 if (!lpkey)
1985 return SHELL_ERROR_BADKEY;
1986 if (lpszValueName==NULL) {
1987 for (i=0;i<lpkey->nrofvalues;i++)
1988 if (lpkey->values[i].name==NULL)
1989 break;
1990 } else {
1991 for (i=0;i<lpkey->nrofvalues;i++)
1992 if ( lpkey->values[i].name &&
1993 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1995 break;
1997 if (i==lpkey->nrofvalues) {
1998 if (lpszValueName==NULL) {
1999 if (lpbData) {
2000 *(WCHAR*)lpbData = 0;
2001 *lpcbData = 2;
2003 if (lpdwType)
2004 *lpdwType = REG_SZ;
2005 return SHELL_ERROR_SUCCESS;
2007 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2009 if (lpdwType)
2010 *lpdwType = lpkey->values[i].type;
2011 if (lpbData==NULL) {
2012 if (lpcbData==NULL)
2013 return SHELL_ERROR_SUCCESS;
2014 *lpcbData = lpkey->values[i].len;
2015 return SHELL_ERROR_SUCCESS;
2017 if (*lpcbData<lpkey->values[i].len) {
2018 *(WCHAR*)lpbData
2019 = 0;
2020 *lpcbData = lpkey->values[i].len;
2021 return ERROR_MORE_DATA;
2023 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2024 *lpcbData = lpkey->values[i].len;
2025 return SHELL_ERROR_SUCCESS;
2028 /* RegQueryValueW [ADVAPI32.159] */
2029 DWORD RegQueryValue32W(
2030 HKEY hkey,
2031 LPWSTR lpszSubKey,
2032 LPWSTR lpszData,
2033 LPDWORD lpcbData
2035 HKEY xhkey;
2036 DWORD ret,lpdwType;
2038 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2039 hkey,W2C(lpszSubKey,0),lpszData,
2040 lpcbData?*lpcbData:0
2043 /* only open subkey, if we really do descend */
2044 if (lpszSubKey && *lpszSubKey) {
2045 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2046 if (ret!=ERROR_SUCCESS)
2047 return ret;
2048 } else
2049 xhkey = hkey;
2051 lpdwType = REG_SZ;
2052 ret = RegQueryValueEx32W(
2053 xhkey,
2054 NULL, /* varname NULL -> compat */
2055 NULL, /* lpdwReserved, must be NULL */
2056 &lpdwType,
2057 (LPBYTE)lpszData,
2058 lpcbData
2060 if (xhkey!=hkey)
2061 RegCloseKey(xhkey);
2062 return ret;
2065 /* RegQueryValueExA [ADVAPI32.157] */
2066 DWORD RegQueryValueEx32A(
2067 HKEY hkey,
2068 LPSTR lpszValueName,
2069 LPDWORD lpdwReserved,
2070 LPDWORD lpdwType,
2071 LPBYTE lpbData,
2072 LPDWORD lpcbData
2074 LPWSTR lpszValueNameW;
2075 LPBYTE buf;
2076 DWORD ret,myxlen;
2077 DWORD *mylen;
2078 DWORD type;
2080 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2081 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2082 lpcbData?*lpcbData:0
2084 if (lpbData) {
2085 /* double buffer */
2086 buf = (LPBYTE)xmalloc((*lpcbData)*2);
2087 myxlen = *lpcbData*2;
2088 mylen = &myxlen;
2089 } else {
2090 buf=NULL;
2091 if (lpcbData) {
2092 myxlen = *lpcbData*2;
2093 mylen = &myxlen;
2094 } else
2095 mylen = NULL;
2097 if (lpszValueName)
2098 lpszValueNameW=strdupA2W(lpszValueName);
2099 else
2100 lpszValueNameW=NULL;
2102 if (lpdwType)
2103 type=*lpdwType;
2104 ret=RegQueryValueEx32W(
2105 hkey,
2106 lpszValueNameW,
2107 lpdwReserved,
2108 &type,
2109 buf,
2110 mylen
2112 if (lpdwType)
2113 *lpdwType=type;
2114 if (ret==ERROR_SUCCESS) {
2115 if (buf) {
2116 if (UNICONVMASK & (1<<(type))) {
2117 /* convert UNICODE to ASCII */
2118 strcpyWA(lpbData,(LPWSTR)buf);
2119 *lpcbData = myxlen/2;
2120 } else {
2121 if (myxlen>*lpcbData)
2122 ret = ERROR_MORE_DATA;
2123 else
2124 memcpy(lpbData,buf,myxlen);
2126 *lpcbData = myxlen;
2128 } else {
2129 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2130 *lpcbData = myxlen/2;
2132 } else {
2133 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2134 *lpcbData = myxlen/2;
2136 if (buf)
2137 free(buf);
2138 return ret;
2141 /* RegQueryValueEx [KERNEL.225] */
2142 DWORD RegQueryValueEx16(
2143 HKEY hkey,
2144 LPSTR lpszValueName,
2145 LPDWORD lpdwReserved,
2146 LPDWORD lpdwType,
2147 LPBYTE lpbData,
2148 LPDWORD lpcbData
2150 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2151 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2152 lpcbData?*lpcbData:0
2154 return RegQueryValueEx32A(
2155 hkey,
2156 lpszValueName,
2157 lpdwReserved,
2158 lpdwType,
2159 lpbData,
2160 lpcbData
2164 /* RegQueryValueA [ADVAPI32.156] */
2165 DWORD RegQueryValue32A(
2166 HKEY hkey,
2167 LPSTR lpszSubKey,
2168 LPSTR lpszData,
2169 LPDWORD lpcbData
2171 HKEY xhkey;
2172 DWORD ret,lpdwType;
2174 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2175 hkey,lpszSubKey,lpszData,
2176 lpcbData?*lpcbData:0
2179 /* only open subkey, if we really do descend */
2180 if (lpszSubKey && *lpszSubKey) {
2181 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2182 if (ret!=ERROR_SUCCESS)
2183 return ret;
2184 } else
2185 xhkey = hkey;
2187 lpdwType = REG_SZ;
2188 ret = RegQueryValueEx32A(
2189 xhkey,
2190 NULL, /* lpszValueName NULL -> compat */
2191 NULL, /* lpdwReserved, must be NULL */
2192 &lpdwType,
2193 (LPBYTE)lpszData,
2194 lpcbData
2196 if (xhkey!=hkey)
2197 RegCloseKey(xhkey);
2198 return ret;
2201 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2202 DWORD RegQueryValue16(
2203 HKEY hkey,
2204 LPSTR lpszSubKey,
2205 LPSTR lpszData,
2206 LPDWORD lpcbData
2208 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2209 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2211 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2212 * anyway, so we just mask out the high 16 bit.
2213 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2215 if (lpcbData)
2216 *lpcbData &= 0xFFFF;
2217 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2221 * Setting values of Registry keys
2223 * Callpath:
2224 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2225 * RegSetValue32W -> RegSetValueEx32W
2228 /* RegSetValueExW [ADVAPI32.170] */
2229 DWORD RegSetValueEx32W(
2230 HKEY hkey,
2231 LPWSTR lpszValueName,
2232 DWORD dwReserved,
2233 DWORD dwType,
2234 LPBYTE lpbData,
2235 DWORD cbData
2237 LPKEYSTRUCT lpkey;
2238 int i;
2240 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2241 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2243 /* we no longer care about the lpbData type here... */
2244 lpkey = lookup_hkey(hkey);
2245 if (!lpkey)
2246 return SHELL_ERROR_BADKEY;
2248 lpkey->flags |= REG_OPTION_TAINTED;
2250 if (lpszValueName==NULL) {
2251 for (i=0;i<lpkey->nrofvalues;i++)
2252 if (lpkey->values[i].name==NULL)
2253 break;
2254 } else {
2255 for (i=0;i<lpkey->nrofvalues;i++)
2256 if ( lpkey->values[i].name &&
2257 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2259 break;
2261 if (i==lpkey->nrofvalues) {
2262 lpkey->values = (LPKEYVALUE)xrealloc(
2263 lpkey->values,
2264 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2266 lpkey->nrofvalues++;
2267 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2269 if (lpkey->values[i].name==NULL)
2270 if (lpszValueName)
2271 lpkey->values[i].name = strdupW(lpszValueName);
2272 else
2273 lpkey->values[i].name = NULL;
2274 lpkey->values[i].len = cbData;
2275 lpkey->values[i].type = dwType;
2276 if (lpkey->values[i].data !=NULL)
2277 free(lpkey->values[i].data);
2278 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2279 lpkey->values[i].lastmodified = time(NULL);
2280 memcpy(lpkey->values[i].data,lpbData,cbData);
2281 return SHELL_ERROR_SUCCESS;
2284 /* RegSetValueExA [ADVAPI32.169] */
2285 DWORD RegSetValueEx32A(
2286 HKEY hkey,
2287 LPSTR lpszValueName,
2288 DWORD dwReserved,
2289 DWORD dwType,
2290 LPBYTE lpbData,
2291 DWORD cbData
2293 LPBYTE buf;
2294 LPWSTR lpszValueNameW;
2295 DWORD ret;
2297 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2298 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2300 if ((1<<dwType) & UNICONVMASK) {
2301 buf=(LPBYTE)strdupA2W(lpbData);
2302 cbData=2*strlen(lpbData)+2;
2303 } else
2304 buf=lpbData;
2305 if (lpszValueName)
2306 lpszValueNameW = strdupA2W(lpszValueName);
2307 else
2308 lpszValueNameW = NULL;
2309 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2310 if (lpszValueNameW)
2311 free(lpszValueNameW);
2312 if (buf!=lpbData)
2313 free(buf);
2314 return ret;
2317 /* RegSetValueEx [KERNEL.226] */
2318 DWORD RegSetValueEx16(
2319 HKEY hkey,
2320 LPSTR lpszValueName,
2321 DWORD dwReserved,
2322 DWORD dwType,
2323 LPBYTE lpbData,
2324 DWORD cbData
2326 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2327 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2329 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2332 /* RegSetValueW [ADVAPI32.171] */
2333 DWORD RegSetValue32W(
2334 HKEY hkey,
2335 LPCWSTR lpszSubKey,
2336 DWORD dwType,
2337 LPCWSTR lpszData,
2338 DWORD cbData
2340 HKEY xhkey;
2341 DWORD ret;
2343 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2344 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2346 if (lpszSubKey && *lpszSubKey) {
2347 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2348 if (ret!=ERROR_SUCCESS)
2349 return ret;
2350 } else
2351 xhkey=hkey;
2352 if (dwType!=REG_SZ) {
2353 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2354 dwType=REG_SZ;
2356 if (cbData!=2*lstrlen32W(lpszData)+2) {
2357 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2358 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2360 cbData=2*lstrlen32W(lpszData)+2;
2362 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2363 if (hkey!=xhkey)
2364 RegCloseKey(xhkey);
2365 return ret;
2368 /* RegSetValueA [ADVAPI32.168] */
2369 DWORD RegSetValue32A(
2370 HKEY hkey,
2371 LPCSTR lpszSubKey,
2372 DWORD dwType,
2373 LPCSTR lpszData,
2374 DWORD cbData
2376 DWORD ret;
2377 HKEY xhkey;
2379 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2380 hkey,lpszSubKey,dwType,lpszData,cbData
2382 if (lpszSubKey && *lpszSubKey) {
2383 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2384 if (ret!=ERROR_SUCCESS)
2385 return ret;
2386 } else
2387 xhkey=hkey;
2389 if (dwType!=REG_SZ) {
2390 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2391 dwType=REG_SZ;
2393 if (cbData!=strlen(lpszData)+1)
2394 cbData=strlen(lpszData)+1;
2395 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2396 if (xhkey!=hkey)
2397 RegCloseKey(xhkey);
2398 return ret;
2401 /* RegSetValue [KERNEL.221] [SHELL.5] */
2402 DWORD RegSetValue16(
2403 HKEY hkey,
2404 LPCSTR lpszSubKey,
2405 DWORD dwType,
2406 LPCSTR lpszData,
2407 DWORD cbData
2409 DWORD ret;
2410 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2411 hkey,lpszSubKey,dwType,lpszData,cbData
2413 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2414 return ret;
2418 * Key Enumeration
2420 * Callpath:
2421 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2422 * RegEnumKey32W -> RegEnumKeyEx32W
2425 /* RegEnumKeyExW [ADVAPI32.139] */
2426 DWORD RegEnumKeyEx32W(
2427 HKEY hkey,
2428 DWORD iSubkey,
2429 LPWSTR lpszName,
2430 LPDWORD lpcchName,
2431 LPDWORD lpdwReserved,
2432 LPWSTR lpszClass,
2433 LPDWORD lpcchClass,
2434 FILETIME *ft
2436 LPKEYSTRUCT lpkey,lpxkey;
2438 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2439 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2441 lpkey=lookup_hkey(hkey);
2442 if (!lpkey)
2443 return SHELL_ERROR_BADKEY;
2444 if (!lpkey->nextsub)
2445 return ERROR_NO_MORE_ITEMS;
2446 lpxkey=lpkey->nextsub;
2447 while (iSubkey && lpxkey) {
2448 iSubkey--;
2449 lpxkey=lpxkey->next;
2451 if (iSubkey || !lpxkey)
2452 return ERROR_NO_MORE_ITEMS;
2453 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2454 return ERROR_MORE_DATA;
2455 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2456 if (lpszClass) {
2457 /* what should we write into it? */
2458 *lpszClass = 0;
2459 *lpcchClass = 2;
2461 return ERROR_SUCCESS;
2465 /* RegEnumKeyW [ADVAPI32.140] */
2466 DWORD RegEnumKey32W(
2467 HKEY hkey,
2468 DWORD iSubkey,
2469 LPWSTR lpszName,
2470 DWORD lpcchName
2472 FILETIME ft;
2474 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2475 hkey,iSubkey,lpszName,lpcchName
2477 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2479 /* RegEnumKeyExA [ADVAPI32.138] */
2480 DWORD RegEnumKeyEx32A(
2481 HKEY hkey,
2482 DWORD iSubkey,
2483 LPSTR lpszName,
2484 LPDWORD lpcchName,
2485 LPDWORD lpdwReserved,
2486 LPSTR lpszClass,
2487 LPDWORD lpcchClass,
2488 FILETIME *ft
2490 DWORD ret,lpcchNameW,lpcchClassW;
2491 LPWSTR lpszNameW,lpszClassW;
2494 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2495 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2497 if (lpszName) {
2498 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2499 lpcchNameW = *lpcchName*2;
2500 } else {
2501 lpszNameW = NULL;
2502 lpcchNameW = 0;
2504 if (lpszClass) {
2505 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2506 lpcchClassW = *lpcchClass*2;
2507 } else {
2508 lpszClassW =0;
2509 lpcchClassW=0;
2511 ret=RegEnumKeyEx32W(
2512 hkey,
2513 iSubkey,
2514 lpszNameW,
2515 &lpcchNameW,
2516 lpdwReserved,
2517 lpszClassW,
2518 &lpcchClassW,
2521 if (ret==ERROR_SUCCESS) {
2522 strcpyWA(lpszName,lpszNameW);
2523 *lpcchName=strlen(lpszName);
2524 if (lpszClassW) {
2525 strcpyWA(lpszClass,lpszClassW);
2526 *lpcchClass=strlen(lpszClass);
2529 if (lpszNameW)
2530 free(lpszNameW);
2531 if (lpszClassW)
2532 free(lpszClassW);
2533 return ret;
2536 /* RegEnumKeyA [ADVAPI32.137] */
2537 DWORD RegEnumKey32A(
2538 HKEY hkey,
2539 DWORD iSubkey,
2540 LPSTR lpszName,
2541 DWORD lpcchName
2543 FILETIME ft;
2545 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2546 hkey,iSubkey,lpszName,lpcchName
2548 return RegEnumKeyEx32A(
2549 hkey,
2550 iSubkey,
2551 lpszName,
2552 &lpcchName,
2553 NULL,
2554 NULL,
2555 NULL,
2560 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2561 DWORD RegEnumKey16(
2562 HKEY hkey,
2563 DWORD iSubkey,
2564 LPSTR lpszName,
2565 DWORD lpcchName
2567 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2568 hkey,iSubkey,lpszName,lpcchName
2570 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2574 * Enumerate Registry Values
2576 * Callpath:
2577 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2580 /* RegEnumValueW [ADVAPI32.142] */
2581 DWORD RegEnumValue32W(
2582 HKEY hkey,
2583 DWORD iValue,
2584 LPWSTR lpszValue,
2585 LPDWORD lpcchValue,
2586 LPDWORD lpdReserved,
2587 LPDWORD lpdwType,
2588 LPBYTE lpbData,
2589 LPDWORD lpcbData
2591 LPKEYSTRUCT lpkey;
2592 LPKEYVALUE val;
2594 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2595 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2597 lpkey = lookup_hkey(hkey);
2598 if (!lpkey)
2599 return SHELL_ERROR_BADKEY;
2600 if (lpkey->nrofvalues<=iValue)
2601 return ERROR_NO_MORE_ITEMS;
2602 val = lpkey->values+iValue;
2604 if (val->name) {
2605 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2606 *lpcchValue = lstrlen32W(val->name)*2+2;
2607 return ERROR_MORE_DATA;
2609 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2610 *lpcchValue=lstrlen32W(val->name)*2+2;
2611 } else {
2612 /* how to handle NULL value? */
2613 *lpszValue = 0;
2614 *lpcchValue = 2;
2616 *lpdwType=val->type;
2617 if (lpbData) {
2618 if (val->len>*lpcbData)
2619 return ERROR_MORE_DATA;
2620 memcpy(lpbData,val->data,val->len);
2621 *lpcbData = val->len;
2623 return SHELL_ERROR_SUCCESS;
2626 /* RegEnumValueA [ADVAPI32.141] */
2627 DWORD RegEnumValue32A(
2628 HKEY hkey,
2629 DWORD iValue,
2630 LPSTR lpszValue,
2631 LPDWORD lpcchValue,
2632 LPDWORD lpdReserved,
2633 LPDWORD lpdwType,
2634 LPBYTE lpbData,
2635 LPDWORD lpcbData
2637 LPWSTR lpszValueW;
2638 LPBYTE lpbDataW;
2639 DWORD ret,lpcbDataW;
2641 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2642 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2645 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2646 if (lpbData) {
2647 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2648 lpcbDataW = *lpcbData*2;
2649 } else
2650 lpbDataW = NULL;
2651 ret=RegEnumValue32W(
2652 hkey,
2653 iValue,
2654 lpszValueW,
2655 lpcchValue,
2656 lpdReserved,
2657 lpdwType,
2658 lpbDataW,
2659 &lpcbDataW
2662 if (ret==ERROR_SUCCESS) {
2663 strcpyWA(lpszValue,lpszValueW);
2664 if (lpbData) {
2665 if ((1<<*lpdwType) & UNICONVMASK) {
2666 strcpyWA(lpbData,(LPWSTR)lpbDataW);
2667 } else {
2668 if (lpcbDataW > *lpcbData)
2669 ret = ERROR_MORE_DATA;
2670 else
2671 memcpy(lpbData,lpbDataW,lpcbDataW);
2673 *lpcbData = lpcbDataW;
2676 if (lpbDataW)
2677 free(lpbDataW);
2678 if (lpszValueW)
2679 free(lpszValueW);
2680 return ret;
2683 /* RegEnumValue [KERNEL.223] */
2684 DWORD RegEnumValue16(
2685 HKEY hkey,
2686 DWORD iValue,
2687 LPSTR lpszValue,
2688 LPDWORD lpcchValue,
2689 LPDWORD lpdReserved,
2690 LPDWORD lpdwType,
2691 LPBYTE lpbData,
2692 LPDWORD lpcbData
2694 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2695 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2697 return RegEnumValue32A(
2698 hkey,
2699 iValue,
2700 lpszValue,
2701 lpcchValue,
2702 lpdReserved,
2703 lpdwType,
2704 lpbData,
2705 lpcbData
2710 * Close registry key
2712 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2713 DWORD RegCloseKey(HKEY hkey) {
2714 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2715 remove_handle(hkey);
2716 return ERROR_SUCCESS;
2719 * Delete registry key
2721 * Callpath:
2722 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2724 /* RegDeleteKeyW [ADVAPI32.134] */
2725 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2726 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2727 LPWSTR *wps;
2728 int wpc,i;
2730 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2731 hkey,W2C(lpszSubKey,0)
2733 lpNextKey = lookup_hkey(hkey);
2734 if (!lpNextKey)
2735 return SHELL_ERROR_BADKEY;
2736 /* we need to know the previous key in the hier. */
2737 if (!lpszSubKey || !*lpszSubKey)
2738 return SHELL_ERROR_BADKEY;
2739 split_keypath(lpszSubKey,&wps,&wpc);
2740 i = 0;
2741 lpxkey = lpNextKey;
2742 while (i<wpc-1) {
2743 lpxkey=lpNextKey->nextsub;
2744 while (lpxkey) {
2745 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2746 break;
2747 lpxkey=lpxkey->next;
2749 if (!lpxkey) {
2750 FREE_KEY_PATH;
2751 /* not found is success */
2752 return SHELL_ERROR_SUCCESS;
2754 i++;
2755 lpNextKey = lpxkey;
2757 lpxkey = lpNextKey->nextsub;
2758 lplpPrevKey = &(lpNextKey->nextsub);
2759 while (lpxkey) {
2760 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2761 break;
2762 lplpPrevKey = &(lpxkey->next);
2763 lpxkey = lpxkey->next;
2765 if (!lpxkey)
2766 return SHELL_ERROR_SUCCESS;
2767 if (lpxkey->nextsub)
2768 return SHELL_ERROR_CANTWRITE;
2769 *lplpPrevKey = lpxkey->next;
2770 free(lpxkey->keyname);
2771 if (lpxkey->class)
2772 free(lpxkey->class);
2773 if (lpxkey->values)
2774 free(lpxkey->values);
2775 free(lpxkey);
2776 FREE_KEY_PATH;
2777 return SHELL_ERROR_SUCCESS;
2780 /* RegDeleteKeyA [ADVAPI32.133] */
2781 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2782 LPWSTR lpszSubKeyW;
2783 DWORD ret;
2785 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2786 hkey,lpszSubKey
2788 lpszSubKeyW=strdupA2W(lpszSubKey);
2789 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2790 free(lpszSubKeyW);
2791 return ret;
2794 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2795 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2796 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2797 hkey,lpszSubKey
2799 return RegDeleteKey32A(hkey,lpszSubKey);
2803 * Delete registry value
2805 * Callpath:
2806 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2808 /* RegDeleteValueW [ADVAPI32.136] */
2809 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2810 DWORD i;
2811 LPKEYSTRUCT lpkey;
2812 LPKEYVALUE val;
2814 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2815 hkey,W2C(lpszValue,0)
2817 lpkey=lookup_hkey(hkey);
2818 if (!lpkey)
2819 return SHELL_ERROR_BADKEY;
2820 if (lpszValue) {
2821 for (i=0;i<lpkey->nrofvalues;i++)
2822 if ( lpkey->values[i].name &&
2823 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2825 break;
2826 } else {
2827 for (i=0;i<lpkey->nrofvalues;i++)
2828 if (lpkey->values[i].name==NULL)
2829 break;
2831 if (i==lpkey->nrofvalues)
2832 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2833 val = lpkey->values+i;
2834 if (val->name) free(val->name);
2835 if (val->data) free(val->data);
2836 memcpy(
2837 lpkey->values+i,
2838 lpkey->values+i+1,
2839 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2841 lpkey->values = (LPKEYVALUE)xrealloc(
2842 lpkey->values,
2843 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2845 lpkey->nrofvalues--;
2846 return SHELL_ERROR_SUCCESS;
2849 /* RegDeleteValueA [ADVAPI32.135] */
2850 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2851 LPWSTR lpszValueW;
2852 DWORD ret;
2854 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2855 if (lpszValue)
2856 lpszValueW=strdupA2W(lpszValue);
2857 else
2858 lpszValueW=NULL;
2859 ret=RegDeleteValue32W(hkey,lpszValueW);
2860 if (lpszValueW)
2861 free(lpszValueW);
2862 return ret;
2865 /* RegDeleteValue [KERNEL.222] */
2866 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2867 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2868 return RegDeleteValue32A(hkey,lpszValue);
2871 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2872 DWORD RegFlushKey(HKEY hkey) {
2873 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2874 return SHELL_ERROR_SUCCESS;
2877 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2879 /* RegQueryInfoKeyW [ADVAPI32.153] */
2880 DWORD RegQueryInfoKey32W(
2881 HKEY hkey,
2882 LPWSTR lpszClass,
2883 LPDWORD lpcchClass,
2884 LPDWORD lpdwReserved,
2885 LPDWORD lpcSubKeys,
2886 LPDWORD lpcchMaxSubkey,
2887 LPDWORD lpcchMaxClass,
2888 LPDWORD lpcValues,
2889 LPDWORD lpcchMaxValueName,
2890 LPDWORD lpccbMaxValueData,
2891 LPDWORD lpcbSecurityDescriptor,
2892 FILETIME *ft
2894 LPKEYSTRUCT lpkey,lpxkey;
2895 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2896 int i;
2898 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2899 lpkey=lookup_hkey(hkey);
2900 if (!lpkey)
2901 return SHELL_ERROR_BADKEY;
2902 if (lpszClass) {
2903 if (lpkey->class) {
2904 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2905 *lpcchClass=lstrlen32W(lpkey->class)*2;
2906 return ERROR_MORE_DATA;
2908 *lpcchClass=lstrlen32W(lpkey->class)*2;
2909 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2910 } else {
2911 *lpszClass = 0;
2912 *lpcchClass = 0;
2914 } else {
2915 if (lpcchClass)
2916 *lpcchClass = lstrlen32W(lpkey->class)*2;
2918 lpxkey=lpkey->nextsub;
2919 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2920 while (lpxkey) {
2921 nrofkeys++;
2922 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2923 maxsubkey=lstrlen32W(lpxkey->keyname);
2924 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2925 maxclass=lstrlen32W(lpxkey->class);
2926 if (lpxkey->nrofvalues>maxvalues)
2927 maxvalues=lpxkey->nrofvalues;
2928 for (i=0;i<lpxkey->nrofvalues;i++) {
2929 LPKEYVALUE val=lpxkey->values+i;
2931 if (val->name && lstrlen32W(val->name)>maxvname)
2932 maxvname=lstrlen32W(val->name);
2933 if (val->len>maxvdata)
2934 maxvdata=val->len;
2936 lpxkey=lpxkey->next;
2938 if (!maxclass) maxclass = 1;
2939 if (!maxvname) maxvname = 1;
2940 if (lpcSubKeys)
2941 *lpcSubKeys = nrofkeys;
2942 if (lpcchMaxSubkey)
2943 *lpcchMaxSubkey = maxsubkey*2;
2944 if (lpcchMaxClass)
2945 *lpcchMaxClass = maxclass*2;
2946 if (lpcValues)
2947 *lpcValues = maxvalues;
2948 if (lpcchMaxValueName)
2949 *lpcchMaxValueName= maxvname;
2950 if (lpccbMaxValueData)
2951 *lpccbMaxValueData= maxvdata;
2952 return SHELL_ERROR_SUCCESS;
2955 /* RegQueryInfoKeyA [ADVAPI32.152] */
2956 DWORD RegQueryInfoKey32A(
2957 HKEY hkey,
2958 LPSTR lpszClass,
2959 LPDWORD lpcchClass,
2960 LPDWORD lpdwReserved,
2961 LPDWORD lpcSubKeys,
2962 LPDWORD lpcchMaxSubkey,
2963 LPDWORD lpcchMaxClass,
2964 LPDWORD lpcValues,
2965 LPDWORD lpcchMaxValueName,
2966 LPDWORD lpccbMaxValueData,
2967 LPDWORD lpcbSecurityDescriptor,
2968 FILETIME *ft
2970 LPWSTR lpszClassW;
2971 DWORD ret;
2973 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2974 if (lpszClass) {
2975 *lpcchClass*= 2;
2976 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2978 } else
2979 lpszClassW = NULL;
2980 ret=RegQueryInfoKey32W(
2981 hkey,
2982 lpszClassW,
2983 lpcchClass,
2984 lpdwReserved,
2985 lpcSubKeys,
2986 lpcchMaxSubkey,
2987 lpcchMaxClass,
2988 lpcValues,
2989 lpcchMaxValueName,
2990 lpccbMaxValueData,
2991 lpcbSecurityDescriptor,
2994 if (ret==ERROR_SUCCESS)
2995 strcpyWA(lpszClass,lpszClassW);
2996 if (lpcchClass)
2997 *lpcchClass/=2;
2998 if (lpcchMaxSubkey)
2999 *lpcchMaxSubkey/=2;
3000 if (lpcchMaxClass)
3001 *lpcchMaxClass/=2;
3002 if (lpcchMaxValueName)
3003 *lpcchMaxValueName/=2;
3004 if (lpszClassW)
3005 free(lpszClassW);
3006 return ret;