Release 970329
[wine/multimedia.git] / misc / registry.c
blob668ebf83c5b6a715e31483a84f20a8de7bcac222
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 "heap.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 strdupW(x) STRING32_strdupW(x)
86 #define strchrW(a,c) STRING32_lstrchrW(a,c)
88 static struct openhandle {
89 LPKEYSTRUCT lpkey;
90 HKEY hkey;
91 REGSAM accessmask;
92 } *openhandles=NULL;
93 static int nrofopenhandles=0;
94 static int currenthandle=1;
96 static void
97 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
98 int i;
100 for (i=0;i<nrofopenhandles;i++) {
101 if (openhandles[i].lpkey==lpkey) {
102 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
104 if (openhandles[i].hkey==hkey) {
105 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
108 openhandles=xrealloc( openhandles,
109 sizeof(struct openhandle)*(nrofopenhandles+1)
111 openhandles[i].lpkey = lpkey;
112 openhandles[i].hkey = hkey;
113 openhandles[i].accessmask= accessmask;
114 nrofopenhandles++;
117 static LPKEYSTRUCT
118 get_handle(HKEY hkey) {
119 int i;
121 for (i=0;i<nrofopenhandles;i++)
122 if (openhandles[i].hkey==hkey)
123 return openhandles[i].lpkey;
124 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
125 return NULL;
128 static void
129 remove_handle(HKEY hkey) {
130 int i;
132 for (i=0;i<nrofopenhandles;i++)
133 if (openhandles[i].hkey==hkey)
134 break;
135 if (i==nrofopenhandles) {
136 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
137 return;
139 memcpy( openhandles+i,
140 openhandles+i+1,
141 sizeof(struct openhandle)*(nrofopenhandles-i-1)
143 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
144 nrofopenhandles--;
145 return;
149 /* debug function, converts a unicode into a static memory area
150 * (sub for using two static strings, in case we need them in a single call)
152 LPSTR
153 W2C(LPCWSTR x,int sub) {
154 static LPSTR unicodedebug[2]={NULL,NULL};
155 if (x==NULL)
156 return "<NULL>";
157 if (sub!=0 && sub!=1)
158 return "<W2C:bad sub>";
159 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
160 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
161 return unicodedebug[sub];
164 static LPKEYSTRUCT
165 lookup_hkey(HKEY hkey) {
166 switch (hkey) {
167 case 0x00000000:
168 case 0x00000001:
169 case HKEY_CLASSES_ROOT:
170 return key_classes_root;
171 case HKEY_CURRENT_USER:
172 return key_current_user;
173 case HKEY_LOCAL_MACHINE:
174 return key_local_machine;
175 case HKEY_USERS:
176 return key_users;
177 case HKEY_PERFORMANCE_DATA:
178 return key_performance_data;
179 case HKEY_DYN_DATA:
180 return key_dyn_data;
181 case HKEY_CURRENT_CONFIG:
182 return key_current_config;
183 default:
184 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
185 (LONG)hkey
187 return get_handle(hkey);
189 /*NOTREACHED*/
193 * splits the unicode string 'wp' into an array of strings.
194 * the array is allocated by this function.
195 * the number of components will be stored in 'wpc'
196 * Free the array using FREE_KEY_PATH
198 static void
199 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
200 int i,j,len;
201 LPWSTR ws;
203 ws = HEAP_strdupW( SystemHeap, 0, wp );
204 *wpc = 1;
205 for (i=0;ws[i];i++) {
206 if (ws[i]=='\\') {
207 ws[i]=0;
208 (*wpc)++;
211 len = i;
212 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
213 (*wpv)[0]= ws;
214 j = 1;
215 for (i=1;i<len;i++)
216 if (ws[i-1]==0)
217 (*wpv)[j++]=ws+i;
218 (*wpv)[j]=NULL;
220 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
223 * Shell initialisation, allocates keys.
225 void SHELL_StartupRegistry();
226 void
227 SHELL_Init() {
228 struct passwd *pwd;
230 HKEY cl_r_hkey,c_u_hkey;
231 #define ADD_ROOT_KEY(xx) \
232 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
233 memset(xx,'\0',sizeof(KEYSTRUCT));\
234 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
236 ADD_ROOT_KEY(key_local_machine);
237 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
238 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
239 exit(1);
241 key_classes_root = lookup_hkey(cl_r_hkey);
243 ADD_ROOT_KEY(key_users);
245 #if 0
246 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
247 * (later, when a win32 registry editing tool becomes avail.)
249 while (pwd=getpwent()) {
250 if (pwd->pw_name == NULL)
251 continue;
252 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
253 RegCloseKey(c_u_hkey);
255 #endif
256 pwd=getpwuid(getuid());
257 if (pwd && pwd->pw_name) {
258 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
259 key_current_user = lookup_hkey(c_u_hkey);
260 } else {
261 ADD_ROOT_KEY(key_current_user);
263 ADD_ROOT_KEY(key_performance_data);
264 ADD_ROOT_KEY(key_current_config);
265 ADD_ROOT_KEY(key_dyn_data);
266 #undef ADD_ROOT_KEY
267 SHELL_StartupRegistry();
271 void
272 SHELL_StartupRegistry() {
273 HKEY hkey,xhkey=0;
274 FILE *F;
275 char buf[200],cpubuf[200];
277 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
278 RegCloseKey(xhkey);
279 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
280 #ifdef linux
281 F=fopen("/proc/cpuinfo","r");
282 if (F) {
283 int procnr=-1,x;
284 while (NULL!=fgets(buf,200,F)) {
285 if (sscanf(buf,"processor\t: %d",&x)) {
286 sprintf(buf,"%d",x);
287 if (xhkey)
288 RegCloseKey(xhkey);
289 procnr=x;
290 RegCreateKey16(hkey,buf,&xhkey);
292 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
293 sprintf(buf,"CPU %s",cpubuf);
294 if (xhkey)
295 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
298 fclose(F);
300 if (xhkey)
301 RegCloseKey(xhkey);
302 RegCloseKey(hkey);
303 #else
304 /* FIXME */
305 RegCreateKey16(hkey,"0",&xhkey);
306 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
307 #endif
308 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
309 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
310 RegCloseKey(hkey);
311 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
312 * CurrentVersion
313 * CurrentBuildNumber
314 * CurrentType
315 * string RegisteredOwner
316 * string RegisteredOrganization
319 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
320 * string SysContact
321 * string SysLocation
322 * SysServices
324 if (-1!=gethostname(buf,200)) {
325 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
326 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
327 RegCloseKey(xhkey);
330 /************************ SAVE Registry Function ****************************/
332 #define REGISTRY_SAVE_VERSION 0x00000001
334 /* Registry saveformat:
335 * If you change it, increase above number by 1, which will flush
336 * old registry database files.
338 * Global:
339 * "WINE REGISTRY Version %d"
340 * subkeys....
341 * Subkeys:
342 * keyname
343 * valuename=lastmodified,type,data
344 * ...
345 * subkeys
346 * ...
347 * keyname,valuename,stringdata:
348 * the usual ascii characters from 0x00-0xff (well, not 0x00)
349 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
350 * ( "=\\\t" escaped in \uXXXX form.)
351 * type,lastmodified:
352 * int
354 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
356 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
357 * SaveOnlyUpdatedKeys=yes
359 static int
360 _save_check_tainted(LPKEYSTRUCT lpkey) {
361 int tainted;
363 if (!lpkey)
364 return 0;
365 if (lpkey->flags & REG_OPTION_TAINTED)
366 tainted = 1;
367 else
368 tainted = 0;
369 while (lpkey) {
370 if (_save_check_tainted(lpkey->nextsub)) {
371 lpkey->flags |= REG_OPTION_TAINTED;
372 tainted = 1;
374 lpkey = lpkey->next;
376 return tainted;
379 static void
380 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
381 LPWSTR s;
382 int doescape;
384 if (wstr==NULL)
385 return;
386 s=wstr;
387 while (*s) {
388 doescape=0;
389 if (*s>0xff)
390 doescape = 1;
391 if (*s=='\n')
392 doescape = 1;
393 if (escapeeq && *s=='=')
394 doescape = 1;
395 if (*s=='\\')
396 fputc(*s,F); /* if \\ than put it twice. */
397 if (doescape)
398 fprintf(F,"\\u%04x",*((unsigned short*)s));
399 else
400 fputc(*s,F);
401 s++;
405 static int
406 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
407 LPKEYSTRUCT lpxkey;
408 int i,tabs,j;
410 lpxkey = lpkey;
411 while (lpxkey) {
412 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
413 (all || (lpxkey->flags & REG_OPTION_TAINTED))
415 for (tabs=level;tabs--;)
416 fputc('\t',F);
417 _save_USTRING(F,lpxkey->keyname,1);
418 fputs("\n",F);
419 for (i=0;i<lpxkey->nrofvalues;i++) {
420 LPKEYVALUE val=lpxkey->values+i;
422 for (tabs=level+1;tabs--;)
423 fputc('\t',F);
424 _save_USTRING(F,val->name,0);
425 fputc('=',F);
426 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
427 if ((1<<val->type) & UNICONVMASK)
428 _save_USTRING(F,(LPWSTR)val->data,0);
429 else
430 for (j=0;j<val->len;j++)
431 fprintf(F,"%02x",*((unsigned char*)val->data+j));
432 fputs("\n",F);
434 /* descend recursively */
435 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
436 return 0;
438 lpxkey=lpxkey->next;
440 return 1;
443 static int
444 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
445 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
446 _save_check_tainted(lpkey->nextsub);
447 return _savesubkey(F,lpkey->nextsub,0,all);
450 static BOOL32
451 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
452 FILE *F;
454 F=fopen(fn,"w");
455 if (F==NULL) {
456 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
457 fn,strerror(errno)
459 return FALSE;
461 if (!_savesubreg(F,lpkey,all)) {
462 fclose(F);
463 unlink(fn);
464 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
465 return FALSE;
467 fclose(F);
468 return TRUE;
471 void
472 SHELL_SaveRegistry() {
473 char *fn;
474 struct passwd *pwd;
475 char buf[4];
476 HKEY hkey;
477 int all;
479 all=0;
480 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
481 strcpy(buf,"yes");
482 } else {
483 DWORD len,junk,type;
485 len=4;
486 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
487 hkey,
488 VAL_SAVEUPDATED,
489 &junk,
490 &type,
491 buf,
492 &len
493 ))|| (type!=REG_SZ)
495 strcpy(buf,"yes");
496 RegCloseKey(hkey);
498 if (lstrcmpi32A(buf,"yes"))
499 all=1;
500 pwd=getpwuid(getuid());
501 if (pwd!=NULL && pwd->pw_dir!=NULL)
503 char *tmp;
505 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
506 strlen(SAVE_CURRENT_USER) + 2 );
507 strcpy(fn,pwd->pw_dir);
508 strcat(fn,WINE_PREFIX);
509 /* create the directory. don't care about errorcodes. */
510 mkdir(fn,0755); /* drwxr-xr-x */
511 strcat(fn,"/"SAVE_CURRENT_USER);
512 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
513 strcpy(tmp,fn);strcat(tmp,".tmp");
514 if (_savereg(key_current_user,tmp,all)) {
515 if (-1==rename(tmp,fn)) {
516 perror("rename tmp registry");
517 unlink(tmp);
520 free(tmp);
521 free(fn);
522 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
523 strcpy(fn,pwd->pw_dir);
524 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
525 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
526 strcpy(tmp,fn);strcat(tmp,".tmp");
527 if (_savereg(key_local_machine,tmp,all)) {
528 if (-1==rename(tmp,fn)) {
529 perror("rename tmp registry");
530 unlink(tmp);
533 free(tmp);
534 free(fn);
535 } else
536 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
539 /************************ LOAD Registry Function ****************************/
541 static LPKEYSTRUCT
542 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
543 LPKEYSTRUCT lpxkey,*lplpkey;
545 lplpkey= &(lpkey->nextsub);
546 lpxkey = *lplpkey;
547 while (lpxkey) {
548 if (!lstrcmp32W(lpxkey->keyname,keyname))
549 break;
550 lplpkey = &(lpxkey->next);
551 lpxkey = *lplpkey;
553 if (lpxkey==NULL) {
554 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
555 lpxkey = *lplpkey;
556 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
557 lpxkey->keyname = keyname;
558 } else
559 free(keyname);
560 return lpxkey;
563 static void
564 _find_or_add_value(
565 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
566 DWORD lastmodified
568 LPKEYVALUE val=NULL;
569 int i;
571 for (i=0;i<lpkey->nrofvalues;i++) {
572 val=lpkey->values+i;
573 if (name==NULL) {
574 if (val->name==NULL)
575 break;
576 } else {
577 if ( val->name!=NULL &&
578 !lstrcmp32W(val->name,name)
580 break;
583 if (i==lpkey->nrofvalues) {
584 lpkey->values = xrealloc(
585 lpkey->values,
586 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
588 val=lpkey->values+i;
589 memset(val,'\0',sizeof(KEYVALUE));
590 val->name = name;
591 } else {
592 if (name)
593 free(name);
595 if (val->lastmodified<lastmodified) {
596 val->lastmodified=lastmodified;
597 val->type = type;
598 val->len = len;
599 if (val->data)
600 free(val->data);
601 val->data = data;
602 } else
603 free(data);
607 /* reads a line including dynamically enlarging the readbuffer and throwing
608 * away comments
610 static int
611 _wine_read_line(FILE *F,char **buf,int *len) {
612 char *s,*curread;
613 int mylen,curoff;
615 curread = *buf;
616 mylen = *len;
617 **buf = '\0';
618 while (1) {
619 while (1) {
620 s=fgets(curread,mylen,F);
621 if (s==NULL)
622 return 0; /* EOF */
623 if (NULL==(s=strchr(curread,'\n'))) {
624 /* buffer wasn't large enough */
625 curoff = strlen(*buf);
626 *buf = xrealloc(*buf,*len*2);
627 curread = *buf + curoff;
628 mylen = *len; /* we filled up the buffer and
629 * got new '*len' bytes to fill
631 *len = *len * 2;
632 } else {
633 *s='\0';
634 break;
637 /* throw away comments */
638 if (**buf=='#' || **buf==';') {
639 curread = *buf;
640 mylen = *len;
641 continue;
643 if (s) /* got end of line */
644 break;
646 return 1;
649 /* converts a char* into a UNICODE string (up to a special char)
650 * and returns the position exactly after that string
652 static char*
653 _wine_read_USTRING(char *buf,LPWSTR *str) {
654 char *s;
655 LPWSTR ws;
657 /* read up to "=" or "\0" or "\n" */
658 s = buf;
659 if (*s == '=') {
660 /* empty string is the win3.1 default value(NULL)*/
661 *str = NULL;
662 return s;
664 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
665 ws = *str;
666 while (*s && (*s!='\n') && (*s!='=')) {
667 if (*s!='\\')
668 *ws++=*((unsigned char*)s++);
669 else {
670 s++;
671 if (*s=='\\') {
672 *ws+='\\';
673 s++;
674 continue;
676 if (*s!='u') {
677 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
678 *ws++='\\';
679 *ws++=*s++;
680 } else {
681 char xbuf[5];
682 int wc;
684 s++;
685 memcpy(xbuf,s,4);xbuf[4]='\0';
686 if (!sscanf(xbuf,"%x",&wc))
687 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
688 s+=4;
689 *ws++ =(unsigned short)wc;
693 *ws = 0;
694 ws = *str;
695 *str = strdupW(*str);
696 free(ws);
697 return s;
700 static int
701 _wine_loadsubkey(
702 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
704 LPKEYSTRUCT lpxkey;
705 int i;
706 char *s;
707 LPWSTR name;
709 lpkey->flags |= optflag;
711 /* good. we already got a line here ... so parse it */
712 lpxkey = NULL;
713 while (1) {
714 i=0;s=*buf;
715 while (*s=='\t') {
716 s++;
717 i++;
719 if (i>level) {
720 if (lpxkey==NULL) {
721 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
722 return 0;
724 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
725 continue;
727 /* let the caller handle this line */
728 if (i<level || **buf=='\0')
729 return 1;
731 /* it can be: a value or a keyname. Parse the name first */
732 s=_wine_read_USTRING(s,&name);
734 /* switch() default: hack to avoid gotos */
735 switch (0) {
736 default:
737 if (*s=='\0') {
738 lpxkey=_find_or_add_key(lpkey,name);
739 } else {
740 LPBYTE data;
741 int len,lastmodified,type;
743 if (*s!='=') {
744 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
745 break;
747 s++;
748 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
749 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
750 break;
752 /* skip the 2 , */
753 s=strchr(s,',');s++;
754 s=strchr(s,',');s++;
755 if ((1<<type) & UNICONVMASK) {
756 s=_wine_read_USTRING(s,(LPWSTR*)&data);
757 if (data)
758 len = lstrlen32W((LPWSTR)data)*2+2;
759 else
760 len = 0;
761 } else {
762 len=strlen(s)/2;
763 data = (LPBYTE)xmalloc(len+1);
764 for (i=0;i<len;i++) {
765 data[i]=0;
766 if (*s>='0' && *s<='9')
767 data[i]=(*s-'0')<<4;
768 if (*s>='a' && *s<='f')
769 data[i]=(*s-'a')<<4;
770 if (*s>='A' && *s<='F')
771 data[i]=(*s-'A')<<4;
772 s++;
773 if (*s>='0' && *s<='9')
774 data[i]|=*s-'0';
775 if (*s>='a' && *s<='f')
776 data[i]|=*s-'a';
777 if (*s>='A' && *s<='F')
778 data[i]|=*s-'A';
779 s++;
782 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
785 /* read the next line */
786 if (!_wine_read_line(F,buf,buflen))
787 return 1;
789 return 1;
792 static int
793 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
794 int ver;
795 char *buf;
796 int buflen;
798 buf=xmalloc(10);buflen=10;
799 if (!_wine_read_line(F,&buf,&buflen)) {
800 free(buf);
801 return 0;
803 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
804 free(buf);
805 return 0;
807 if (ver!=REGISTRY_SAVE_VERSION) {
808 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
809 free(buf);
810 return 0;
812 if (!_wine_read_line(F,&buf,&buflen)) {
813 free(buf);
814 return 0;
816 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
817 free(buf);
818 return 0;
820 free(buf);
821 return 1;
824 static void
825 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
826 FILE *F;
828 F=fopen(fn,"rb");
829 if (F==NULL) {
830 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
831 fn,strerror(errno)
833 return;
835 if (!_wine_loadsubreg(F,lpkey,optflag)) {
836 fclose(F);
837 unlink(fn);
838 return;
840 fclose(F);
843 static void
844 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
845 LPKEYSTRUCT lpxkey;
846 int j;
847 LPKEYVALUE valfrom;
849 from=from->nextsub;
850 while (from) {
851 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
853 for (j=0;j<from->nrofvalues;j++) {
854 LPWSTR name;
855 LPBYTE data;
857 valfrom = from->values+j;
858 name=valfrom->name;
859 if (name) name=strdupW(name);
860 data=(LPBYTE)malloc(valfrom->len);
861 memcpy(data,valfrom->data,valfrom->len);
863 _find_or_add_value(
864 lpxkey,
865 name,
866 valfrom->type,
867 data,
868 valfrom->len,
869 valfrom->lastmodified
872 _copy_registry(from,lpxkey);
873 from = from->next;
877 /* WINDOWS 95 REGISTRY LOADER */
879 * Structure of a win95 registry database.
880 * main header:
881 * 0 : "CREG" - magic
882 * 4 : DWORD version
883 * 8 : DWORD offset_of_RGDB_part
884 * 0C..1F: ? (someone fill in please)
886 * 20: RGKN_section:
887 * header:
888 * 0 : "RGKN" - magic
889 * 4..0x1B: ? (fill in)
890 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
892 * Disk Key Entry Structure:
893 * 00: DWORD - unknown
894 * 04: DWORD - unknown
895 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
896 * 0C: DWORD - disk address of PreviousLevel Key.
897 * 10: DWORD - disk address of Next Sublevel Key.
898 * 14: DWORD - disk address of Next Key (on same level).
899 * DKEP>18: WORD - Nr, Low Significant part.
900 * 1A: WORD - Nr, High Significant part.
902 * The disk address always points to the nr part of the previous key entry
903 * of the referenced key. Don't ask me why, or even if I got this correct
904 * from staring at 1kg of hexdumps. (DKEP)
906 * The number of the entry is the low byte of the Low Significant Part ored
907 * with 0x100 * (low byte of the High Significant part)
908 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
910 * There are two minor corrections to the position of that structure.
911 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
912 * the DKE reread from there.
913 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
914 * (FIXME: slightly better explanation needed here)
916 * RGDB_section:
917 * 00: "RGDB" - magic
918 * 04: DWORD offset to next RGDB section (perhaps WORD)
919 * 08...1F: ?
920 * 20.....: disk keys
922 * disk key:
923 * 00: DWORD nextkeyoffset - offset to the next disk key structure
924 * 08: WORD nrLS - low significant part of NR
925 * 0A: WORD nrHS - high significant part of NR
926 * 0C: DWORD bytesused - bytes used in this structure.
927 * 10: WORD name_len - length of name in bytes. without \0
928 * 12: WORD nr_of_values - number of values.
929 * 14: char name[name_len] - name string. No \0.
930 * 14+name_len: disk values
931 * nextkeyoffset: ... next disk key
933 * disk value:
934 * 00: DWORD type - value type (hmm, could be WORD too)
935 * 04: DWORD - unknown, usually 0
936 * 08: WORD namelen - length of Name. 0 means name=NULL
937 * 0C: WORD datalen - length of Data.
938 * 10: char name[namelen] - name, no \0
939 * 10+namelen: BYTE data[datalen] - data, without \0 if string
940 * 10+namelen+datalen: next values or disk key
942 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
943 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
944 * structure) and reading another RGDB_section.
945 * repeat until end of file.
947 * FIXME: this description needs some serious help, yes.
950 struct _w95keyvalue {
951 unsigned long type;
952 unsigned short datalen;
953 char *name;
954 unsigned char *data;
955 unsigned long x1;
956 int lastmodified;
959 struct _w95key {
960 char *name;
961 int nrofvals;
962 struct _w95keyvalue *values;
963 unsigned long dkeaddr;
964 unsigned long x1;
965 unsigned long x2;
966 unsigned long x3;
967 unsigned long xx1;
968 struct _w95key *prevlvl;
969 struct _w95key *nextsub;
970 struct _w95key *next;
973 /* fast lookup table dkeaddr->nr */
974 struct _w95nr2da {
975 unsigned long dkeaddr;
976 unsigned long nr;
980 static void
981 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
982 int i;
983 LPKEYSTRUCT lpxkey;
984 LPWSTR name;
986 while (key) {
987 if (key->name == NULL) {
988 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
989 key->dkeaddr
991 return;
993 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
995 if (key->nrofvals<0) {
996 /* shouldn't happen */
997 fprintf(stderr,"key %s already processed!\n",key->name);
998 key = key->next;
999 continue;
1001 for (i=0;i<key->nrofvals;i++) {
1002 LPBYTE data;
1003 int len;
1005 name = strdupA2W(key->values[i].name);
1006 if (!*name) name = NULL;
1007 free(key->values[i].name);
1009 len = key->values[i].datalen;
1010 data = key->values[i].data;
1011 if ((1<<key->values[i].type) & UNICONVMASK) {
1012 data = (BYTE*)strdupA2W(data);
1013 len = lstrlen32W((LPWSTR)data)*2+2;
1014 free(key->values[i].data);
1016 _find_or_add_value(
1017 lpxkey,
1018 name,
1019 key->values[i].type,
1020 data,
1021 len,
1022 key->values[i].lastmodified
1025 if (key->values) {
1026 free(key->values);
1027 key->values = NULL;
1029 key->nrofvals=-key->nrofvals-1;
1030 _w95_walk_tree(lpxkey,key->nextsub);
1031 key=key->next;
1035 /* small helper function to adjust address offset (dkeaddrs) */
1036 static unsigned long
1037 _w95_adj_da(unsigned long dkeaddr) {
1038 if ((dkeaddr&0xFFF)<0x018) {
1039 int diff;
1041 diff=0x1C-(dkeaddr&0xFFF);
1042 return dkeaddr+diff;
1044 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1045 /* readjust to 0x000,
1046 * but ONLY if we are >0x1000 already
1048 if (dkeaddr & ~0xFFF)
1049 return dkeaddr & ~0xFFF;
1051 return dkeaddr;
1054 static int
1055 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1057 static struct _w95key*
1058 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1059 int i,off;
1061 if (dkeaddr == 0xFFFFFFFF)
1062 return NULL;
1063 if (dkeaddr<0x20)
1064 return NULL;
1065 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1066 off = (dkeaddr-0x3c)/0x1c;
1067 for (i=0;i<n;i++)
1068 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1069 return keys+nr2da[(i+off)%n].nr;
1070 /* 0x3C happens often, just report unusual values */
1071 if (dkeaddr!=0x3c)
1072 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1073 return NULL;
1076 static void
1077 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1078 /* Disk Key Entry structure (RGKN part) */
1079 struct dke {
1080 unsigned long x1;
1081 unsigned long x2;
1082 unsigned long x3;/*usually 0xFFFFFFFF */
1083 unsigned long prevlvl;
1084 unsigned long nextsub;
1085 unsigned long next;
1086 unsigned short nrLS;
1087 unsigned short nrMS;
1089 /* Disk Key Header structure (RGDB part) */
1090 struct dkh {
1091 unsigned long nextkeyoff;
1092 unsigned short nrLS;
1093 unsigned short nrMS;
1094 unsigned long bytesused;
1095 unsigned short keynamelen;
1096 unsigned short values;
1097 unsigned long xx1;
1098 /* keyname */
1099 /* disk key values or nothing */
1101 /* Disk Key Value structure */
1102 struct dkv {
1103 unsigned long type;
1104 unsigned long x1;
1105 unsigned short valnamelen;
1106 unsigned short valdatalen;
1107 /* valname, valdata */
1109 struct _w95nr2da *nr2da;
1111 HFILE32 hfd;
1112 int lastmodified;
1113 char magic[5];
1114 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1115 struct _w95key *keys;
1116 int nrofdkes;
1117 unsigned char *data,*curdata,*nextrgdb;
1118 OFSTRUCT ofs;
1119 BY_HANDLE_FILE_INFORMATION hfdinfo;
1121 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1122 hfd=OpenFile32(fn,&ofs,OF_READ);
1123 if (hfd==HFILE_ERROR32)
1124 return;
1125 magic[4]=0;
1126 if (4!=_lread32(hfd,magic,4))
1127 return;
1128 if (strcmp(magic,"CREG")) {
1129 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1130 return;
1132 if (4!=_lread32(hfd,&version,4))
1133 return;
1134 if (4!=_lread32(hfd,&rgdbsection,4))
1135 return;
1136 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1137 return;
1138 if (4!=_lread32(hfd,magic,4))
1139 return;
1140 if (strcmp(magic,"RGKN")) {
1141 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1142 return;
1145 /* STEP 1: Keylink structures */
1146 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1147 return;
1148 where = 0x40;
1149 end = rgdbsection;
1151 nrofdkes = (end-where)/sizeof(struct dke)+100;
1152 data = (char*)xmalloc(end-where);
1153 if ((end-where)!=_lread32(hfd,data,end-where))
1154 return;
1155 curdata = data;
1157 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1158 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1159 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1160 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1162 for (i=0;i<nrofdkes;i++) {
1163 struct dke dke;
1164 unsigned long dkeaddr;
1166 pos=curdata-data+0x40;
1167 memcpy(&dke,curdata,sizeof(dke));
1168 curdata+=sizeof(dke);
1169 nr = dke.nrLS + (dke.nrMS<<8);
1170 dkeaddr=pos-4;
1171 if ((dkeaddr&0xFFF)<0x018) {
1172 int diff;
1174 diff=0x1C-(dkeaddr&0xFFF);
1175 dkeaddr+=diff;
1176 curdata+=diff-sizeof(dke);
1177 memcpy(&dke,curdata,sizeof(dke));
1178 nr = dke.nrLS + (dke.nrMS<<8);
1179 curdata+=sizeof(dke);
1181 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1182 /* readjust to 0x000,
1183 * but ONLY if we are >0x1000 already
1185 if (dkeaddr & ~0xFFF)
1186 dkeaddr = dkeaddr & ~0xFFF;
1188 if (nr>nrofdkes) {
1189 /* 0xFFFFFFFF happens often, just report unusual values */
1190 if (nr!=0xFFFFFFFF)
1191 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1192 continue;
1194 if (keys[nr].dkeaddr) {
1195 int x;
1197 for (x=sizeof(dke);x--;)
1198 if (((char*)&dke)[x])
1199 break;
1200 if (x==-1)
1201 break; /* finished reading if we got only 0 */
1202 if (nr) {
1203 if ( (dke.next!=(long)keys[nr].next) ||
1204 (dke.nextsub!=(long)keys[nr].nextsub) ||
1205 (dke.prevlvl!=(long)keys[nr].prevlvl)
1207 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1209 continue;
1211 nr2da[i].nr = nr;
1212 nr2da[i].dkeaddr = dkeaddr;
1214 keys[nr].dkeaddr = dkeaddr;
1215 keys[nr].x1 = dke.x1;
1216 keys[nr].x2 = dke.x2;
1217 keys[nr].x3 = dke.x3;
1218 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1219 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1220 keys[nr].next = (struct _w95key*)dke.next;
1222 free(data);
1224 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1225 (int(*)(const void *,const void*))_w95dkecomp);
1227 /* STEP 2: keydata & values */
1228 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1229 return;
1230 end = hfdinfo.nFileSizeLow;
1231 lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1233 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1234 return;
1235 data = (char*)xmalloc(end-rgdbsection);
1236 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1237 return;
1238 _lclose32(hfd);
1239 curdata = data;
1240 memcpy(magic,curdata,4);
1241 memcpy(&off_next_rgdb,curdata+4,4);
1242 nextrgdb = curdata+off_next_rgdb;
1243 if (strcmp(magic,"RGDB")) {
1244 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1245 return;
1247 curdata=data+0x20;
1248 while (1) {
1249 struct dkh dkh;
1250 int bytesread;
1251 struct _w95key *key,xkey;
1253 bytesread = 0;
1254 if (curdata>=nextrgdb) {
1255 curdata = nextrgdb;
1256 if (!strncmp(curdata,"RGDB",4)) {
1257 memcpy(&off_next_rgdb,curdata+4,4);
1258 nextrgdb = curdata+off_next_rgdb;
1259 curdata+=0x20;
1260 } else {
1261 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1262 break;
1265 #define XREAD(whereto,len) \
1266 if ((curdata-data+len)<end) {\
1267 memcpy(whereto,curdata,len);\
1268 curdata+=len;\
1269 bytesread+=len;\
1272 XREAD(&dkh,sizeof(dkh));
1273 nr = dkh.nrLS + (dkh.nrMS<<8);
1274 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1275 if (dkh.nrLS == 0xFFFF) {
1276 /* skip over key using nextkeyoff */
1277 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1278 continue;
1280 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1281 key = &xkey;
1282 memset(key,'\0',sizeof(xkey));
1283 } else {
1284 key = keys+nr;
1285 if (!key->dkeaddr)
1286 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1288 key->nrofvals = dkh.values;
1289 key->name = (char*)xmalloc(dkh.keynamelen+1);
1290 key->xx1 = dkh.xx1;
1291 XREAD(key->name,dkh.keynamelen);
1292 key->name[dkh.keynamelen]=0;
1293 if (key->nrofvals) {
1294 key->values = (struct _w95keyvalue*)xmalloc(
1295 sizeof(struct _w95keyvalue)*key->nrofvals
1297 for (i=0;i<key->nrofvals;i++) {
1298 struct dkv dkv;
1300 XREAD(&dkv,sizeof(dkv));
1301 key->values[i].type = dkv.type;
1302 key->values[i].name = (char*)xmalloc(
1303 dkv.valnamelen+1
1305 key->values[i].datalen = dkv.valdatalen;
1306 key->values[i].data = (unsigned char*)xmalloc(
1307 dkv.valdatalen+1
1309 key->values[i].x1 = dkv.x1;
1310 XREAD(key->values[i].name,dkv.valnamelen);
1311 XREAD(key->values[i].data,dkv.valdatalen);
1312 key->values[i].data[dkv.valdatalen]=0;
1313 key->values[i].name[dkv.valnamelen]=0;
1314 key->values[i].lastmodified=lastmodified;
1317 if (bytesread != dkh.nextkeyoff) {
1318 if (dkh.bytesused != bytesread)
1319 dprintf_reg(stddeb,
1320 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1321 dkh.bytesused
1323 curdata += dkh.nextkeyoff-bytesread;
1325 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1326 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1327 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1328 if (!bytesread)
1329 break;
1331 free(data);
1332 _w95_walk_tree(lpkey,keys);
1333 free(keys);
1336 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1339 reghack - windows 3.11 registry data format demo program.
1341 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1342 a combined hash table and tree description, and finally a text table.
1344 The header is obvious from the struct header. The taboff1 and taboff2
1345 fields are always 0x20, and their usage is unknown.
1347 The 8-byte entry table has various entry types.
1349 tabent[0] is a root index. The second word has the index of the root of
1350 the directory.
1351 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1352 the index of the key/value that has that hash. Data with the same
1353 hash value are on a circular list. The other three words in the
1354 hash entry are always zero.
1355 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1356 entry: dirent and keyent/valent. They are identified by context.
1357 tabent[freeidx] is the first free entry. The first word in a free entry
1358 is the index of the next free entry. The last has 0 as a link.
1359 The other three words in the free list are probably irrelevant.
1361 Entries in text table are preceeded by a word at offset-2. This word
1362 has the value (2*index)+1, where index is the referring keyent/valent
1363 entry in the table. I have no suggestion for the 2* and the +1.
1364 Following the word, there are N bytes of data, as per the keyent/valent
1365 entry length. The offset of the keyent/valent entry is from the start
1366 of the text table to the first data byte.
1368 This information is not available from Microsoft. The data format is
1369 deduced from the reg.dat file by me. Mistakes may
1370 have been made. I claim no rights and give no guarantees for this program.
1372 Tor Sjøwall, tor@sn.no
1375 /* reg.dat header format */
1376 struct _w31_header {
1377 char cookie[8]; /* 'SHCC3.10' */
1378 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1379 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1380 unsigned long tabcnt; /* number of entries in index table */
1381 unsigned long textoff; /* offset of text part */
1382 unsigned long textsize; /* byte size of text part */
1383 unsigned short hashsize; /* hash size */
1384 unsigned short freeidx; /* free index */
1387 /* generic format of table entries */
1388 struct _w31_tabent {
1389 unsigned short w0, w1, w2, w3;
1392 /* directory tabent: */
1393 struct _w31_dirent {
1394 unsigned short sibling_idx; /* table index of sibling dirent */
1395 unsigned short child_idx; /* table index of child dirent */
1396 unsigned short key_idx; /* table index of key keyent */
1397 unsigned short value_idx; /* table index of value valent */
1400 /* key tabent: */
1401 struct _w31_keyent {
1402 unsigned short hash_idx; /* hash chain index for string */
1403 unsigned short refcnt; /* reference count */
1404 unsigned short length; /* length of string */
1405 unsigned short string_off; /* offset of string in text table */
1408 /* value tabent: */
1409 struct _w31_valent {
1410 unsigned short hash_idx; /* hash chain index for string */
1411 unsigned short refcnt; /* reference count */
1412 unsigned short length; /* length of string */
1413 unsigned short string_off; /* offset of string in text table */
1416 /* recursive helper function to display a directory tree */
1417 void
1418 __w31_dumptree( unsigned short idx,
1419 unsigned char *txt,
1420 struct _w31_tabent *tab,
1421 struct _w31_header *head,
1422 LPKEYSTRUCT lpkey,
1423 time_t lastmodified,
1424 int level
1426 struct _w31_dirent *dir;
1427 struct _w31_keyent *key;
1428 struct _w31_valent *val;
1429 LPKEYSTRUCT xlpkey = NULL;
1430 LPWSTR name,value;
1431 static char tail[400];
1433 while (idx!=0) {
1434 dir=(struct _w31_dirent*)&tab[idx];
1436 if (dir->key_idx) {
1437 key = (struct _w31_keyent*)&tab[dir->key_idx];
1439 memcpy(tail,&txt[key->string_off],key->length);
1440 tail[key->length]='\0';
1441 /* all toplevel entries AND the entries in the
1442 * toplevel subdirectory belong to \SOFTWARE\Classes
1444 if (!level && !lstrcmp32A(tail,".classes")) {
1445 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1446 idx=dir->sibling_idx;
1447 continue;
1449 name=STRING32_DupAnsiToUni(tail);
1451 xlpkey=_find_or_add_key(lpkey,name);
1453 /* only add if leaf node or valued node */
1454 if (dir->value_idx!=0||dir->child_idx==0) {
1455 if (dir->value_idx) {
1456 val=(struct _w31_valent*)&tab[dir->value_idx];
1457 memcpy(tail,&txt[val->string_off],val->length);
1458 tail[val->length]='\0';
1459 value=STRING32_DupAnsiToUni(tail);
1460 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1463 } else {
1464 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1466 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1467 idx=dir->sibling_idx;
1471 void
1472 _w31_loadreg() {
1473 HFILE32 hf;
1474 struct _w31_header head;
1475 struct _w31_tabent *tab;
1476 unsigned char *txt;
1477 int len;
1478 OFSTRUCT ofs;
1479 BY_HANDLE_FILE_INFORMATION hfinfo;
1480 time_t lastmodified;
1481 HKEY hkey;
1482 LPKEYSTRUCT lpkey;
1484 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1485 if (hf==HFILE_ERROR32)
1486 return;
1488 /* read & dump header */
1489 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1490 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1491 _lclose32(hf);
1492 return;
1494 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1495 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1496 _lclose32(hf);
1497 return;
1500 len = head.tabcnt * sizeof(struct _w31_tabent);
1501 /* read and dump index table */
1502 tab = xmalloc(len);
1503 if (len!=_lread32(hf,tab,len)) {
1504 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1505 free(tab);
1506 _lclose32(hf);
1507 return;
1510 /* read text */
1511 txt = xmalloc(head.textsize);
1512 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1513 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1514 free(tab);
1515 free(txt);
1516 _lclose32(hf);
1517 return;
1519 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1520 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1521 free(tab);
1522 free(txt);
1523 _lclose32(hf);
1524 return;
1527 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1528 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1529 free(tab);
1530 free(txt);
1531 _lclose32(hf);
1532 return;
1534 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1536 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1537 return;
1538 lpkey = lookup_hkey(hkey);
1539 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1540 free(tab);
1541 free(txt);
1542 _lclose32(hf);
1543 return;
1546 void
1547 SHELL_LoadRegistry() {
1548 char *fn;
1549 struct passwd *pwd;
1550 LPKEYSTRUCT lpkey;
1551 HKEY hkey;
1554 if (key_classes_root==NULL)
1555 SHELL_Init();
1557 /* Load windows 3.1 entries */
1558 _w31_loadreg();
1559 /* Load windows 95 entries */
1560 _w95_loadreg("C:\\system.1st", key_local_machine);
1561 _w95_loadreg("system.dat", key_local_machine);
1562 _w95_loadreg("user.dat", key_users);
1564 /* the global user default is loaded under HKEY_USERS\\.Default */
1565 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1566 lpkey = lookup_hkey(hkey);
1567 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1569 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1570 _copy_registry(lpkey,key_current_user);
1571 RegCloseKey(hkey);
1573 /* the global machine defaults */
1574 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1576 /* load the user saved registries */
1578 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1580 pwd=getpwuid(getuid());
1581 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1582 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1583 strcpy(fn,pwd->pw_dir);
1584 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1585 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1586 free(fn);
1587 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1588 strcpy(fn,pwd->pw_dir);
1589 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1590 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1591 free(fn);
1592 } else
1593 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1594 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1595 DWORD junk,type,len;
1596 char data[5];
1598 len=4;
1599 if (( RegQueryValueEx32A(
1600 hkey,
1601 VAL_SAVEUPDATED,
1602 &junk,
1603 &type,
1604 data,
1605 &len
1606 )!=ERROR_SUCCESS) ||
1607 type != REG_SZ
1609 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1610 RegCloseKey(hkey);
1615 /********************* API FUNCTIONS ***************************************/
1617 * Open Keys.
1619 * All functions are stubs to RegOpenKeyEx32W where all the
1620 * magic happens.
1622 * FIXME: security,options,desiredaccess,...
1624 * Callpath:
1625 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1626 * RegOpenKey32W -> RegOpenKeyEx32W
1629 /* RegOpenKeyExW [ADVAPI32.150] */
1630 DWORD RegOpenKeyEx32W(
1631 HKEY hkey,
1632 LPCWSTR lpszSubKey,
1633 DWORD dwReserved,
1634 REGSAM samDesired,
1635 LPHKEY retkey
1637 LPKEYSTRUCT lpNextKey,lpxkey;
1638 LPWSTR *wps;
1639 int wpc,i;
1640 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1641 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1644 lpNextKey = lookup_hkey(hkey);
1645 if (!lpNextKey)
1646 return SHELL_ERROR_BADKEY;
1647 if (!lpszSubKey || !*lpszSubKey) {
1648 add_handle(++currenthandle,lpNextKey,samDesired);
1649 *retkey=currenthandle;
1650 return SHELL_ERROR_SUCCESS;
1652 split_keypath(lpszSubKey,&wps,&wpc);
1653 i = 0;
1654 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1655 lpxkey = lpNextKey;
1656 while (wps[i]) {
1657 lpxkey=lpNextKey->nextsub;
1658 while (lpxkey) {
1659 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1660 break;
1661 lpxkey=lpxkey->next;
1663 if (!lpxkey) {
1664 FREE_KEY_PATH;
1665 return SHELL_ERROR_BADKEY;
1667 i++;
1668 lpNextKey = lpxkey;
1670 add_handle(++currenthandle,lpxkey,samDesired);
1671 *retkey = currenthandle;
1672 FREE_KEY_PATH;
1673 return SHELL_ERROR_SUCCESS;
1676 /* RegOpenKeyW [ADVAPI32.151] */
1677 DWORD RegOpenKey32W(
1678 HKEY hkey,
1679 LPCWSTR lpszSubKey,
1680 LPHKEY retkey
1682 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1683 (LONG)hkey,W2C(lpszSubKey,0),retkey
1685 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1689 /* RegOpenKeyExA [ADVAPI32.149] */
1690 DWORD RegOpenKeyEx32A(
1691 HKEY hkey,
1692 LPCSTR lpszSubKey,
1693 DWORD dwReserved,
1694 REGSAM samDesired,
1695 LPHKEY retkey
1697 LPWSTR lpszSubKeyW;
1698 DWORD ret;
1700 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1701 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1703 if (lpszSubKey)
1704 lpszSubKeyW=strdupA2W(lpszSubKey);
1705 else
1706 lpszSubKeyW=NULL;
1707 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1708 if (lpszSubKeyW)
1709 free(lpszSubKeyW);
1710 return ret;
1713 /* RegOpenKeyA [ADVAPI32.148] */
1714 DWORD RegOpenKey32A(
1715 HKEY hkey,
1716 LPCSTR lpszSubKey,
1717 LPHKEY retkey
1719 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1720 (LONG)hkey,lpszSubKey,retkey
1722 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1725 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1726 DWORD RegOpenKey16(
1727 HKEY hkey,
1728 LPCSTR lpszSubKey,
1729 LPHKEY retkey
1731 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1732 (LONG)hkey,lpszSubKey,retkey
1734 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1738 * Create keys
1740 * All those functions convert their respective
1741 * arguments and call RegCreateKeyExW at the end.
1743 * FIXME: no security,no access attrib,no optionhandling yet.
1745 * Callpath:
1746 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1747 * RegCreateKey32W -> RegCreateKeyEx32W
1750 /* RegCreateKeyExW [ADVAPI32.131] */
1751 DWORD RegCreateKeyEx32W(
1752 HKEY hkey,
1753 LPCWSTR lpszSubKey,
1754 DWORD dwReserved,
1755 LPWSTR lpszClass,
1756 DWORD fdwOptions,
1757 REGSAM samDesired,
1758 LPSECURITY_ATTRIBUTES lpSecAttribs,
1759 LPHKEY retkey,
1760 LPDWORD lpDispos
1762 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1763 LPWSTR *wps;
1764 int wpc,i;
1766 /*FIXME: handle security/access/whatever */
1767 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1768 (LONG)hkey,
1769 W2C(lpszSubKey,0),
1770 dwReserved,
1771 W2C(lpszClass,1),
1772 fdwOptions,
1773 samDesired,
1774 lpSecAttribs,
1775 retkey,
1776 lpDispos
1779 lpNextKey = lookup_hkey(hkey);
1780 if (!lpNextKey)
1781 return SHELL_ERROR_BADKEY;
1782 if (!lpszSubKey || !*lpszSubKey) {
1783 add_handle(++currenthandle,lpNextKey,samDesired);
1784 *retkey=currenthandle;
1785 lpNextKey->flags|=REG_OPTION_TAINTED;
1786 return SHELL_ERROR_SUCCESS;
1788 split_keypath(lpszSubKey,&wps,&wpc);
1789 i = 0;
1790 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1791 lpxkey = lpNextKey;
1792 while (wps[i]) {
1793 lpxkey=lpNextKey->nextsub;
1794 while (lpxkey) {
1795 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1796 break;
1797 lpxkey=lpxkey->next;
1799 if (!lpxkey)
1800 break;
1801 i++;
1802 lpNextKey = lpxkey;
1804 if (lpxkey) {
1805 add_handle(++currenthandle,lpxkey,samDesired);
1806 lpxkey->flags |= REG_OPTION_TAINTED;
1807 *retkey = currenthandle;
1808 if (lpDispos)
1809 *lpDispos = REG_OPENED_EXISTING_KEY;
1810 FREE_KEY_PATH;
1811 return SHELL_ERROR_SUCCESS;
1813 /* good. now the hard part */
1814 while (wps[i]) {
1815 lplpPrevKey = &(lpNextKey->nextsub);
1816 lpxkey = *lplpPrevKey;
1817 while (lpxkey) {
1818 lplpPrevKey = &(lpxkey->next);
1819 lpxkey = *lplpPrevKey;
1821 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1822 if (!*lplpPrevKey) {
1823 FREE_KEY_PATH;
1824 return SHELL_ERROR_OUTOFMEMORY;
1826 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1827 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1828 (*lplpPrevKey)->next = NULL;
1829 (*lplpPrevKey)->nextsub = NULL;
1830 (*lplpPrevKey)->values = NULL;
1831 (*lplpPrevKey)->nrofvalues = 0;
1832 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1833 if (lpszClass)
1834 (*lplpPrevKey)->class = strdupW(lpszClass);
1835 else
1836 (*lplpPrevKey)->class = NULL;
1837 lpNextKey = *lplpPrevKey;
1838 i++;
1840 add_handle(++currenthandle,lpNextKey,samDesired);
1842 /*FIXME: flag handling correct? */
1843 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1844 if (lpszClass)
1845 lpNextKey->class = strdupW(lpszClass);
1846 else
1847 lpNextKey->class = NULL;
1848 *retkey = currenthandle;
1849 if (lpDispos)
1850 *lpDispos = REG_CREATED_NEW_KEY;
1851 FREE_KEY_PATH;
1852 return SHELL_ERROR_SUCCESS;
1855 /* RegCreateKeyW [ADVAPI32.132] */
1856 DWORD RegCreateKey32W(
1857 HKEY hkey,
1858 LPCWSTR lpszSubKey,
1859 LPHKEY retkey
1861 DWORD junk,ret;
1863 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1864 (LONG)hkey,W2C(lpszSubKey,0),retkey
1866 ret=RegCreateKeyEx32W(
1867 hkey, /* key handle */
1868 lpszSubKey, /* subkey name */
1869 0, /* reserved = 0 */
1870 NULL, /* lpszClass? FIXME: ? */
1871 REG_OPTION_NON_VOLATILE, /* options */
1872 KEY_ALL_ACCESS, /* desired access attribs */
1873 NULL, /* lpsecurity attributes */
1874 retkey, /* lpretkey */
1875 &junk /* disposition value */
1877 return ret;
1880 /* RegCreateKeyExA [ADVAPI32.130] */
1881 DWORD RegCreateKeyEx32A(
1882 HKEY hkey,
1883 LPCSTR lpszSubKey,
1884 DWORD dwReserved,
1885 LPSTR lpszClass,
1886 DWORD fdwOptions,
1887 REGSAM samDesired,
1888 LPSECURITY_ATTRIBUTES lpSecAttribs,
1889 LPHKEY retkey,
1890 LPDWORD lpDispos
1892 LPWSTR lpszSubKeyW,lpszClassW;
1893 DWORD ret;
1895 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1896 (LONG)hkey,
1897 lpszSubKey,
1898 dwReserved,
1899 lpszClass,
1900 fdwOptions,
1901 samDesired,
1902 lpSecAttribs,
1903 retkey,
1904 lpDispos
1906 if (lpszSubKey)
1907 lpszSubKeyW=strdupA2W(lpszSubKey);
1908 else
1909 lpszSubKeyW=NULL;
1910 if (lpszClass)
1911 lpszClassW=strdupA2W(lpszClass);
1912 else
1913 lpszClassW=NULL;
1914 ret=RegCreateKeyEx32W(
1915 hkey,
1916 lpszSubKeyW,
1917 dwReserved,
1918 lpszClassW,
1919 fdwOptions,
1920 samDesired,
1921 lpSecAttribs,
1922 retkey,
1923 lpDispos
1925 if (lpszSubKeyW)
1926 free(lpszSubKeyW);
1927 if (lpszClassW)
1928 free(lpszClassW);
1929 return ret;
1932 /* RegCreateKeyA [ADVAPI32.129] */
1933 DWORD RegCreateKey32A(
1934 HKEY hkey,
1935 LPCSTR lpszSubKey,
1936 LPHKEY retkey
1938 DWORD junk;
1940 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1941 (LONG)hkey,lpszSubKey,retkey
1943 return RegCreateKeyEx32A(
1944 hkey, /* key handle */
1945 lpszSubKey, /* subkey name */
1946 0, /* reserved = 0 */
1947 NULL, /* lpszClass? FIXME: ? */
1948 REG_OPTION_NON_VOLATILE,/* options */
1949 KEY_ALL_ACCESS, /* desired access attribs */
1950 NULL, /* lpsecurity attributes */
1951 retkey, /* lpretkey */
1952 &junk /* disposition value */
1956 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1957 DWORD RegCreateKey16(
1958 HKEY hkey,
1959 LPCSTR lpszSubKey,
1960 LPHKEY retkey
1962 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1963 (LONG)hkey,lpszSubKey,retkey
1965 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1969 * Query Value Functions
1970 * Win32 differs between keynames and valuenames.
1971 * multiple values may belong to one key, the special value
1972 * with name NULL is the default value used by the win31
1973 * compat functions.
1975 * Callpath:
1976 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1977 * RegQueryValue32W -> RegQueryValueEx32W
1980 /* RegQueryValueExW [ADVAPI32.158] */
1981 DWORD RegQueryValueEx32W(
1982 HKEY hkey,
1983 LPWSTR lpszValueName,
1984 LPDWORD lpdwReserved,
1985 LPDWORD lpdwType,
1986 LPBYTE lpbData,
1987 LPDWORD lpcbData
1989 LPKEYSTRUCT lpkey;
1990 int i;
1992 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1993 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1994 lpcbData?*lpcbData:0
1997 lpkey = lookup_hkey(hkey);
1998 if (!lpkey)
1999 return SHELL_ERROR_BADKEY;
2000 if (lpszValueName==NULL) {
2001 for (i=0;i<lpkey->nrofvalues;i++)
2002 if (lpkey->values[i].name==NULL)
2003 break;
2004 } else {
2005 for (i=0;i<lpkey->nrofvalues;i++)
2006 if ( lpkey->values[i].name &&
2007 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2009 break;
2011 if (i==lpkey->nrofvalues) {
2012 if (lpszValueName==NULL) {
2013 if (lpbData) {
2014 *(WCHAR*)lpbData = 0;
2015 *lpcbData = 2;
2017 if (lpdwType)
2018 *lpdwType = REG_SZ;
2019 return SHELL_ERROR_SUCCESS;
2021 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2023 if (lpdwType)
2024 *lpdwType = lpkey->values[i].type;
2025 if (lpbData==NULL) {
2026 if (lpcbData==NULL)
2027 return SHELL_ERROR_SUCCESS;
2028 *lpcbData = lpkey->values[i].len;
2029 return SHELL_ERROR_SUCCESS;
2031 if (*lpcbData<lpkey->values[i].len) {
2032 *(WCHAR*)lpbData
2033 = 0;
2034 *lpcbData = lpkey->values[i].len;
2035 return ERROR_MORE_DATA;
2037 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2038 *lpcbData = lpkey->values[i].len;
2039 return SHELL_ERROR_SUCCESS;
2042 /* RegQueryValueW [ADVAPI32.159] */
2043 DWORD RegQueryValue32W(
2044 HKEY hkey,
2045 LPWSTR lpszSubKey,
2046 LPWSTR lpszData,
2047 LPDWORD lpcbData
2049 HKEY xhkey;
2050 DWORD ret,lpdwType;
2052 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2053 hkey,W2C(lpszSubKey,0),lpszData,
2054 lpcbData?*lpcbData:0
2057 /* only open subkey, if we really do descend */
2058 if (lpszSubKey && *lpszSubKey) {
2059 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2060 if (ret!=ERROR_SUCCESS)
2061 return ret;
2062 } else
2063 xhkey = hkey;
2065 lpdwType = REG_SZ;
2066 ret = RegQueryValueEx32W(
2067 xhkey,
2068 NULL, /* varname NULL -> compat */
2069 NULL, /* lpdwReserved, must be NULL */
2070 &lpdwType,
2071 (LPBYTE)lpszData,
2072 lpcbData
2074 if (xhkey!=hkey)
2075 RegCloseKey(xhkey);
2076 return ret;
2079 /* RegQueryValueExA [ADVAPI32.157] */
2080 DWORD RegQueryValueEx32A(
2081 HKEY hkey,
2082 LPSTR lpszValueName,
2083 LPDWORD lpdwReserved,
2084 LPDWORD lpdwType,
2085 LPBYTE lpbData,
2086 LPDWORD lpcbData
2088 LPWSTR lpszValueNameW;
2089 LPBYTE buf;
2090 DWORD ret,myxlen;
2091 DWORD *mylen;
2092 DWORD type;
2094 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2095 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2096 lpcbData?*lpcbData:0
2098 if (lpbData) {
2099 /* double buffer */
2100 buf = (LPBYTE)xmalloc((*lpcbData)*2);
2101 myxlen = *lpcbData*2;
2102 mylen = &myxlen;
2103 } else {
2104 buf=NULL;
2105 if (lpcbData) {
2106 myxlen = *lpcbData*2;
2107 mylen = &myxlen;
2108 } else
2109 mylen = NULL;
2111 if (lpszValueName)
2112 lpszValueNameW=strdupA2W(lpszValueName);
2113 else
2114 lpszValueNameW=NULL;
2116 if (lpdwType)
2117 type=*lpdwType;
2118 ret=RegQueryValueEx32W(
2119 hkey,
2120 lpszValueNameW,
2121 lpdwReserved,
2122 &type,
2123 buf,
2124 mylen
2126 if (lpdwType)
2127 *lpdwType=type;
2128 if (ret==ERROR_SUCCESS) {
2129 if (buf) {
2130 if (UNICONVMASK & (1<<(type))) {
2131 /* convert UNICODE to ASCII */
2132 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2133 *lpcbData = myxlen/2;
2134 } else {
2135 if (myxlen>*lpcbData)
2136 ret = ERROR_MORE_DATA;
2137 else
2138 memcpy(lpbData,buf,myxlen);
2140 *lpcbData = myxlen;
2142 } else {
2143 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2144 *lpcbData = myxlen/2;
2146 } else {
2147 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2148 *lpcbData = myxlen/2;
2150 if (buf)
2151 free(buf);
2152 return ret;
2155 /* RegQueryValueEx [KERNEL.225] */
2156 DWORD RegQueryValueEx16(
2157 HKEY hkey,
2158 LPSTR lpszValueName,
2159 LPDWORD lpdwReserved,
2160 LPDWORD lpdwType,
2161 LPBYTE lpbData,
2162 LPDWORD lpcbData
2164 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2165 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2166 lpcbData?*lpcbData:0
2168 return RegQueryValueEx32A(
2169 hkey,
2170 lpszValueName,
2171 lpdwReserved,
2172 lpdwType,
2173 lpbData,
2174 lpcbData
2178 /* RegQueryValueA [ADVAPI32.156] */
2179 DWORD RegQueryValue32A(
2180 HKEY hkey,
2181 LPSTR lpszSubKey,
2182 LPSTR lpszData,
2183 LPDWORD lpcbData
2185 HKEY xhkey;
2186 DWORD ret,lpdwType;
2188 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2189 hkey,lpszSubKey,lpszData,
2190 lpcbData?*lpcbData:0
2193 /* only open subkey, if we really do descend */
2194 if (lpszSubKey && *lpszSubKey) {
2195 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2196 if (ret!=ERROR_SUCCESS)
2197 return ret;
2198 } else
2199 xhkey = hkey;
2201 lpdwType = REG_SZ;
2202 ret = RegQueryValueEx32A(
2203 xhkey,
2204 NULL, /* lpszValueName NULL -> compat */
2205 NULL, /* lpdwReserved, must be NULL */
2206 &lpdwType,
2207 (LPBYTE)lpszData,
2208 lpcbData
2210 if (xhkey!=hkey)
2211 RegCloseKey(xhkey);
2212 return ret;
2215 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2216 DWORD RegQueryValue16(
2217 HKEY hkey,
2218 LPSTR lpszSubKey,
2219 LPSTR lpszData,
2220 LPDWORD lpcbData
2222 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2223 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2225 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2226 * anyway, so we just mask out the high 16 bit.
2227 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2229 if (lpcbData)
2230 *lpcbData &= 0xFFFF;
2231 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2235 * Setting values of Registry keys
2237 * Callpath:
2238 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2239 * RegSetValue32W -> RegSetValueEx32W
2242 /* RegSetValueExW [ADVAPI32.170] */
2243 DWORD RegSetValueEx32W(
2244 HKEY hkey,
2245 LPWSTR lpszValueName,
2246 DWORD dwReserved,
2247 DWORD dwType,
2248 LPBYTE lpbData,
2249 DWORD cbData
2251 LPKEYSTRUCT lpkey;
2252 int i;
2254 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2255 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2257 /* we no longer care about the lpbData type here... */
2258 lpkey = lookup_hkey(hkey);
2259 if (!lpkey)
2260 return SHELL_ERROR_BADKEY;
2262 lpkey->flags |= REG_OPTION_TAINTED;
2264 if (lpszValueName==NULL) {
2265 for (i=0;i<lpkey->nrofvalues;i++)
2266 if (lpkey->values[i].name==NULL)
2267 break;
2268 } else {
2269 for (i=0;i<lpkey->nrofvalues;i++)
2270 if ( lpkey->values[i].name &&
2271 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2273 break;
2275 if (i==lpkey->nrofvalues) {
2276 lpkey->values = (LPKEYVALUE)xrealloc(
2277 lpkey->values,
2278 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2280 lpkey->nrofvalues++;
2281 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2283 if (lpkey->values[i].name==NULL)
2284 if (lpszValueName)
2285 lpkey->values[i].name = strdupW(lpszValueName);
2286 else
2287 lpkey->values[i].name = NULL;
2288 lpkey->values[i].len = cbData;
2289 lpkey->values[i].type = dwType;
2290 if (lpkey->values[i].data !=NULL)
2291 free(lpkey->values[i].data);
2292 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2293 lpkey->values[i].lastmodified = time(NULL);
2294 memcpy(lpkey->values[i].data,lpbData,cbData);
2295 return SHELL_ERROR_SUCCESS;
2298 /* RegSetValueExA [ADVAPI32.169] */
2299 DWORD RegSetValueEx32A(
2300 HKEY hkey,
2301 LPSTR lpszValueName,
2302 DWORD dwReserved,
2303 DWORD dwType,
2304 LPBYTE lpbData,
2305 DWORD cbData
2307 LPBYTE buf;
2308 LPWSTR lpszValueNameW;
2309 DWORD ret;
2311 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2312 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2314 if ((1<<dwType) & UNICONVMASK) {
2315 buf=(LPBYTE)strdupA2W(lpbData);
2316 cbData=2*strlen(lpbData)+2;
2317 } else
2318 buf=lpbData;
2319 if (lpszValueName)
2320 lpszValueNameW = strdupA2W(lpszValueName);
2321 else
2322 lpszValueNameW = NULL;
2323 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2324 if (lpszValueNameW)
2325 free(lpszValueNameW);
2326 if (buf!=lpbData)
2327 free(buf);
2328 return ret;
2331 /* RegSetValueEx [KERNEL.226] */
2332 DWORD RegSetValueEx16(
2333 HKEY hkey,
2334 LPSTR lpszValueName,
2335 DWORD dwReserved,
2336 DWORD dwType,
2337 LPBYTE lpbData,
2338 DWORD cbData
2340 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2341 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2343 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2346 /* RegSetValueW [ADVAPI32.171] */
2347 DWORD RegSetValue32W(
2348 HKEY hkey,
2349 LPCWSTR lpszSubKey,
2350 DWORD dwType,
2351 LPCWSTR lpszData,
2352 DWORD cbData
2354 HKEY xhkey;
2355 DWORD ret;
2357 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2358 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2360 if (lpszSubKey && *lpszSubKey) {
2361 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2362 if (ret!=ERROR_SUCCESS)
2363 return ret;
2364 } else
2365 xhkey=hkey;
2366 if (dwType!=REG_SZ) {
2367 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2368 dwType=REG_SZ;
2370 if (cbData!=2*lstrlen32W(lpszData)+2) {
2371 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2372 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2374 cbData=2*lstrlen32W(lpszData)+2;
2376 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2377 if (hkey!=xhkey)
2378 RegCloseKey(xhkey);
2379 return ret;
2382 /* RegSetValueA [ADVAPI32.168] */
2383 DWORD RegSetValue32A(
2384 HKEY hkey,
2385 LPCSTR lpszSubKey,
2386 DWORD dwType,
2387 LPCSTR lpszData,
2388 DWORD cbData
2390 DWORD ret;
2391 HKEY xhkey;
2393 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2394 hkey,lpszSubKey,dwType,lpszData,cbData
2396 if (lpszSubKey && *lpszSubKey) {
2397 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2398 if (ret!=ERROR_SUCCESS)
2399 return ret;
2400 } else
2401 xhkey=hkey;
2403 if (dwType!=REG_SZ) {
2404 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2405 dwType=REG_SZ;
2407 if (cbData!=strlen(lpszData)+1)
2408 cbData=strlen(lpszData)+1;
2409 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2410 if (xhkey!=hkey)
2411 RegCloseKey(xhkey);
2412 return ret;
2415 /* RegSetValue [KERNEL.221] [SHELL.5] */
2416 DWORD RegSetValue16(
2417 HKEY hkey,
2418 LPCSTR lpszSubKey,
2419 DWORD dwType,
2420 LPCSTR lpszData,
2421 DWORD cbData
2423 DWORD ret;
2424 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2425 hkey,lpszSubKey,dwType,lpszData,cbData
2427 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2428 return ret;
2432 * Key Enumeration
2434 * Callpath:
2435 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2436 * RegEnumKey32W -> RegEnumKeyEx32W
2439 /* RegEnumKeyExW [ADVAPI32.139] */
2440 DWORD RegEnumKeyEx32W(
2441 HKEY hkey,
2442 DWORD iSubkey,
2443 LPWSTR lpszName,
2444 LPDWORD lpcchName,
2445 LPDWORD lpdwReserved,
2446 LPWSTR lpszClass,
2447 LPDWORD lpcchClass,
2448 FILETIME *ft
2450 LPKEYSTRUCT lpkey,lpxkey;
2452 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2453 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2455 lpkey=lookup_hkey(hkey);
2456 if (!lpkey)
2457 return SHELL_ERROR_BADKEY;
2458 if (!lpkey->nextsub)
2459 return ERROR_NO_MORE_ITEMS;
2460 lpxkey=lpkey->nextsub;
2461 while (iSubkey && lpxkey) {
2462 iSubkey--;
2463 lpxkey=lpxkey->next;
2465 if (iSubkey || !lpxkey)
2466 return ERROR_NO_MORE_ITEMS;
2467 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2468 return ERROR_MORE_DATA;
2469 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2470 if (lpszClass) {
2471 /* what should we write into it? */
2472 *lpszClass = 0;
2473 *lpcchClass = 2;
2475 return ERROR_SUCCESS;
2479 /* RegEnumKeyW [ADVAPI32.140] */
2480 DWORD RegEnumKey32W(
2481 HKEY hkey,
2482 DWORD iSubkey,
2483 LPWSTR lpszName,
2484 DWORD lpcchName
2486 FILETIME ft;
2488 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2489 hkey,iSubkey,lpszName,lpcchName
2491 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2493 /* RegEnumKeyExA [ADVAPI32.138] */
2494 DWORD RegEnumKeyEx32A(
2495 HKEY hkey,
2496 DWORD iSubkey,
2497 LPSTR lpszName,
2498 LPDWORD lpcchName,
2499 LPDWORD lpdwReserved,
2500 LPSTR lpszClass,
2501 LPDWORD lpcchClass,
2502 FILETIME *ft
2504 DWORD ret,lpcchNameW,lpcchClassW;
2505 LPWSTR lpszNameW,lpszClassW;
2508 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2509 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2511 if (lpszName) {
2512 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2513 lpcchNameW = *lpcchName*2;
2514 } else {
2515 lpszNameW = NULL;
2516 lpcchNameW = 0;
2518 if (lpszClass) {
2519 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2520 lpcchClassW = *lpcchClass*2;
2521 } else {
2522 lpszClassW =0;
2523 lpcchClassW=0;
2525 ret=RegEnumKeyEx32W(
2526 hkey,
2527 iSubkey,
2528 lpszNameW,
2529 &lpcchNameW,
2530 lpdwReserved,
2531 lpszClassW,
2532 &lpcchClassW,
2535 if (ret==ERROR_SUCCESS) {
2536 lstrcpyWtoA(lpszName,lpszNameW);
2537 *lpcchName=strlen(lpszName);
2538 if (lpszClassW) {
2539 lstrcpyWtoA(lpszClass,lpszClassW);
2540 *lpcchClass=strlen(lpszClass);
2543 if (lpszNameW)
2544 free(lpszNameW);
2545 if (lpszClassW)
2546 free(lpszClassW);
2547 return ret;
2550 /* RegEnumKeyA [ADVAPI32.137] */
2551 DWORD RegEnumKey32A(
2552 HKEY hkey,
2553 DWORD iSubkey,
2554 LPSTR lpszName,
2555 DWORD lpcchName
2557 FILETIME ft;
2559 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2560 hkey,iSubkey,lpszName,lpcchName
2562 return RegEnumKeyEx32A(
2563 hkey,
2564 iSubkey,
2565 lpszName,
2566 &lpcchName,
2567 NULL,
2568 NULL,
2569 NULL,
2574 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2575 DWORD RegEnumKey16(
2576 HKEY hkey,
2577 DWORD iSubkey,
2578 LPSTR lpszName,
2579 DWORD lpcchName
2581 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2582 hkey,iSubkey,lpszName,lpcchName
2584 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2588 * Enumerate Registry Values
2590 * Callpath:
2591 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2594 /* RegEnumValueW [ADVAPI32.142] */
2595 DWORD RegEnumValue32W(
2596 HKEY hkey,
2597 DWORD iValue,
2598 LPWSTR lpszValue,
2599 LPDWORD lpcchValue,
2600 LPDWORD lpdReserved,
2601 LPDWORD lpdwType,
2602 LPBYTE lpbData,
2603 LPDWORD lpcbData
2605 LPKEYSTRUCT lpkey;
2606 LPKEYVALUE val;
2608 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2609 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2611 lpkey = lookup_hkey(hkey);
2612 if (!lpkey)
2613 return SHELL_ERROR_BADKEY;
2614 if (lpkey->nrofvalues<=iValue)
2615 return ERROR_NO_MORE_ITEMS;
2616 val = lpkey->values+iValue;
2618 if (val->name) {
2619 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2620 *lpcchValue = lstrlen32W(val->name)*2+2;
2621 return ERROR_MORE_DATA;
2623 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2624 *lpcchValue=lstrlen32W(val->name)*2+2;
2625 } else {
2626 /* how to handle NULL value? */
2627 *lpszValue = 0;
2628 *lpcchValue = 2;
2630 *lpdwType=val->type;
2631 if (lpbData) {
2632 if (val->len>*lpcbData)
2633 return ERROR_MORE_DATA;
2634 memcpy(lpbData,val->data,val->len);
2635 *lpcbData = val->len;
2637 return SHELL_ERROR_SUCCESS;
2640 /* RegEnumValueA [ADVAPI32.141] */
2641 DWORD RegEnumValue32A(
2642 HKEY hkey,
2643 DWORD iValue,
2644 LPSTR lpszValue,
2645 LPDWORD lpcchValue,
2646 LPDWORD lpdReserved,
2647 LPDWORD lpdwType,
2648 LPBYTE lpbData,
2649 LPDWORD lpcbData
2651 LPWSTR lpszValueW;
2652 LPBYTE lpbDataW;
2653 DWORD ret,lpcbDataW;
2655 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2656 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2659 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2660 if (lpbData) {
2661 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2662 lpcbDataW = *lpcbData*2;
2663 } else
2664 lpbDataW = NULL;
2665 ret=RegEnumValue32W(
2666 hkey,
2667 iValue,
2668 lpszValueW,
2669 lpcchValue,
2670 lpdReserved,
2671 lpdwType,
2672 lpbDataW,
2673 &lpcbDataW
2676 if (ret==ERROR_SUCCESS) {
2677 lstrcpyWtoA(lpszValue,lpszValueW);
2678 if (lpbData) {
2679 if ((1<<*lpdwType) & UNICONVMASK) {
2680 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2681 } else {
2682 if (lpcbDataW > *lpcbData)
2683 ret = ERROR_MORE_DATA;
2684 else
2685 memcpy(lpbData,lpbDataW,lpcbDataW);
2687 *lpcbData = lpcbDataW;
2690 if (lpbDataW)
2691 free(lpbDataW);
2692 if (lpszValueW)
2693 free(lpszValueW);
2694 return ret;
2697 /* RegEnumValue [KERNEL.223] */
2698 DWORD RegEnumValue16(
2699 HKEY hkey,
2700 DWORD iValue,
2701 LPSTR lpszValue,
2702 LPDWORD lpcchValue,
2703 LPDWORD lpdReserved,
2704 LPDWORD lpdwType,
2705 LPBYTE lpbData,
2706 LPDWORD lpcbData
2708 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2709 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2711 return RegEnumValue32A(
2712 hkey,
2713 iValue,
2714 lpszValue,
2715 lpcchValue,
2716 lpdReserved,
2717 lpdwType,
2718 lpbData,
2719 lpcbData
2724 * Close registry key
2726 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2727 DWORD RegCloseKey(HKEY hkey) {
2728 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2729 remove_handle(hkey);
2730 return ERROR_SUCCESS;
2733 * Delete registry key
2735 * Callpath:
2736 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2738 /* RegDeleteKeyW [ADVAPI32.134] */
2739 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2740 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2741 LPWSTR *wps;
2742 int wpc,i;
2744 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2745 hkey,W2C(lpszSubKey,0)
2747 lpNextKey = lookup_hkey(hkey);
2748 if (!lpNextKey)
2749 return SHELL_ERROR_BADKEY;
2750 /* we need to know the previous key in the hier. */
2751 if (!lpszSubKey || !*lpszSubKey)
2752 return SHELL_ERROR_BADKEY;
2753 split_keypath(lpszSubKey,&wps,&wpc);
2754 i = 0;
2755 lpxkey = lpNextKey;
2756 while (i<wpc-1) {
2757 lpxkey=lpNextKey->nextsub;
2758 while (lpxkey) {
2759 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2760 break;
2761 lpxkey=lpxkey->next;
2763 if (!lpxkey) {
2764 FREE_KEY_PATH;
2765 /* not found is success */
2766 return SHELL_ERROR_SUCCESS;
2768 i++;
2769 lpNextKey = lpxkey;
2771 lpxkey = lpNextKey->nextsub;
2772 lplpPrevKey = &(lpNextKey->nextsub);
2773 while (lpxkey) {
2774 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2775 break;
2776 lplpPrevKey = &(lpxkey->next);
2777 lpxkey = lpxkey->next;
2779 if (!lpxkey)
2780 return SHELL_ERROR_SUCCESS;
2781 if (lpxkey->nextsub)
2782 return SHELL_ERROR_CANTWRITE;
2783 *lplpPrevKey = lpxkey->next;
2784 free(lpxkey->keyname);
2785 if (lpxkey->class)
2786 free(lpxkey->class);
2787 if (lpxkey->values)
2788 free(lpxkey->values);
2789 free(lpxkey);
2790 FREE_KEY_PATH;
2791 return SHELL_ERROR_SUCCESS;
2794 /* RegDeleteKeyA [ADVAPI32.133] */
2795 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2796 LPWSTR lpszSubKeyW;
2797 DWORD ret;
2799 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2800 hkey,lpszSubKey
2802 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2803 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2804 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2805 return ret;
2808 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2809 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2810 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2811 hkey,lpszSubKey
2813 return RegDeleteKey32A(hkey,lpszSubKey);
2817 * Delete registry value
2819 * Callpath:
2820 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2822 /* RegDeleteValueW [ADVAPI32.136] */
2823 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2824 DWORD i;
2825 LPKEYSTRUCT lpkey;
2826 LPKEYVALUE val;
2828 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2829 hkey,W2C(lpszValue,0)
2831 lpkey=lookup_hkey(hkey);
2832 if (!lpkey)
2833 return SHELL_ERROR_BADKEY;
2834 if (lpszValue) {
2835 for (i=0;i<lpkey->nrofvalues;i++)
2836 if ( lpkey->values[i].name &&
2837 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2839 break;
2840 } else {
2841 for (i=0;i<lpkey->nrofvalues;i++)
2842 if (lpkey->values[i].name==NULL)
2843 break;
2845 if (i==lpkey->nrofvalues)
2846 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2847 val = lpkey->values+i;
2848 if (val->name) free(val->name);
2849 if (val->data) free(val->data);
2850 memcpy(
2851 lpkey->values+i,
2852 lpkey->values+i+1,
2853 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2855 lpkey->values = (LPKEYVALUE)xrealloc(
2856 lpkey->values,
2857 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2859 lpkey->nrofvalues--;
2860 return SHELL_ERROR_SUCCESS;
2863 /* RegDeleteValueA [ADVAPI32.135] */
2864 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2865 LPWSTR lpszValueW;
2866 DWORD ret;
2868 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2869 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2870 ret=RegDeleteValue32W(hkey,lpszValueW);
2871 HeapFree(GetProcessHeap(),0,lpszValueW);
2872 return ret;
2875 /* RegDeleteValue [KERNEL.222] */
2876 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2877 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2878 return RegDeleteValue32A(hkey,lpszValue);
2881 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2882 DWORD RegFlushKey(HKEY hkey) {
2883 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2884 return SHELL_ERROR_SUCCESS;
2887 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2889 /* RegQueryInfoKeyW [ADVAPI32.153] */
2890 DWORD RegQueryInfoKey32W(
2891 HKEY hkey,
2892 LPWSTR lpszClass,
2893 LPDWORD lpcchClass,
2894 LPDWORD lpdwReserved,
2895 LPDWORD lpcSubKeys,
2896 LPDWORD lpcchMaxSubkey,
2897 LPDWORD lpcchMaxClass,
2898 LPDWORD lpcValues,
2899 LPDWORD lpcchMaxValueName,
2900 LPDWORD lpccbMaxValueData,
2901 LPDWORD lpcbSecurityDescriptor,
2902 FILETIME *ft
2904 LPKEYSTRUCT lpkey,lpxkey;
2905 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2906 int i;
2908 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2909 lpkey=lookup_hkey(hkey);
2910 if (!lpkey)
2911 return SHELL_ERROR_BADKEY;
2912 if (lpszClass) {
2913 if (lpkey->class) {
2914 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2915 *lpcchClass=lstrlen32W(lpkey->class)*2;
2916 return ERROR_MORE_DATA;
2918 *lpcchClass=lstrlen32W(lpkey->class)*2;
2919 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2920 } else {
2921 *lpszClass = 0;
2922 *lpcchClass = 0;
2924 } else {
2925 if (lpcchClass)
2926 *lpcchClass = lstrlen32W(lpkey->class)*2;
2928 lpxkey=lpkey->nextsub;
2929 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2930 while (lpxkey) {
2931 nrofkeys++;
2932 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2933 maxsubkey=lstrlen32W(lpxkey->keyname);
2934 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2935 maxclass=lstrlen32W(lpxkey->class);
2936 if (lpxkey->nrofvalues>maxvalues)
2937 maxvalues=lpxkey->nrofvalues;
2938 for (i=0;i<lpxkey->nrofvalues;i++) {
2939 LPKEYVALUE val=lpxkey->values+i;
2941 if (val->name && lstrlen32W(val->name)>maxvname)
2942 maxvname=lstrlen32W(val->name);
2943 if (val->len>maxvdata)
2944 maxvdata=val->len;
2946 lpxkey=lpxkey->next;
2948 if (!maxclass) maxclass = 1;
2949 if (!maxvname) maxvname = 1;
2950 if (lpcSubKeys)
2951 *lpcSubKeys = nrofkeys;
2952 if (lpcchMaxSubkey)
2953 *lpcchMaxSubkey = maxsubkey*2;
2954 if (lpcchMaxClass)
2955 *lpcchMaxClass = maxclass*2;
2956 if (lpcValues)
2957 *lpcValues = maxvalues;
2958 if (lpcchMaxValueName)
2959 *lpcchMaxValueName= maxvname;
2960 if (lpccbMaxValueData)
2961 *lpccbMaxValueData= maxvdata;
2962 return SHELL_ERROR_SUCCESS;
2965 /* RegQueryInfoKeyA [ADVAPI32.152] */
2966 DWORD RegQueryInfoKey32A(
2967 HKEY hkey,
2968 LPSTR lpszClass,
2969 LPDWORD lpcchClass,
2970 LPDWORD lpdwReserved,
2971 LPDWORD lpcSubKeys,
2972 LPDWORD lpcchMaxSubkey,
2973 LPDWORD lpcchMaxClass,
2974 LPDWORD lpcValues,
2975 LPDWORD lpcchMaxValueName,
2976 LPDWORD lpccbMaxValueData,
2977 LPDWORD lpcbSecurityDescriptor,
2978 FILETIME *ft
2980 LPWSTR lpszClassW;
2981 DWORD ret;
2983 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2984 if (lpszClass) {
2985 *lpcchClass*= 2;
2986 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2988 } else
2989 lpszClassW = NULL;
2990 ret=RegQueryInfoKey32W(
2991 hkey,
2992 lpszClassW,
2993 lpcchClass,
2994 lpdwReserved,
2995 lpcSubKeys,
2996 lpcchMaxSubkey,
2997 lpcchMaxClass,
2998 lpcValues,
2999 lpcchMaxValueName,
3000 lpccbMaxValueData,
3001 lpcbSecurityDescriptor,
3004 if (ret==ERROR_SUCCESS)
3005 lstrcpyWtoA(lpszClass,lpszClassW);
3006 if (lpcchClass)
3007 *lpcchClass/=2;
3008 if (lpcchMaxSubkey)
3009 *lpcchMaxSubkey/=2;
3010 if (lpcchMaxClass)
3011 *lpcchMaxClass/=2;
3012 if (lpcchMaxValueName)
3013 *lpcchMaxValueName/=2;
3014 if (lpszClassW)
3015 free(lpszClassW);
3016 return ret;
3018 /* RegConnectRegistryA [ADVAPI32.127] */
3019 DWORD RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey) {
3020 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
3021 machine,hkey,reskey
3023 return ERROR_FILE_NOT_FOUND; /* FIXME */