Release 961215
[wine/multimedia.git] / misc / registry.c
blobe208349e205aea6f8b0d0774db6211393ec9d173
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;
508 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
509 strlen(SAVE_CURRENT_USER) + 2 );
510 strcpy(fn,pwd->pw_dir);
511 strcat(fn,WINE_PREFIX);
512 /* create the directory. don't care about errorcodes. */
513 mkdir(fn,0755); /* drwxr-xr-x */
514 strcat(fn,"/"SAVE_CURRENT_USER);
515 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
516 strcpy(tmp,fn);strcat(tmp,".tmp");
517 if (_savereg(key_current_user,tmp,all)) {
518 if (-1==rename(tmp,fn)) {
519 perror("rename tmp registry");
520 unlink(tmp);
523 free(tmp);
524 free(fn);
525 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
526 strcpy(fn,pwd->pw_dir);
527 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
528 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
529 strcpy(tmp,fn);strcat(tmp,".tmp");
530 if (_savereg(key_local_machine,tmp,all)) {
531 if (-1==rename(tmp,fn)) {
532 perror("rename tmp registry");
533 unlink(tmp);
536 free(tmp);
537 free(fn);
538 } else
539 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
542 /************************ LOAD Registry Function ****************************/
544 static LPKEYSTRUCT
545 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
546 LPKEYSTRUCT lpxkey,*lplpkey;
548 lplpkey= &(lpkey->nextsub);
549 lpxkey = *lplpkey;
550 while (lpxkey) {
551 if (!lstrcmp32W(lpxkey->keyname,keyname))
552 break;
553 lplpkey = &(lpxkey->next);
554 lpxkey = *lplpkey;
556 if (lpxkey==NULL) {
557 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
558 lpxkey = *lplpkey;
559 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
560 lpxkey->keyname = keyname;
561 } else
562 free(keyname);
563 return lpxkey;
566 static void
567 _find_or_add_value(
568 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
569 DWORD lastmodified
571 LPKEYVALUE val=NULL;
572 int i;
574 for (i=0;i<lpkey->nrofvalues;i++) {
575 val=lpkey->values+i;
576 if (name==NULL) {
577 if (val->name==NULL)
578 break;
579 } else {
580 if ( val->name!=NULL &&
581 !lstrcmp32W(val->name,name)
583 break;
586 if (i==lpkey->nrofvalues) {
587 lpkey->values = xrealloc(
588 lpkey->values,
589 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
591 val=lpkey->values+i;
592 memset(val,'\0',sizeof(KEYVALUE));
593 val->name = name;
594 } else {
595 if (name)
596 free(name);
598 if (val->lastmodified<lastmodified) {
599 val->lastmodified=lastmodified;
600 val->type = type;
601 val->len = len;
602 if (val->data)
603 free(val->data);
604 val->data = data;
605 } else
606 free(data);
610 /* reads a line including dynamically enlarging the readbuffer and throwing
611 * away comments
613 static int
614 _wine_read_line(FILE *F,char **buf,int *len) {
615 char *s,*curread;
616 int mylen,curoff;
618 curread = *buf;
619 mylen = *len;
620 **buf = '\0';
621 while (1) {
622 while (1) {
623 s=fgets(curread,mylen,F);
624 if (s==NULL)
625 return 0; /* EOF */
626 if (NULL==(s=strchr(curread,'\n'))) {
627 /* buffer wasn't large enough */
628 curoff = strlen(*buf);
629 *buf = xrealloc(*buf,*len*2);
630 curread = *buf + curoff;
631 mylen = *len; /* we filled up the buffer and
632 * got new '*len' bytes to fill
634 *len = *len * 2;
635 } else {
636 *s='\0';
637 break;
640 /* throw away comments */
641 if (**buf=='#' || **buf==';') {
642 curread = *buf;
643 mylen = *len;
644 continue;
646 if (s) /* got end of line */
647 break;
649 return 1;
652 /* converts a char* into a UNICODE string (up to a special char)
653 * and returns the position exactly after that string
655 static char*
656 _wine_read_USTRING(char *buf,LPWSTR *str) {
657 char *s;
658 LPWSTR ws;
660 /* read up to "=" or "\0" or "\n" */
661 s = buf;
662 if (*s == '=') {
663 /* empty string is the win3.1 default value(NULL)*/
664 *str = NULL;
665 return s;
667 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
668 ws = *str;
669 while (*s && (*s!='\n') && (*s!='=')) {
670 if (*s!='\\')
671 *ws++=*((unsigned char*)s++);
672 else {
673 s++;
674 if (*s=='\\') {
675 *ws+='\\';
676 s++;
677 continue;
679 if (*s!='u') {
680 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
681 *ws++='\\';
682 *ws++=*s++;
683 } else {
684 char xbuf[5];
685 int wc;
687 s++;
688 memcpy(xbuf,s,4);xbuf[4]='\0';
689 if (!sscanf(xbuf,"%x",&wc))
690 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
691 s+=4;
692 *ws++ =(unsigned short)wc;
696 *ws = 0;
697 ws = *str;
698 *str = strdupW(*str);
699 free(ws);
700 return s;
703 static int
704 _wine_loadsubkey(
705 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
707 LPKEYSTRUCT lpxkey;
708 int i;
709 char *s;
710 LPWSTR name;
712 lpkey->flags |= optflag;
714 /* good. we already got a line here ... so parse it */
715 lpxkey = NULL;
716 while (1) {
717 i=0;s=*buf;
718 while (*s=='\t') {
719 s++;
720 i++;
722 if (i>level) {
723 if (lpxkey==NULL) {
724 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
725 return 0;
727 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
728 continue;
730 /* let the caller handle this line */
731 if (i<level || **buf=='\0')
732 return 1;
734 /* it can be: a value or a keyname. Parse the name first */
735 s=_wine_read_USTRING(s,&name);
737 /* switch() default: hack to avoid gotos */
738 switch (0) {
739 default:
740 if (*s=='\0') {
741 lpxkey=_find_or_add_key(lpkey,name);
742 } else {
743 LPBYTE data;
744 int len,lastmodified,type;
746 if (*s!='=') {
747 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
748 break;
750 s++;
751 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
752 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
753 break;
755 /* skip the 2 , */
756 s=strchr(s,',');s++;
757 s=strchr(s,',');s++;
758 if ((1<<type) & UNICONVMASK) {
759 s=_wine_read_USTRING(s,(LPWSTR*)&data);
760 if (data)
761 len = lstrlen32W((LPWSTR)data)*2+2;
762 else
763 len = 0;
764 } else {
765 len=strlen(s)/2;
766 data = (LPBYTE)xmalloc(len+1);
767 for (i=0;i<len;i++) {
768 data[i]=0;
769 if (*s>='0' && *s<='9')
770 data[i]=(*s-'0')<<4;
771 if (*s>='a' && *s<='f')
772 data[i]=(*s-'a')<<4;
773 if (*s>='A' && *s<='F')
774 data[i]=(*s-'A')<<4;
775 s++;
776 if (*s>='0' && *s<='9')
777 data[i]|=*s-'0';
778 if (*s>='a' && *s<='f')
779 data[i]|=*s-'a';
780 if (*s>='A' && *s<='F')
781 data[i]|=*s-'A';
782 s++;
785 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
788 /* read the next line */
789 if (!_wine_read_line(F,buf,buflen))
790 return 1;
792 return 1;
795 static int
796 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
797 int ver;
798 char *buf;
799 int buflen;
801 buf=xmalloc(10);buflen=10;
802 if (!_wine_read_line(F,&buf,&buflen)) {
803 free(buf);
804 return 0;
806 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
807 free(buf);
808 return 0;
810 if (ver!=REGISTRY_SAVE_VERSION) {
811 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
812 free(buf);
813 return 0;
815 if (!_wine_read_line(F,&buf,&buflen)) {
816 free(buf);
817 return 0;
819 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
820 free(buf);
821 return 0;
823 free(buf);
824 return 1;
827 static void
828 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
829 FILE *F;
831 F=fopen(fn,"rb");
832 if (F==NULL) {
833 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
834 fn,strerror(errno)
836 return;
838 if (!_wine_loadsubreg(F,lpkey,optflag)) {
839 fclose(F);
840 unlink(fn);
841 return;
843 fclose(F);
846 static void
847 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
848 LPKEYSTRUCT lpxkey;
849 int j;
850 LPKEYVALUE valfrom;
852 from=from->nextsub;
853 while (from) {
854 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
856 for (j=0;j<from->nrofvalues;j++) {
857 LPWSTR name;
858 LPBYTE data;
860 valfrom = from->values+j;
861 name=valfrom->name;
862 if (name) name=strdupW(name);
863 data=(LPBYTE)malloc(valfrom->len);
864 memcpy(data,valfrom->data,valfrom->len);
866 _find_or_add_value(
867 lpxkey,
868 name,
869 valfrom->type,
870 data,
871 valfrom->len,
872 valfrom->lastmodified
875 _copy_registry(from,lpxkey);
876 from = from->next;
880 /* WINDOWS 95 REGISTRY LOADER */
882 * Structure of a win95 registry database.
883 * main header:
884 * 0 : "CREG" - magic
885 * 4 : DWORD version
886 * 8 : DWORD offset_of_RGDB_part
887 * 0C..1F: ? (someone fill in please)
889 * 20: RGKN_section:
890 * header:
891 * 0 : "RGKN" - magic
892 * 4..0x1B: ? (fill in)
893 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
895 * Disk Key Entry Structure:
896 * 00: DWORD - unknown
897 * 04: DWORD - unknown
898 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
899 * 0C: DWORD - disk address of PreviousLevel Key.
900 * 10: DWORD - disk address of Next Sublevel Key.
901 * 14: DWORD - disk address of Next Key (on same level).
902 * DKEP>18: WORD - Nr, Low Significant part.
903 * 1A: WORD - Nr, High Significant part.
905 * The disk address always points to the nr part of the previous key entry
906 * of the referenced key. Don't ask me why, or even if I got this correct
907 * from staring at 1kg of hexdumps. (DKEP)
909 * The number of the entry is the low byte of the Low Significant Part ored
910 * with 0x100 * (low byte of the High Significant part)
911 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
913 * There are two minor corrections to the position of that structure.
914 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
915 * the DKE reread from there.
916 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
917 * (FIXME: slightly better explanation needed here)
919 * RGDB_section:
920 * 00: "RGDB" - magic
921 * 04: DWORD offset to next RGDB section (perhaps WORD)
922 * 08...1F: ?
923 * 20.....: disk keys
925 * disk key:
926 * 00: DWORD nextkeyoffset - offset to the next disk key structure
927 * 08: WORD nrLS - low significant part of NR
928 * 0A: WORD nrHS - high significant part of NR
929 * 0C: DWORD bytesused - bytes used in this structure.
930 * 10: WORD name_len - length of name in bytes. without \0
931 * 12: WORD nr_of_values - number of values.
932 * 14: char name[name_len] - name string. No \0.
933 * 14+name_len: disk values
934 * nextkeyoffset: ... next disk key
936 * disk value:
937 * 00: DWORD type - value type (hmm, could be WORD too)
938 * 04: DWORD - unknown, usually 0
939 * 08: WORD namelen - length of Name. 0 means name=NULL
940 * 0C: WORD datalen - length of Data.
941 * 10: char name[namelen] - name, no \0
942 * 10+namelen: BYTE data[datalen] - data, without \0 if string
943 * 10+namelen+datalen: next values or disk key
945 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
946 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
947 * structure) and reading another RGDB_section.
948 * repeat until end of file.
950 * FIXME: this description needs some serious help, yes.
953 struct _w95keyvalue {
954 unsigned long type;
955 unsigned short datalen;
956 char *name;
957 unsigned char *data;
958 unsigned long x1;
959 int lastmodified;
962 struct _w95key {
963 char *name;
964 int nrofvals;
965 struct _w95keyvalue *values;
966 unsigned long dkeaddr;
967 unsigned long x1;
968 unsigned long x2;
969 unsigned long x3;
970 unsigned long xx1;
971 struct _w95key *prevlvl;
972 struct _w95key *nextsub;
973 struct _w95key *next;
976 /* fast lookup table dkeaddr->nr */
977 struct _w95nr2da {
978 unsigned long dkeaddr;
979 unsigned long nr;
983 static void
984 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
985 int i;
986 LPKEYSTRUCT lpxkey;
987 LPWSTR name;
989 while (key) {
990 if (key->name == NULL) {
991 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
992 key->dkeaddr
994 return;
996 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
998 if (key->nrofvals<0) {
999 /* shouldn't happen */
1000 fprintf(stderr,"key %s already processed!\n",key->name);
1001 key = key->next;
1002 continue;
1004 for (i=0;i<key->nrofvals;i++) {
1005 LPBYTE data;
1006 int len;
1008 name = strdupA2W(key->values[i].name);
1009 if (!*name) name = NULL;
1010 free(key->values[i].name);
1012 len = key->values[i].datalen;
1013 data = key->values[i].data;
1014 if ((1<<key->values[i].type) & UNICONVMASK) {
1015 data = (BYTE*)strdupA2W(data);
1016 len = lstrlen32W((LPWSTR)data)*2+2;
1017 free(key->values[i].data);
1019 _find_or_add_value(
1020 lpxkey,
1021 name,
1022 key->values[i].type,
1023 data,
1024 len,
1025 key->values[i].lastmodified
1028 if (key->values) {
1029 free(key->values);
1030 key->values = NULL;
1032 key->nrofvals=-key->nrofvals-1;
1033 _w95_walk_tree(lpxkey,key->nextsub);
1034 key=key->next;
1038 /* small helper function to adjust address offset (dkeaddrs) */
1039 static unsigned long
1040 _w95_adj_da(unsigned long dkeaddr) {
1041 if ((dkeaddr&0xFFF)<0x018) {
1042 int diff;
1044 diff=0x1C-(dkeaddr&0xFFF);
1045 return dkeaddr+diff;
1047 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1048 /* readjust to 0x000,
1049 * but ONLY if we are >0x1000 already
1051 if (dkeaddr & ~0xFFF)
1052 return dkeaddr & ~0xFFF;
1054 return dkeaddr;
1057 static int
1058 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1060 static struct _w95key*
1061 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1062 int i,off;
1064 if (dkeaddr == 0xFFFFFFFF)
1065 return NULL;
1066 if (dkeaddr<0x20)
1067 return NULL;
1068 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1069 off = (dkeaddr-0x3c)/0x1c;
1070 for (i=0;i<n;i++)
1071 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1072 return keys+nr2da[(i+off)%n].nr;
1073 /* 0x3C happens often, just report unusual values */
1074 if (dkeaddr!=0x3c)
1075 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1076 return NULL;
1079 static void
1080 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1081 /* Disk Key Entry structure (RGKN part) */
1082 struct dke {
1083 unsigned long x1;
1084 unsigned long x2;
1085 unsigned long x3;/*usually 0xFFFFFFFF */
1086 unsigned long prevlvl;
1087 unsigned long nextsub;
1088 unsigned long next;
1089 unsigned short nrLS;
1090 unsigned short nrMS;
1092 /* Disk Key Header structure (RGDB part) */
1093 struct dkh {
1094 unsigned long nextkeyoff;
1095 unsigned short nrLS;
1096 unsigned short nrMS;
1097 unsigned long bytesused;
1098 unsigned short keynamelen;
1099 unsigned short values;
1100 unsigned long xx1;
1101 /* keyname */
1102 /* disk key values or nothing */
1104 /* Disk Key Value structure */
1105 struct dkv {
1106 unsigned long type;
1107 unsigned long x1;
1108 unsigned short valnamelen;
1109 unsigned short valdatalen;
1110 /* valname, valdata */
1112 struct _w95nr2da *nr2da;
1114 HFILE hfd;
1115 int lastmodified;
1116 char magic[5];
1117 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1118 struct _w95key *keys;
1119 int nrofdkes;
1120 unsigned char *data,*curdata,*nextrgdb;
1121 OFSTRUCT ofs;
1122 BY_HANDLE_FILE_INFORMATION hfdinfo;
1124 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1125 hfd=OpenFile(fn,&ofs,OF_READ);
1126 if (hfd==HFILE_ERROR)
1127 return;
1128 magic[4]=0;
1129 if (4!=_lread32(hfd,magic,4))
1130 return;
1131 if (strcmp(magic,"CREG")) {
1132 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1133 return;
1135 if (4!=_lread32(hfd,&version,4))
1136 return;
1137 if (4!=_lread32(hfd,&rgdbsection,4))
1138 return;
1139 if (-1==_llseek(hfd,0x20,SEEK_SET))
1140 return;
1141 if (4!=_lread32(hfd,magic,4))
1142 return;
1143 if (strcmp(magic,"RGKN")) {
1144 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1145 return;
1148 /* STEP 1: Keylink structures */
1149 if (-1==_llseek(hfd,0x40,SEEK_SET))
1150 return;
1151 where = 0x40;
1152 end = rgdbsection;
1154 nrofdkes = (end-where)/sizeof(struct dke)+100;
1155 data = (char*)xmalloc(end-where);
1156 if ((end-where)!=_lread32(hfd,data,end-where))
1157 return;
1158 curdata = data;
1160 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1161 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1162 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1163 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1165 for (i=0;i<nrofdkes;i++) {
1166 struct dke dke;
1167 unsigned long dkeaddr;
1169 pos=curdata-data+0x40;
1170 memcpy(&dke,curdata,sizeof(dke));
1171 curdata+=sizeof(dke);
1172 nr = dke.nrLS + (dke.nrMS<<8);
1173 dkeaddr=pos-4;
1174 if ((dkeaddr&0xFFF)<0x018) {
1175 int diff;
1177 diff=0x1C-(dkeaddr&0xFFF);
1178 dkeaddr+=diff;
1179 curdata+=diff-sizeof(dke);
1180 memcpy(&dke,curdata,sizeof(dke));
1181 nr = dke.nrLS + (dke.nrMS<<8);
1182 curdata+=sizeof(dke);
1184 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1185 /* readjust to 0x000,
1186 * but ONLY if we are >0x1000 already
1188 if (dkeaddr & ~0xFFF)
1189 dkeaddr = dkeaddr & ~0xFFF;
1191 if (nr>nrofdkes) {
1192 /* 0xFFFFFFFF happens often, just report unusual values */
1193 if (nr!=0xFFFFFFFF)
1194 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1195 continue;
1197 if (keys[nr].dkeaddr) {
1198 int x;
1200 for (x=sizeof(dke);x--;)
1201 if (((char*)&dke)[x])
1202 break;
1203 if (x==-1)
1204 break; /* finished reading if we got only 0 */
1205 if (nr) {
1206 if ( (dke.next!=(long)keys[nr].next) ||
1207 (dke.nextsub!=(long)keys[nr].nextsub) ||
1208 (dke.prevlvl!=(long)keys[nr].prevlvl)
1210 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1212 continue;
1214 nr2da[i].nr = nr;
1215 nr2da[i].dkeaddr = dkeaddr;
1217 keys[nr].dkeaddr = dkeaddr;
1218 keys[nr].x1 = dke.x1;
1219 keys[nr].x2 = dke.x2;
1220 keys[nr].x3 = dke.x3;
1221 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1222 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1223 keys[nr].next = (struct _w95key*)dke.next;
1225 free(data);
1227 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1228 (int(*)(const void *,const void*))_w95dkecomp);
1230 /* STEP 2: keydata & values */
1231 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1232 return;
1233 end = hfdinfo.nFileSizeLow;
1234 lastmodified = DOSFS_FileTimeToUnixTime(&(hfdinfo.ftLastWriteTime));
1236 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1237 return;
1238 data = (char*)xmalloc(end-rgdbsection);
1239 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1240 return;
1241 _lclose(hfd);
1242 curdata = data;
1243 memcpy(magic,curdata,4);
1244 memcpy(&off_next_rgdb,curdata+4,4);
1245 nextrgdb = curdata+off_next_rgdb;
1246 if (strcmp(magic,"RGDB")) {
1247 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1248 return;
1250 curdata=data+0x20;
1251 while (1) {
1252 struct dkh dkh;
1253 int bytesread;
1254 struct _w95key *key,xkey;
1256 bytesread = 0;
1257 if (curdata>=nextrgdb) {
1258 curdata = nextrgdb;
1259 if (!strncmp(curdata,"RGDB",4)) {
1260 memcpy(&off_next_rgdb,curdata+4,4);
1261 nextrgdb = curdata+off_next_rgdb;
1262 curdata+=0x20;
1263 } else {
1264 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1265 break;
1268 #define XREAD(whereto,len) \
1269 if ((curdata-data+len)<end) {\
1270 memcpy(whereto,curdata,len);\
1271 curdata+=len;\
1272 bytesread+=len;\
1275 XREAD(&dkh,sizeof(dkh));
1276 nr = dkh.nrLS + (dkh.nrMS<<8);
1277 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1278 if (dkh.nrLS == 0xFFFF) {
1279 /* skip over key using nextkeyoff */
1280 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1281 continue;
1283 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1284 key = &xkey;
1285 memset(key,'\0',sizeof(xkey));
1286 } else {
1287 key = keys+nr;
1288 if (!key->dkeaddr)
1289 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1291 key->nrofvals = dkh.values;
1292 key->name = (char*)xmalloc(dkh.keynamelen+1);
1293 key->xx1 = dkh.xx1;
1294 XREAD(key->name,dkh.keynamelen);
1295 key->name[dkh.keynamelen]=0;
1296 if (key->nrofvals) {
1297 key->values = (struct _w95keyvalue*)xmalloc(
1298 sizeof(struct _w95keyvalue)*key->nrofvals
1300 for (i=0;i<key->nrofvals;i++) {
1301 struct dkv dkv;
1303 XREAD(&dkv,sizeof(dkv));
1304 key->values[i].type = dkv.type;
1305 key->values[i].name = (char*)xmalloc(
1306 dkv.valnamelen+1
1308 key->values[i].datalen = dkv.valdatalen;
1309 key->values[i].data = (unsigned char*)xmalloc(
1310 dkv.valdatalen+1
1312 key->values[i].x1 = dkv.x1;
1313 XREAD(key->values[i].name,dkv.valnamelen);
1314 XREAD(key->values[i].data,dkv.valdatalen);
1315 key->values[i].data[dkv.valdatalen]=0;
1316 key->values[i].name[dkv.valnamelen]=0;
1317 key->values[i].lastmodified=lastmodified;
1320 if (bytesread != dkh.nextkeyoff) {
1321 if (dkh.bytesused != bytesread)
1322 dprintf_reg(stddeb,
1323 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1324 dkh.bytesused
1326 curdata += dkh.nextkeyoff-bytesread;
1328 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1329 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1330 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1331 if (!bytesread)
1332 break;
1334 free(data);
1335 _w95_walk_tree(lpkey,keys);
1336 free(keys);
1339 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1342 reghack - windows 3.11 registry data format demo program.
1344 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1345 a combined hash table and tree description, and finally a text table.
1347 The header is obvious from the struct header. The taboff1 and taboff2
1348 fields are always 0x20, and their usage is unknown.
1350 The 8-byte entry table has various entry types.
1352 tabent[0] is a root index. The second word has the index of the root of
1353 the directory.
1354 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1355 the index of the key/value that has that hash. Data with the same
1356 hash value are on a circular list. The other three words in the
1357 hash entry are always zero.
1358 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1359 entry: dirent and keyent/valent. They are identified by context.
1360 tabent[freeidx] is the first free entry. The first word in a free entry
1361 is the index of the next free entry. The last has 0 as a link.
1362 The other three words in the free list are probably irrelevant.
1364 Entries in text table are preceeded by a word at offset-2. This word
1365 has the value (2*index)+1, where index is the referring keyent/valent
1366 entry in the table. I have no suggestion for the 2* and the +1.
1367 Following the word, there are N bytes of data, as per the keyent/valent
1368 entry length. The offset of the keyent/valent entry is from the start
1369 of the text table to the first data byte.
1371 This information is not available from Microsoft. The data format is
1372 deduced from the reg.dat file by me. Mistakes may
1373 have been made. I claim no rights and give no guarantees for this program.
1375 Tor Sjøwall, tor@sn.no
1378 /* reg.dat header format */
1379 struct _w31_header {
1380 char cookie[8]; /* 'SHCC3.10' */
1381 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1382 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1383 unsigned long tabcnt; /* number of entries in index table */
1384 unsigned long textoff; /* offset of text part */
1385 unsigned long textsize; /* byte size of text part */
1386 unsigned short hashsize; /* hash size */
1387 unsigned short freeidx; /* free index */
1390 /* generic format of table entries */
1391 struct _w31_tabent {
1392 unsigned short w0, w1, w2, w3;
1395 /* directory tabent: */
1396 struct _w31_dirent {
1397 unsigned short sibling_idx; /* table index of sibling dirent */
1398 unsigned short child_idx; /* table index of child dirent */
1399 unsigned short key_idx; /* table index of key keyent */
1400 unsigned short value_idx; /* table index of value valent */
1403 /* key tabent: */
1404 struct _w31_keyent {
1405 unsigned short hash_idx; /* hash chain index for string */
1406 unsigned short refcnt; /* reference count */
1407 unsigned short length; /* length of string */
1408 unsigned short string_off; /* offset of string in text table */
1411 /* value tabent: */
1412 struct _w31_valent {
1413 unsigned short hash_idx; /* hash chain index for string */
1414 unsigned short refcnt; /* reference count */
1415 unsigned short length; /* length of string */
1416 unsigned short string_off; /* offset of string in text table */
1419 /* recursive helper function to display a directory tree */
1420 void
1421 __w31_dumptree( unsigned short idx,
1422 unsigned char *txt,
1423 struct _w31_tabent *tab,
1424 struct _w31_header *head,
1425 LPKEYSTRUCT lpkey,
1426 time_t lastmodified,
1427 int level
1429 struct _w31_dirent *dir;
1430 struct _w31_keyent *key;
1431 struct _w31_valent *val;
1432 LPKEYSTRUCT xlpkey;
1433 LPWSTR name,value;
1434 static char tail[400];
1436 while (idx!=0) {
1437 dir=(struct _w31_dirent*)&tab[idx];
1439 if (dir->key_idx) {
1440 key = (struct _w31_keyent*)&tab[dir->key_idx];
1442 memcpy(tail,&txt[key->string_off],key->length);
1443 tail[key->length]='\0';
1444 /* all toplevel entries AND the entries in the
1445 * toplevel subdirectory belong to \SOFTWARE\Classes
1447 if (!level && !lstrcmp32A(tail,".classes")) {
1448 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1449 idx=dir->sibling_idx;
1450 continue;
1452 name=STRING32_DupAnsiToUni(tail);
1454 xlpkey=_find_or_add_key(lpkey,name);
1456 /* only add if leaf node or valued node */
1457 if (dir->value_idx!=0||dir->child_idx==0) {
1458 if (dir->value_idx) {
1459 val=(struct _w31_valent*)&tab[dir->value_idx];
1460 memcpy(tail,&txt[val->string_off],val->length);
1461 tail[val->length]='\0';
1462 value=STRING32_DupAnsiToUni(tail);
1463 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1466 } else {
1467 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1469 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1470 idx=dir->sibling_idx;
1474 void
1475 _w31_loadreg() {
1476 HFILE hf;
1477 struct _w31_header head;
1478 struct _w31_tabent *tab;
1479 unsigned char *txt;
1480 int len;
1481 OFSTRUCT ofs;
1482 BY_HANDLE_FILE_INFORMATION hfinfo;
1483 time_t lastmodified;
1484 HKEY hkey;
1485 LPKEYSTRUCT lpkey;
1487 hf = OpenFile("reg.dat",&ofs,OF_READ);
1488 if (hf==HFILE_ERROR)
1489 return;
1491 /* read & dump header */
1492 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1493 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1494 _lclose(hf);
1495 return;
1497 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1498 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1499 _lclose(hf);
1500 return;
1503 len = head.tabcnt * sizeof(struct _w31_tabent);
1504 /* read and dump index table */
1505 tab = xmalloc(len);
1506 if (len!=_lread32(hf,tab,len)) {
1507 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1508 free(tab);
1509 _lclose(hf);
1510 return;
1513 /* read text */
1514 txt = xmalloc(head.textsize);
1515 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1516 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1517 free(tab);
1518 free(txt);
1519 _lclose(hf);
1520 return;
1522 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1523 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1524 free(tab);
1525 free(txt);
1526 _lclose(hf);
1527 return;
1530 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1531 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1532 free(tab);
1533 free(txt);
1534 _lclose(hf);
1535 return;
1537 lastmodified = DOSFS_FileTimeToUnixTime(&(hfinfo.ftLastWriteTime));
1539 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1540 return;
1541 lpkey = lookup_hkey(hkey);
1542 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1543 free(tab);
1544 free(txt);
1545 _lclose(hf);
1546 return;
1549 void
1550 SHELL_LoadRegistry() {
1551 char *fn;
1552 struct passwd *pwd;
1553 LPKEYSTRUCT lpkey;
1554 HKEY hkey;
1557 if (key_classes_root==NULL)
1558 SHELL_Init();
1560 /* Load windows 3.1 entries */
1561 _w31_loadreg();
1562 /* Load windows 95 entries */
1563 _w95_loadreg("C:\\system.1st", key_local_machine);
1564 _w95_loadreg("system.dat", key_local_machine);
1565 _w95_loadreg("user.dat", key_users);
1567 /* the global user default is loaded under HKEY_USERS\\.Default */
1568 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1569 lpkey = lookup_hkey(hkey);
1570 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1572 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1573 _copy_registry(lpkey,key_current_user);
1574 RegCloseKey(hkey);
1576 /* the global machine defaults */
1577 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1579 /* load the user saved registries */
1581 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1583 pwd=getpwuid(getuid());
1584 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1585 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1586 strcpy(fn,pwd->pw_dir);
1587 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1588 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1589 free(fn);
1590 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1591 strcpy(fn,pwd->pw_dir);
1592 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1593 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1594 free(fn);
1595 } else
1596 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1597 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1598 DWORD junk,type,len;
1599 char data[5];
1601 len=4;
1602 if (( RegQueryValueEx32A(
1603 hkey,
1604 VAL_SAVEUPDATED,
1605 &junk,
1606 &type,
1607 data,
1608 &len
1609 )!=ERROR_SUCCESS) ||
1610 type != REG_SZ
1612 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1613 RegCloseKey(hkey);
1618 /********************* API FUNCTIONS ***************************************/
1620 * Open Keys.
1622 * All functions are stubs to RegOpenKeyEx32W where all the
1623 * magic happens.
1625 * FIXME: security,options,desiredaccess,...
1627 * Callpath:
1628 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1629 * RegOpenKey32W -> RegOpenKeyEx32W
1632 /* RegOpenKeyExW [ADVAPI32.150] */
1633 DWORD RegOpenKeyEx32W(
1634 HKEY hkey,
1635 LPCWSTR lpszSubKey,
1636 DWORD dwReserved,
1637 REGSAM samDesired,
1638 LPHKEY retkey
1640 LPKEYSTRUCT lpNextKey,lpxkey;
1641 LPWSTR *wps;
1642 int wpc,i;
1643 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1644 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1647 lpNextKey = lookup_hkey(hkey);
1648 if (!lpNextKey)
1649 return SHELL_ERROR_BADKEY;
1650 if (!lpszSubKey || !*lpszSubKey) {
1651 add_handle(++currenthandle,lpNextKey,samDesired);
1652 *retkey=currenthandle;
1653 return SHELL_ERROR_SUCCESS;
1655 split_keypath(lpszSubKey,&wps,&wpc);
1656 i = 0;
1657 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1658 lpxkey = lpNextKey;
1659 while (wps[i]) {
1660 lpxkey=lpNextKey->nextsub;
1661 while (lpxkey) {
1662 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1663 break;
1664 lpxkey=lpxkey->next;
1666 if (!lpxkey) {
1667 FREE_KEY_PATH;
1668 return SHELL_ERROR_BADKEY;
1670 i++;
1671 lpNextKey = lpxkey;
1673 add_handle(++currenthandle,lpxkey,samDesired);
1674 *retkey = currenthandle;
1675 FREE_KEY_PATH;
1676 return SHELL_ERROR_SUCCESS;
1679 /* RegOpenKeyW [ADVAPI32.151] */
1680 DWORD RegOpenKey32W(
1681 HKEY hkey,
1682 LPCWSTR lpszSubKey,
1683 LPHKEY retkey
1685 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1686 (LONG)hkey,W2C(lpszSubKey,0),retkey
1688 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1692 /* RegOpenKeyExA [ADVAPI32.149] */
1693 DWORD RegOpenKeyEx32A(
1694 HKEY hkey,
1695 LPCSTR lpszSubKey,
1696 DWORD dwReserved,
1697 REGSAM samDesired,
1698 LPHKEY retkey
1700 LPWSTR lpszSubKeyW;
1701 DWORD ret;
1703 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1704 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1706 if (lpszSubKey)
1707 lpszSubKeyW=strdupA2W(lpszSubKey);
1708 else
1709 lpszSubKeyW=NULL;
1710 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1711 if (lpszSubKeyW)
1712 free(lpszSubKeyW);
1713 return ret;
1716 /* RegOpenKeyA [ADVAPI32.148] */
1717 DWORD RegOpenKey32A(
1718 HKEY hkey,
1719 LPCSTR lpszSubKey,
1720 LPHKEY retkey
1722 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1723 (LONG)hkey,lpszSubKey,retkey
1725 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1728 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1729 DWORD RegOpenKey16(
1730 HKEY hkey,
1731 LPCSTR lpszSubKey,
1732 LPHKEY retkey
1734 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1735 (LONG)hkey,lpszSubKey,retkey
1737 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1741 * Create keys
1743 * All those functions convert their respective
1744 * arguments and call RegCreateKeyExW at the end.
1746 * FIXME: no security,no access attrib,no optionhandling yet.
1748 * Callpath:
1749 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1750 * RegCreateKey32W -> RegCreateKeyEx32W
1753 /* RegCreateKeyExW [ADVAPI32.131] */
1754 DWORD RegCreateKeyEx32W(
1755 HKEY hkey,
1756 LPCWSTR lpszSubKey,
1757 DWORD dwReserved,
1758 LPWSTR lpszClass,
1759 DWORD fdwOptions,
1760 REGSAM samDesired,
1761 LPSECURITY_ATTRIBUTES lpSecAttribs,
1762 LPHKEY retkey,
1763 LPDWORD lpDispos
1765 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1766 LPWSTR *wps;
1767 int wpc,i;
1769 /*FIXME: handle security/access/whatever */
1770 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1771 (LONG)hkey,
1772 W2C(lpszSubKey,0),
1773 dwReserved,
1774 W2C(lpszClass,1),
1775 fdwOptions,
1776 samDesired,
1777 lpSecAttribs,
1778 retkey,
1779 lpDispos
1782 lpNextKey = lookup_hkey(hkey);
1783 if (!lpNextKey)
1784 return SHELL_ERROR_BADKEY;
1785 if (!lpszSubKey || !*lpszSubKey) {
1786 add_handle(++currenthandle,lpNextKey,samDesired);
1787 *retkey=currenthandle;
1788 lpNextKey->flags|=REG_OPTION_TAINTED;
1789 return SHELL_ERROR_SUCCESS;
1791 split_keypath(lpszSubKey,&wps,&wpc);
1792 i = 0;
1793 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1794 lpxkey = lpNextKey;
1795 while (wps[i]) {
1796 lpxkey=lpNextKey->nextsub;
1797 while (lpxkey) {
1798 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1799 break;
1800 lpxkey=lpxkey->next;
1802 if (!lpxkey)
1803 break;
1804 i++;
1805 lpNextKey = lpxkey;
1807 if (lpxkey) {
1808 add_handle(++currenthandle,lpxkey,samDesired);
1809 lpxkey->flags |= REG_OPTION_TAINTED;
1810 *retkey = currenthandle;
1811 if (lpDispos)
1812 *lpDispos = REG_OPENED_EXISTING_KEY;
1813 FREE_KEY_PATH;
1814 return SHELL_ERROR_SUCCESS;
1816 /* good. now the hard part */
1817 while (wps[i]) {
1818 lplpPrevKey = &(lpNextKey->nextsub);
1819 lpxkey = *lplpPrevKey;
1820 while (lpxkey) {
1821 lplpPrevKey = &(lpxkey->next);
1822 lpxkey = *lplpPrevKey;
1824 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1825 if (!*lplpPrevKey) {
1826 FREE_KEY_PATH;
1827 return SHELL_ERROR_OUTOFMEMORY;
1829 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1830 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1831 (*lplpPrevKey)->next = NULL;
1832 (*lplpPrevKey)->nextsub = NULL;
1833 (*lplpPrevKey)->values = NULL;
1834 (*lplpPrevKey)->nrofvalues = 0;
1835 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1836 if (lpszClass)
1837 (*lplpPrevKey)->class = strdupW(lpszClass);
1838 else
1839 (*lplpPrevKey)->class = NULL;
1840 lpNextKey = *lplpPrevKey;
1841 i++;
1843 add_handle(++currenthandle,lpNextKey,samDesired);
1845 /*FIXME: flag handling correct? */
1846 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1847 if (lpszClass)
1848 lpNextKey->class = strdupW(lpszClass);
1849 else
1850 lpNextKey->class = NULL;
1851 *retkey = currenthandle;
1852 if (lpDispos)
1853 *lpDispos = REG_CREATED_NEW_KEY;
1854 FREE_KEY_PATH;
1855 return SHELL_ERROR_SUCCESS;
1858 /* RegCreateKeyW [ADVAPI32.132] */
1859 DWORD RegCreateKey32W(
1860 HKEY hkey,
1861 LPCWSTR lpszSubKey,
1862 LPHKEY retkey
1864 DWORD junk,ret;
1866 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1867 (LONG)hkey,W2C(lpszSubKey,0),retkey
1869 ret=RegCreateKeyEx32W(
1870 hkey, /* key handle */
1871 lpszSubKey, /* subkey name */
1872 0, /* reserved = 0 */
1873 NULL, /* lpszClass? FIXME: ? */
1874 REG_OPTION_NON_VOLATILE, /* options */
1875 KEY_ALL_ACCESS, /* desired access attribs */
1876 NULL, /* lpsecurity attributes */
1877 retkey, /* lpretkey */
1878 &junk /* disposition value */
1880 return ret;
1883 /* RegCreateKeyExA [ADVAPI32.130] */
1884 DWORD RegCreateKeyEx32A(
1885 HKEY hkey,
1886 LPCSTR lpszSubKey,
1887 DWORD dwReserved,
1888 LPSTR lpszClass,
1889 DWORD fdwOptions,
1890 REGSAM samDesired,
1891 LPSECURITY_ATTRIBUTES lpSecAttribs,
1892 LPHKEY retkey,
1893 LPDWORD lpDispos
1895 LPWSTR lpszSubKeyW,lpszClassW;
1896 DWORD ret;
1898 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1899 (LONG)hkey,
1900 lpszSubKey,
1901 dwReserved,
1902 lpszClass,
1903 fdwOptions,
1904 samDesired,
1905 lpSecAttribs,
1906 retkey,
1907 lpDispos
1909 if (lpszSubKey)
1910 lpszSubKeyW=strdupA2W(lpszSubKey);
1911 else
1912 lpszSubKeyW=NULL;
1913 if (lpszClass)
1914 lpszClassW=strdupA2W(lpszClass);
1915 else
1916 lpszClassW=NULL;
1917 ret=RegCreateKeyEx32W(
1918 hkey,
1919 lpszSubKeyW,
1920 dwReserved,
1921 lpszClassW,
1922 fdwOptions,
1923 samDesired,
1924 lpSecAttribs,
1925 retkey,
1926 lpDispos
1928 if (lpszSubKeyW)
1929 free(lpszSubKeyW);
1930 if (lpszClassW)
1931 free(lpszClassW);
1932 return ret;
1935 /* RegCreateKeyA [ADVAPI32.129] */
1936 DWORD RegCreateKey32A(
1937 HKEY hkey,
1938 LPCSTR lpszSubKey,
1939 LPHKEY retkey
1941 DWORD junk;
1943 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1944 (LONG)hkey,lpszSubKey,retkey
1946 return RegCreateKeyEx32A(
1947 hkey, /* key handle */
1948 lpszSubKey, /* subkey name */
1949 0, /* reserved = 0 */
1950 NULL, /* lpszClass? FIXME: ? */
1951 REG_OPTION_NON_VOLATILE,/* options */
1952 KEY_ALL_ACCESS, /* desired access attribs */
1953 NULL, /* lpsecurity attributes */
1954 retkey, /* lpretkey */
1955 &junk /* disposition value */
1959 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1960 DWORD RegCreateKey16(
1961 HKEY hkey,
1962 LPCSTR lpszSubKey,
1963 LPHKEY retkey
1965 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1966 (LONG)hkey,lpszSubKey,retkey
1968 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1972 * Query Value Functions
1973 * Win32 differs between keynames and valuenames.
1974 * multiple values may belong to one key, the special value
1975 * with name NULL is the default value used by the win31
1976 * compat functions.
1978 * Callpath:
1979 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1980 * RegQueryValue32W -> RegQueryValueEx32W
1983 /* RegQueryValueExW [ADVAPI32.158] */
1984 DWORD RegQueryValueEx32W(
1985 HKEY hkey,
1986 LPWSTR lpszValueName,
1987 LPDWORD lpdwReserved,
1988 LPDWORD lpdwType,
1989 LPBYTE lpbData,
1990 LPDWORD lpcbData
1992 LPKEYSTRUCT lpkey;
1993 int i;
1995 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1996 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1997 lpcbData?*lpcbData:0
2000 lpkey = lookup_hkey(hkey);
2001 if (!lpkey)
2002 return SHELL_ERROR_BADKEY;
2003 if (lpszValueName==NULL) {
2004 for (i=0;i<lpkey->nrofvalues;i++)
2005 if (lpkey->values[i].name==NULL)
2006 break;
2007 } else {
2008 for (i=0;i<lpkey->nrofvalues;i++)
2009 if ( lpkey->values[i].name &&
2010 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2012 break;
2014 if (i==lpkey->nrofvalues) {
2015 if (lpszValueName==NULL) {
2016 if (lpbData) {
2017 *(WCHAR*)lpbData = 0;
2018 *lpcbData = 2;
2020 if (lpdwType)
2021 *lpdwType = REG_SZ;
2022 return SHELL_ERROR_SUCCESS;
2024 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2026 if (lpdwType)
2027 *lpdwType = lpkey->values[i].type;
2028 if (lpbData==NULL) {
2029 if (lpcbData==NULL)
2030 return SHELL_ERROR_SUCCESS;
2031 *lpcbData = lpkey->values[i].len;
2032 return SHELL_ERROR_SUCCESS;
2034 if (*lpcbData<lpkey->values[i].len) {
2035 *(WCHAR*)lpbData
2036 = 0;
2037 *lpcbData = lpkey->values[i].len;
2038 return ERROR_MORE_DATA;
2040 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2041 *lpcbData = lpkey->values[i].len;
2042 return SHELL_ERROR_SUCCESS;
2045 /* RegQueryValueW [ADVAPI32.159] */
2046 DWORD RegQueryValue32W(
2047 HKEY hkey,
2048 LPWSTR lpszSubKey,
2049 LPWSTR lpszData,
2050 LPDWORD lpcbData
2052 HKEY xhkey;
2053 DWORD ret,lpdwType;
2055 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2056 hkey,W2C(lpszSubKey,0),lpszData,
2057 lpcbData?*lpcbData:0
2060 /* only open subkey, if we really do descend */
2061 if (lpszSubKey && *lpszSubKey) {
2062 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2063 if (ret!=ERROR_SUCCESS)
2064 return ret;
2065 } else
2066 xhkey = hkey;
2068 lpdwType = REG_SZ;
2069 ret = RegQueryValueEx32W(
2070 xhkey,
2071 NULL, /* varname NULL -> compat */
2072 NULL, /* lpdwReserved, must be NULL */
2073 &lpdwType,
2074 (LPBYTE)lpszData,
2075 lpcbData
2077 if (xhkey!=hkey)
2078 RegCloseKey(xhkey);
2079 return ret;
2082 /* RegQueryValueExA [ADVAPI32.157] */
2083 DWORD RegQueryValueEx32A(
2084 HKEY hkey,
2085 LPSTR lpszValueName,
2086 LPDWORD lpdwReserved,
2087 LPDWORD lpdwType,
2088 LPBYTE lpbData,
2089 LPDWORD lpcbData
2091 LPWSTR lpszValueNameW;
2092 LPBYTE buf;
2093 DWORD ret,myxlen;
2094 DWORD *mylen;
2095 DWORD type;
2097 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2098 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2099 lpcbData?*lpcbData:0
2101 if (lpbData) {
2102 /* double buffer */
2103 buf = (LPBYTE)xmalloc((*lpcbData)*2);
2104 myxlen = *lpcbData*2;
2105 mylen = &myxlen;
2106 } else {
2107 buf=NULL;
2108 if (lpcbData) {
2109 myxlen = *lpcbData*2;
2110 mylen = &myxlen;
2111 } else
2112 mylen = NULL;
2114 if (lpszValueName)
2115 lpszValueNameW=strdupA2W(lpszValueName);
2116 else
2117 lpszValueNameW=NULL;
2119 if (lpdwType)
2120 type=*lpdwType;
2121 ret=RegQueryValueEx32W(
2122 hkey,
2123 lpszValueNameW,
2124 lpdwReserved,
2125 &type,
2126 buf,
2127 mylen
2129 if (lpdwType)
2130 *lpdwType=type;
2131 if (ret==ERROR_SUCCESS) {
2132 if (buf) {
2133 if (UNICONVMASK & (1<<(type))) {
2134 /* convert UNICODE to ASCII */
2135 strcpyWA(lpbData,(LPWSTR)buf);
2136 *lpcbData = myxlen/2;
2137 } else {
2138 if (myxlen>*lpcbData)
2139 ret = ERROR_MORE_DATA;
2140 else
2141 memcpy(lpbData,buf,myxlen);
2143 *lpcbData = myxlen;
2145 } else {
2146 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2147 *lpcbData = myxlen/2;
2149 } else {
2150 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2151 *lpcbData = myxlen/2;
2153 if (buf)
2154 free(buf);
2155 return ret;
2158 /* RegQueryValueEx [KERNEL.225] */
2159 DWORD RegQueryValueEx16(
2160 HKEY hkey,
2161 LPSTR lpszValueName,
2162 LPDWORD lpdwReserved,
2163 LPDWORD lpdwType,
2164 LPBYTE lpbData,
2165 LPDWORD lpcbData
2167 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2168 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2169 lpcbData?*lpcbData:0
2171 return RegQueryValueEx32A(
2172 hkey,
2173 lpszValueName,
2174 lpdwReserved,
2175 lpdwType,
2176 lpbData,
2177 lpcbData
2181 /* RegQueryValueA [ADVAPI32.156] */
2182 DWORD RegQueryValue32A(
2183 HKEY hkey,
2184 LPSTR lpszSubKey,
2185 LPSTR lpszData,
2186 LPDWORD lpcbData
2188 HKEY xhkey;
2189 DWORD ret,lpdwType;
2191 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2192 hkey,lpszSubKey,lpszData,
2193 lpcbData?*lpcbData:0
2196 /* only open subkey, if we really do descend */
2197 if (lpszSubKey && *lpszSubKey) {
2198 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2199 if (ret!=ERROR_SUCCESS)
2200 return ret;
2201 } else
2202 xhkey = hkey;
2204 lpdwType = REG_SZ;
2205 ret = RegQueryValueEx32A(
2206 xhkey,
2207 NULL, /* lpszValueName NULL -> compat */
2208 NULL, /* lpdwReserved, must be NULL */
2209 &lpdwType,
2210 (LPBYTE)lpszData,
2211 lpcbData
2213 if (xhkey!=hkey)
2214 RegCloseKey(xhkey);
2215 return ret;
2218 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2219 DWORD RegQueryValue16(
2220 HKEY hkey,
2221 LPSTR lpszSubKey,
2222 LPSTR lpszData,
2223 LPDWORD lpcbData
2225 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2226 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2228 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2229 * anyway, so we just mask out the high 16 bit.
2230 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2232 if (lpcbData)
2233 *lpcbData &= 0xFFFF;
2234 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2238 * Setting values of Registry keys
2240 * Callpath:
2241 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2242 * RegSetValue32W -> RegSetValueEx32W
2245 /* RegSetValueExW [ADVAPI32.170] */
2246 DWORD RegSetValueEx32W(
2247 HKEY hkey,
2248 LPWSTR lpszValueName,
2249 DWORD dwReserved,
2250 DWORD dwType,
2251 LPBYTE lpbData,
2252 DWORD cbData
2254 LPKEYSTRUCT lpkey;
2255 int i;
2257 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2258 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2260 /* we no longer care about the lpbData type here... */
2261 lpkey = lookup_hkey(hkey);
2262 if (!lpkey)
2263 return SHELL_ERROR_BADKEY;
2265 lpkey->flags |= REG_OPTION_TAINTED;
2267 if (lpszValueName==NULL) {
2268 for (i=0;i<lpkey->nrofvalues;i++)
2269 if (lpkey->values[i].name==NULL)
2270 break;
2271 } else {
2272 for (i=0;i<lpkey->nrofvalues;i++)
2273 if ( lpkey->values[i].name &&
2274 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2276 break;
2278 if (i==lpkey->nrofvalues) {
2279 lpkey->values = (LPKEYVALUE)xrealloc(
2280 lpkey->values,
2281 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2283 lpkey->nrofvalues++;
2284 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2286 if (lpkey->values[i].name==NULL)
2287 if (lpszValueName)
2288 lpkey->values[i].name = strdupW(lpszValueName);
2289 else
2290 lpkey->values[i].name = NULL;
2291 lpkey->values[i].len = cbData;
2292 lpkey->values[i].type = dwType;
2293 if (lpkey->values[i].data !=NULL)
2294 free(lpkey->values[i].data);
2295 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2296 lpkey->values[i].lastmodified = time(NULL);
2297 memcpy(lpkey->values[i].data,lpbData,cbData);
2298 return SHELL_ERROR_SUCCESS;
2301 /* RegSetValueExA [ADVAPI32.169] */
2302 DWORD RegSetValueEx32A(
2303 HKEY hkey,
2304 LPSTR lpszValueName,
2305 DWORD dwReserved,
2306 DWORD dwType,
2307 LPBYTE lpbData,
2308 DWORD cbData
2310 LPBYTE buf;
2311 LPWSTR lpszValueNameW;
2312 DWORD ret;
2314 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2315 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2317 if ((1<<dwType) & UNICONVMASK) {
2318 buf=(LPBYTE)strdupA2W(lpbData);
2319 cbData=2*strlen(lpbData)+2;
2320 } else
2321 buf=lpbData;
2322 if (lpszValueName)
2323 lpszValueNameW = strdupA2W(lpszValueName);
2324 else
2325 lpszValueNameW = NULL;
2326 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2327 if (lpszValueNameW)
2328 free(lpszValueNameW);
2329 if (buf!=lpbData)
2330 free(buf);
2331 return ret;
2334 /* RegSetValueEx [KERNEL.226] */
2335 DWORD RegSetValueEx16(
2336 HKEY hkey,
2337 LPSTR lpszValueName,
2338 DWORD dwReserved,
2339 DWORD dwType,
2340 LPBYTE lpbData,
2341 DWORD cbData
2343 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2344 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2346 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2349 /* RegSetValueW [ADVAPI32.171] */
2350 DWORD RegSetValue32W(
2351 HKEY hkey,
2352 LPCWSTR lpszSubKey,
2353 DWORD dwType,
2354 LPCWSTR lpszData,
2355 DWORD cbData
2357 HKEY xhkey;
2358 DWORD ret;
2360 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2361 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2363 if (lpszSubKey && *lpszSubKey) {
2364 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2365 if (ret!=ERROR_SUCCESS)
2366 return ret;
2367 } else
2368 xhkey=hkey;
2369 if (dwType!=REG_SZ) {
2370 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2371 dwType=REG_SZ;
2373 if (cbData!=2*lstrlen32W(lpszData)+2) {
2374 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2375 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2377 cbData=2*lstrlen32W(lpszData)+2;
2379 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2380 if (hkey!=xhkey)
2381 RegCloseKey(xhkey);
2382 return ret;
2385 /* RegSetValueA [ADVAPI32.168] */
2386 DWORD RegSetValue32A(
2387 HKEY hkey,
2388 LPCSTR lpszSubKey,
2389 DWORD dwType,
2390 LPCSTR lpszData,
2391 DWORD cbData
2393 DWORD ret;
2394 HKEY xhkey;
2396 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2397 hkey,lpszSubKey,dwType,lpszData,cbData
2399 if (lpszSubKey && *lpszSubKey) {
2400 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2401 if (ret!=ERROR_SUCCESS)
2402 return ret;
2403 } else
2404 xhkey=hkey;
2406 if (dwType!=REG_SZ) {
2407 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2408 dwType=REG_SZ;
2410 if (cbData!=strlen(lpszData)+1)
2411 cbData=strlen(lpszData)+1;
2412 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2413 if (xhkey!=hkey)
2414 RegCloseKey(xhkey);
2415 return ret;
2418 /* RegSetValue [KERNEL.221] [SHELL.5] */
2419 DWORD RegSetValue16(
2420 HKEY hkey,
2421 LPCSTR lpszSubKey,
2422 DWORD dwType,
2423 LPCSTR lpszData,
2424 DWORD cbData
2426 DWORD ret;
2427 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2428 hkey,lpszSubKey,dwType,lpszData,cbData
2430 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2431 return ret;
2435 * Key Enumeration
2437 * Callpath:
2438 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2439 * RegEnumKey32W -> RegEnumKeyEx32W
2442 /* RegEnumKeyExW [ADVAPI32.139] */
2443 DWORD RegEnumKeyEx32W(
2444 HKEY hkey,
2445 DWORD iSubkey,
2446 LPWSTR lpszName,
2447 LPDWORD lpcchName,
2448 LPDWORD lpdwReserved,
2449 LPWSTR lpszClass,
2450 LPDWORD lpcchClass,
2451 FILETIME *ft
2453 LPKEYSTRUCT lpkey,lpxkey;
2455 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2456 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2458 lpkey=lookup_hkey(hkey);
2459 if (!lpkey)
2460 return SHELL_ERROR_BADKEY;
2461 if (!lpkey->nextsub)
2462 return ERROR_NO_MORE_ITEMS;
2463 lpxkey=lpkey->nextsub;
2464 while (iSubkey && lpxkey) {
2465 iSubkey--;
2466 lpxkey=lpxkey->next;
2468 if (iSubkey || !lpxkey)
2469 return ERROR_NO_MORE_ITEMS;
2470 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2471 return ERROR_MORE_DATA;
2472 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2473 if (lpszClass) {
2474 /* what should we write into it? */
2475 *lpszClass = 0;
2476 *lpcchClass = 2;
2478 return ERROR_SUCCESS;
2482 /* RegEnumKeyW [ADVAPI32.140] */
2483 DWORD RegEnumKey32W(
2484 HKEY hkey,
2485 DWORD iSubkey,
2486 LPWSTR lpszName,
2487 DWORD lpcchName
2489 FILETIME ft;
2491 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2492 hkey,iSubkey,lpszName,lpcchName
2494 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2496 /* RegEnumKeyExA [ADVAPI32.138] */
2497 DWORD RegEnumKeyEx32A(
2498 HKEY hkey,
2499 DWORD iSubkey,
2500 LPSTR lpszName,
2501 LPDWORD lpcchName,
2502 LPDWORD lpdwReserved,
2503 LPSTR lpszClass,
2504 LPDWORD lpcchClass,
2505 FILETIME *ft
2507 DWORD ret,lpcchNameW,lpcchClassW;
2508 LPWSTR lpszNameW,lpszClassW;
2511 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2512 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2514 if (lpszName) {
2515 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2516 lpcchNameW = *lpcchName*2;
2517 } else {
2518 lpszNameW = NULL;
2519 lpcchNameW = 0;
2521 if (lpszClass) {
2522 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2523 lpcchClassW = *lpcchClass*2;
2524 } else {
2525 lpszClassW =0;
2526 lpcchClassW=0;
2528 ret=RegEnumKeyEx32W(
2529 hkey,
2530 iSubkey,
2531 lpszNameW,
2532 &lpcchNameW,
2533 lpdwReserved,
2534 lpszClassW,
2535 &lpcchClassW,
2538 if (ret==ERROR_SUCCESS) {
2539 strcpyWA(lpszName,lpszNameW);
2540 *lpcchName=strlen(lpszName);
2541 if (lpszClassW) {
2542 strcpyWA(lpszClass,lpszClassW);
2543 *lpcchClass=strlen(lpszClass);
2546 if (lpszNameW)
2547 free(lpszNameW);
2548 if (lpszClassW)
2549 free(lpszClassW);
2550 return ret;
2553 /* RegEnumKeyA [ADVAPI32.137] */
2554 DWORD RegEnumKey32A(
2555 HKEY hkey,
2556 DWORD iSubkey,
2557 LPSTR lpszName,
2558 DWORD lpcchName
2560 FILETIME ft;
2562 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2563 hkey,iSubkey,lpszName,lpcchName
2565 return RegEnumKeyEx32A(
2566 hkey,
2567 iSubkey,
2568 lpszName,
2569 &lpcchName,
2570 NULL,
2571 NULL,
2572 NULL,
2577 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2578 DWORD RegEnumKey16(
2579 HKEY hkey,
2580 DWORD iSubkey,
2581 LPSTR lpszName,
2582 DWORD lpcchName
2584 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2585 hkey,iSubkey,lpszName,lpcchName
2587 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2591 * Enumerate Registry Values
2593 * Callpath:
2594 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2597 /* RegEnumValueW [ADVAPI32.142] */
2598 DWORD RegEnumValue32W(
2599 HKEY hkey,
2600 DWORD iValue,
2601 LPWSTR lpszValue,
2602 LPDWORD lpcchValue,
2603 LPDWORD lpdReserved,
2604 LPDWORD lpdwType,
2605 LPBYTE lpbData,
2606 LPDWORD lpcbData
2608 LPKEYSTRUCT lpkey;
2609 LPKEYVALUE val;
2611 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2612 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2614 lpkey = lookup_hkey(hkey);
2615 if (!lpkey)
2616 return SHELL_ERROR_BADKEY;
2617 if (lpkey->nrofvalues<=iValue)
2618 return ERROR_NO_MORE_ITEMS;
2619 val = lpkey->values+iValue;
2621 if (val->name) {
2622 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2623 *lpcchValue = lstrlen32W(val->name)*2+2;
2624 return ERROR_MORE_DATA;
2626 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2627 *lpcchValue=lstrlen32W(val->name)*2+2;
2628 } else {
2629 /* how to handle NULL value? */
2630 *lpszValue = 0;
2631 *lpcchValue = 2;
2633 *lpdwType=val->type;
2634 if (lpbData) {
2635 if (val->len>*lpcbData)
2636 return ERROR_MORE_DATA;
2637 memcpy(lpbData,val->data,val->len);
2638 *lpcbData = val->len;
2640 return SHELL_ERROR_SUCCESS;
2643 /* RegEnumValueA [ADVAPI32.141] */
2644 DWORD RegEnumValue32A(
2645 HKEY hkey,
2646 DWORD iValue,
2647 LPSTR lpszValue,
2648 LPDWORD lpcchValue,
2649 LPDWORD lpdReserved,
2650 LPDWORD lpdwType,
2651 LPBYTE lpbData,
2652 LPDWORD lpcbData
2654 LPWSTR lpszValueW;
2655 LPBYTE lpbDataW;
2656 DWORD ret,lpcbDataW;
2658 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2659 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2662 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2663 if (lpbData) {
2664 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2665 lpcbDataW = *lpcbData*2;
2666 } else
2667 lpbDataW = NULL;
2668 ret=RegEnumValue32W(
2669 hkey,
2670 iValue,
2671 lpszValueW,
2672 lpcchValue,
2673 lpdReserved,
2674 lpdwType,
2675 lpbDataW,
2676 &lpcbDataW
2679 if (ret==ERROR_SUCCESS) {
2680 strcpyWA(lpszValue,lpszValueW);
2681 if (lpbData) {
2682 if ((1<<*lpdwType) & UNICONVMASK) {
2683 strcpyWA(lpbData,(LPWSTR)lpbDataW);
2684 } else {
2685 if (lpcbDataW > *lpcbData)
2686 ret = ERROR_MORE_DATA;
2687 else
2688 memcpy(lpbData,lpbDataW,lpcbDataW);
2690 *lpcbData = lpcbDataW;
2693 if (lpbDataW)
2694 free(lpbDataW);
2695 if (lpszValueW)
2696 free(lpszValueW);
2697 return ret;
2700 /* RegEnumValue [KERNEL.223] */
2701 DWORD RegEnumValue16(
2702 HKEY hkey,
2703 DWORD iValue,
2704 LPSTR lpszValue,
2705 LPDWORD lpcchValue,
2706 LPDWORD lpdReserved,
2707 LPDWORD lpdwType,
2708 LPBYTE lpbData,
2709 LPDWORD lpcbData
2711 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2712 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2714 return RegEnumValue32A(
2715 hkey,
2716 iValue,
2717 lpszValue,
2718 lpcchValue,
2719 lpdReserved,
2720 lpdwType,
2721 lpbData,
2722 lpcbData
2727 * Close registry key
2729 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2730 DWORD RegCloseKey(HKEY hkey) {
2731 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2732 remove_handle(hkey);
2733 return ERROR_SUCCESS;
2736 * Delete registry key
2738 * Callpath:
2739 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2741 /* RegDeleteKeyW [ADVAPI32.134] */
2742 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2743 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2744 LPWSTR *wps;
2745 int wpc,i;
2747 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2748 hkey,W2C(lpszSubKey,0)
2750 lpNextKey = lookup_hkey(hkey);
2751 if (!lpNextKey)
2752 return SHELL_ERROR_BADKEY;
2753 /* we need to know the previous key in the hier. */
2754 if (!lpszSubKey || !*lpszSubKey)
2755 return SHELL_ERROR_BADKEY;
2756 split_keypath(lpszSubKey,&wps,&wpc);
2757 i = 0;
2758 lpxkey = lpNextKey;
2759 while (i<wpc-1) {
2760 lpxkey=lpNextKey->nextsub;
2761 while (lpxkey) {
2762 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2763 break;
2764 lpxkey=lpxkey->next;
2766 if (!lpxkey) {
2767 FREE_KEY_PATH;
2768 /* not found is success */
2769 return SHELL_ERROR_SUCCESS;
2771 i++;
2772 lpNextKey = lpxkey;
2774 lpxkey = lpNextKey->nextsub;
2775 lplpPrevKey = &(lpNextKey->nextsub);
2776 while (lpxkey) {
2777 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2778 break;
2779 lplpPrevKey = &(lpxkey->next);
2780 lpxkey = lpxkey->next;
2782 if (!lpxkey)
2783 return SHELL_ERROR_SUCCESS;
2784 if (lpxkey->nextsub)
2785 return SHELL_ERROR_CANTWRITE;
2786 *lplpPrevKey = lpxkey->next;
2787 free(lpxkey->keyname);
2788 if (lpxkey->class)
2789 free(lpxkey->class);
2790 if (lpxkey->values)
2791 free(lpxkey->values);
2792 free(lpxkey);
2793 FREE_KEY_PATH;
2794 return SHELL_ERROR_SUCCESS;
2797 /* RegDeleteKeyA [ADVAPI32.133] */
2798 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2799 LPWSTR lpszSubKeyW;
2800 DWORD ret;
2802 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2803 hkey,lpszSubKey
2805 lpszSubKeyW=strdupA2W(lpszSubKey);
2806 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2807 free(lpszSubKeyW);
2808 return ret;
2811 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2812 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2813 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2814 hkey,lpszSubKey
2816 return RegDeleteKey32A(hkey,lpszSubKey);
2820 * Delete registry value
2822 * Callpath:
2823 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2825 /* RegDeleteValueW [ADVAPI32.136] */
2826 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2827 DWORD i;
2828 LPKEYSTRUCT lpkey;
2829 LPKEYVALUE val;
2831 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2832 hkey,W2C(lpszValue,0)
2834 lpkey=lookup_hkey(hkey);
2835 if (!lpkey)
2836 return SHELL_ERROR_BADKEY;
2837 if (lpszValue) {
2838 for (i=0;i<lpkey->nrofvalues;i++)
2839 if ( lpkey->values[i].name &&
2840 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2842 break;
2843 } else {
2844 for (i=0;i<lpkey->nrofvalues;i++)
2845 if (lpkey->values[i].name==NULL)
2846 break;
2848 if (i==lpkey->nrofvalues)
2849 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2850 val = lpkey->values+i;
2851 if (val->name) free(val->name);
2852 if (val->data) free(val->data);
2853 memcpy(
2854 lpkey->values+i,
2855 lpkey->values+i+1,
2856 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2858 lpkey->values = (LPKEYVALUE)xrealloc(
2859 lpkey->values,
2860 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2862 lpkey->nrofvalues--;
2863 return SHELL_ERROR_SUCCESS;
2866 /* RegDeleteValueA [ADVAPI32.135] */
2867 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2868 LPWSTR lpszValueW;
2869 DWORD ret;
2871 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2872 if (lpszValue)
2873 lpszValueW=strdupA2W(lpszValue);
2874 else
2875 lpszValueW=NULL;
2876 ret=RegDeleteValue32W(hkey,lpszValueW);
2877 if (lpszValueW)
2878 free(lpszValueW);
2879 return ret;
2882 /* RegDeleteValue [KERNEL.222] */
2883 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2884 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2885 return RegDeleteValue32A(hkey,lpszValue);
2888 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2889 DWORD RegFlushKey(HKEY hkey) {
2890 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2891 return SHELL_ERROR_SUCCESS;
2894 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2896 /* RegQueryInfoKeyW [ADVAPI32.153] */
2897 DWORD RegQueryInfoKey32W(
2898 HKEY hkey,
2899 LPWSTR lpszClass,
2900 LPDWORD lpcchClass,
2901 LPDWORD lpdwReserved,
2902 LPDWORD lpcSubKeys,
2903 LPDWORD lpcchMaxSubkey,
2904 LPDWORD lpcchMaxClass,
2905 LPDWORD lpcValues,
2906 LPDWORD lpcchMaxValueName,
2907 LPDWORD lpccbMaxValueData,
2908 LPDWORD lpcbSecurityDescriptor,
2909 FILETIME *ft
2911 LPKEYSTRUCT lpkey,lpxkey;
2912 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2913 int i;
2915 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2916 lpkey=lookup_hkey(hkey);
2917 if (!lpkey)
2918 return SHELL_ERROR_BADKEY;
2919 if (lpszClass) {
2920 if (lpkey->class) {
2921 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2922 *lpcchClass=lstrlen32W(lpkey->class)*2;
2923 return ERROR_MORE_DATA;
2925 *lpcchClass=lstrlen32W(lpkey->class)*2;
2926 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2927 } else {
2928 *lpszClass = 0;
2929 *lpcchClass = 0;
2931 } else {
2932 if (lpcchClass)
2933 *lpcchClass = lstrlen32W(lpkey->class)*2;
2935 lpxkey=lpkey->nextsub;
2936 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2937 while (lpxkey) {
2938 nrofkeys++;
2939 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2940 maxsubkey=lstrlen32W(lpxkey->keyname);
2941 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2942 maxclass=lstrlen32W(lpxkey->class);
2943 if (lpxkey->nrofvalues>maxvalues)
2944 maxvalues=lpxkey->nrofvalues;
2945 for (i=0;i<lpxkey->nrofvalues;i++) {
2946 LPKEYVALUE val=lpxkey->values+i;
2948 if (val->name && lstrlen32W(val->name)>maxvname)
2949 maxvname=lstrlen32W(val->name);
2950 if (val->len>maxvdata)
2951 maxvdata=val->len;
2953 lpxkey=lpxkey->next;
2955 if (!maxclass) maxclass = 1;
2956 if (!maxvname) maxvname = 1;
2957 if (lpcSubKeys)
2958 *lpcSubKeys = nrofkeys;
2959 if (lpcchMaxSubkey)
2960 *lpcchMaxSubkey = maxsubkey*2;
2961 if (lpcchMaxClass)
2962 *lpcchMaxClass = maxclass*2;
2963 if (lpcValues)
2964 *lpcValues = maxvalues;
2965 if (lpcchMaxValueName)
2966 *lpcchMaxValueName= maxvname;
2967 if (lpccbMaxValueData)
2968 *lpccbMaxValueData= maxvdata;
2969 return SHELL_ERROR_SUCCESS;
2972 /* RegQueryInfoKeyA [ADVAPI32.152] */
2973 DWORD RegQueryInfoKey32A(
2974 HKEY hkey,
2975 LPSTR lpszClass,
2976 LPDWORD lpcchClass,
2977 LPDWORD lpdwReserved,
2978 LPDWORD lpcSubKeys,
2979 LPDWORD lpcchMaxSubkey,
2980 LPDWORD lpcchMaxClass,
2981 LPDWORD lpcValues,
2982 LPDWORD lpcchMaxValueName,
2983 LPDWORD lpccbMaxValueData,
2984 LPDWORD lpcbSecurityDescriptor,
2985 FILETIME *ft
2987 LPWSTR lpszClassW;
2988 DWORD ret;
2990 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2991 if (lpszClass) {
2992 *lpcchClass*= 2;
2993 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2995 } else
2996 lpszClassW = NULL;
2997 ret=RegQueryInfoKey32W(
2998 hkey,
2999 lpszClassW,
3000 lpcchClass,
3001 lpdwReserved,
3002 lpcSubKeys,
3003 lpcchMaxSubkey,
3004 lpcchMaxClass,
3005 lpcValues,
3006 lpcchMaxValueName,
3007 lpccbMaxValueData,
3008 lpcbSecurityDescriptor,
3011 if (ret==ERROR_SUCCESS)
3012 strcpyWA(lpszClass,lpszClassW);
3013 if (lpcchClass)
3014 *lpcchClass/=2;
3015 if (lpcchMaxSubkey)
3016 *lpcchMaxSubkey/=2;
3017 if (lpcchMaxClass)
3018 *lpcchMaxClass/=2;
3019 if (lpcchMaxValueName)
3020 *lpcchMaxValueName/=2;
3021 if (lpszClassW)
3022 free(lpszClassW);
3023 return ret;