Release 971012
[wine/multimedia.git] / misc / registry.c
blobe14b342a8955240d454d49fff48d217385966128
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/fcntl.h>
15 #include <sys/stat.h>
16 #include <pwd.h>
17 #include <time.h>
18 #include "windows.h"
19 #include "win.h"
20 #include "winerror.h"
21 #include "file.h"
22 #include "heap.h"
23 #include "string32.h"
24 #include "stddebug.h"
25 #include "debug.h"
26 #include "xmalloc.h"
27 #include "winreg.h"
29 /* FIXME: following defines should be configured global ... */
31 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
32 #define WINE_PREFIX "/.wine"
33 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
34 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
36 /* relative in ~user/.wine/ : */
37 #define SAVE_CURRENT_USER "user.reg"
38 #define SAVE_LOCAL_MACHINE "system.reg"
40 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
41 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
43 /* one value of a key */
44 typedef struct tagKEYVALUE
46 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
47 DWORD type; /* type of value */
48 DWORD len; /* length of data */
49 DWORD lastmodified; /* time of seconds since 1.1.1970 */
50 LPBYTE data; /* content, may be strings, binaries, etc. */
51 } KEYVALUE,*LPKEYVALUE;
53 /* a registry key */
54 typedef struct tagKEYSTRUCT
56 LPWSTR keyname; /* name of THIS key (UNICODE) */
57 DWORD flags; /* flags. */
58 LPWSTR class;
59 /* values */
60 DWORD nrofvalues; /* nr of values in THIS key */
61 LPKEYVALUE values; /* values in THIS key */
62 /* key management pointers */
63 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
64 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
65 } KEYSTRUCT, *LPKEYSTRUCT;
68 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
69 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
70 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
71 static KEYSTRUCT *key_users=NULL; /* all users? */
73 /* dynamic, not saved */
74 static KEYSTRUCT *key_performance_data=NULL;
75 static KEYSTRUCT *key_current_config=NULL;
76 static KEYSTRUCT *key_dyn_data=NULL;
78 /* what valuetypes do we need to convert? */
79 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
81 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
82 #define strdupW(x) STRING32_strdupW(x)
83 #define strchrW(a,c) STRING32_lstrchrW(a,c)
85 static struct openhandle {
86 LPKEYSTRUCT lpkey;
87 HKEY hkey;
88 REGSAM accessmask;
89 } *openhandles=NULL;
90 static int nrofopenhandles=0;
91 static int currenthandle=1;
93 static void
94 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
95 int i;
97 for (i=0;i<nrofopenhandles;i++) {
98 if (openhandles[i].lpkey==lpkey) {
99 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
101 if (openhandles[i].hkey==hkey) {
102 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
105 openhandles=xrealloc( openhandles,
106 sizeof(struct openhandle)*(nrofopenhandles+1)
108 openhandles[i].lpkey = lpkey;
109 openhandles[i].hkey = hkey;
110 openhandles[i].accessmask= accessmask;
111 nrofopenhandles++;
114 static LPKEYSTRUCT
115 get_handle(HKEY hkey) {
116 int i;
118 for (i=0;i<nrofopenhandles;i++)
119 if (openhandles[i].hkey==hkey)
120 return openhandles[i].lpkey;
121 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
122 return NULL;
125 static void
126 remove_handle(HKEY hkey) {
127 int i;
129 for (i=0;i<nrofopenhandles;i++)
130 if (openhandles[i].hkey==hkey)
131 break;
132 if (i==nrofopenhandles) {
133 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
134 return;
136 memcpy( openhandles+i,
137 openhandles+i+1,
138 sizeof(struct openhandle)*(nrofopenhandles-i-1)
140 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
141 nrofopenhandles--;
142 return;
146 /* debug function, converts a unicode into a static memory area
147 * (sub for using two static strings, in case we need them in a single call)
149 LPSTR
150 W2C(LPCWSTR x,int sub) {
151 static LPSTR unicodedebug[2]={NULL,NULL};
152 if (x==NULL)
153 return "<NULL>";
154 if (sub!=0 && sub!=1)
155 return "<W2C:bad sub>";
156 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
157 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
158 return unicodedebug[sub];
161 static LPKEYSTRUCT
162 lookup_hkey(HKEY hkey) {
163 switch (hkey) {
164 case 0x00000000:
165 case 0x00000001:
166 case HKEY_CLASSES_ROOT:
167 return key_classes_root;
168 case HKEY_CURRENT_USER:
169 return key_current_user;
170 case HKEY_LOCAL_MACHINE:
171 return key_local_machine;
172 case HKEY_USERS:
173 return key_users;
174 case HKEY_PERFORMANCE_DATA:
175 return key_performance_data;
176 case HKEY_DYN_DATA:
177 return key_dyn_data;
178 case HKEY_CURRENT_CONFIG:
179 return key_current_config;
180 default:
181 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
182 (LONG)hkey
184 return get_handle(hkey);
186 /*NOTREACHED*/
190 * splits the unicode string 'wp' into an array of strings.
191 * the array is allocated by this function.
192 * the number of components will be stored in 'wpc'
193 * Free the array using FREE_KEY_PATH
195 static void
196 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
197 int i,j,len;
198 LPWSTR ws;
200 ws = HEAP_strdupW( SystemHeap, 0, wp );
201 *wpc = 1;
202 for (i=0;ws[i];i++) {
203 if (ws[i]=='\\') {
204 ws[i]=0;
205 (*wpc)++;
208 len = i;
209 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
210 (*wpv)[0]= ws;
211 j = 1;
212 for (i=1;i<len;i++)
213 if (ws[i-1]==0)
214 (*wpv)[j++]=ws+i;
215 (*wpv)[j]=NULL;
217 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
220 * Shell initialisation, allocates keys.
222 void SHELL_StartupRegistry();
223 void
224 SHELL_Init() {
225 struct passwd *pwd;
227 HKEY cl_r_hkey,c_u_hkey;
228 #define ADD_ROOT_KEY(xx) \
229 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
230 memset(xx,'\0',sizeof(KEYSTRUCT));\
231 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
233 ADD_ROOT_KEY(key_local_machine);
234 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
235 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
236 exit(1);
238 key_classes_root = lookup_hkey(cl_r_hkey);
240 ADD_ROOT_KEY(key_users);
242 #if 0
243 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
244 * (later, when a win32 registry editing tool becomes avail.)
246 while (pwd=getpwent()) {
247 if (pwd->pw_name == NULL)
248 continue;
249 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
250 RegCloseKey(c_u_hkey);
252 #endif
253 pwd=getpwuid(getuid());
254 if (pwd && pwd->pw_name) {
255 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
256 key_current_user = lookup_hkey(c_u_hkey);
257 } else {
258 ADD_ROOT_KEY(key_current_user);
260 ADD_ROOT_KEY(key_performance_data);
261 ADD_ROOT_KEY(key_current_config);
262 ADD_ROOT_KEY(key_dyn_data);
263 #undef ADD_ROOT_KEY
264 SHELL_StartupRegistry();
268 void
269 SHELL_StartupRegistry() {
270 HKEY hkey,xhkey=0;
271 FILE *F;
272 char buf[200],cpubuf[200];
274 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
275 RegCloseKey(xhkey);
276 xhkey = 0;
277 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
278 #ifdef linux
279 F=fopen("/proc/cpuinfo","r");
280 if (F) {
281 int procnr=-1,x;
282 while (NULL!=fgets(buf,200,F)) {
283 if (sscanf(buf,"processor\t: %d",&x)) {
284 sprintf(buf,"%d",x);
285 if (xhkey)
286 RegCloseKey(xhkey);
287 procnr=x;
288 RegCreateKey16(hkey,buf,&xhkey);
290 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
291 sprintf(buf,"CPU %s",cpubuf);
292 if (xhkey)
293 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
296 fclose(F);
298 if (xhkey)
299 RegCloseKey(xhkey);
300 RegCloseKey(hkey);
301 #else
302 /* FIXME */
303 RegCreateKey16(hkey,"0",&xhkey);
304 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
305 #endif
306 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
307 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
308 RegCloseKey(hkey);
309 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
310 * CurrentVersion
311 * CurrentBuildNumber
312 * CurrentType
313 * string RegisteredOwner
314 * string RegisteredOrganization
317 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
318 * string SysContact
319 * string SysLocation
320 * SysServices
322 if (-1!=gethostname(buf,200)) {
323 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
324 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
325 RegCloseKey(xhkey);
328 /************************ SAVE Registry Function ****************************/
330 #define REGISTRY_SAVE_VERSION 0x00000001
332 /* Registry saveformat:
333 * If you change it, increase above number by 1, which will flush
334 * old registry database files.
336 * Global:
337 * "WINE REGISTRY Version %d"
338 * subkeys....
339 * Subkeys:
340 * keyname
341 * valuename=lastmodified,type,data
342 * ...
343 * subkeys
344 * ...
345 * keyname,valuename,stringdata:
346 * the usual ascii characters from 0x00-0xff (well, not 0x00)
347 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
348 * ( "=\\\t" escaped in \uXXXX form.)
349 * type,lastmodified:
350 * int
352 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
354 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
355 * SaveOnlyUpdatedKeys=yes
357 static int
358 _save_check_tainted(LPKEYSTRUCT lpkey) {
359 int tainted;
361 if (!lpkey)
362 return 0;
363 if (lpkey->flags & REG_OPTION_TAINTED)
364 tainted = 1;
365 else
366 tainted = 0;
367 while (lpkey) {
368 if (_save_check_tainted(lpkey->nextsub)) {
369 lpkey->flags |= REG_OPTION_TAINTED;
370 tainted = 1;
372 lpkey = lpkey->next;
374 return tainted;
377 static void
378 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
379 LPWSTR s;
380 int doescape;
382 if (wstr==NULL)
383 return;
384 s=wstr;
385 while (*s) {
386 doescape=0;
387 if (*s>0xff)
388 doescape = 1;
389 if (*s=='\n')
390 doescape = 1;
391 if (escapeeq && *s=='=')
392 doescape = 1;
393 if (*s=='\\')
394 fputc(*s,F); /* if \\ then put it twice. */
395 if (doescape)
396 fprintf(F,"\\u%04x",*((unsigned short*)s));
397 else
398 fputc(*s,F);
399 s++;
403 static int
404 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
405 LPKEYSTRUCT lpxkey;
406 int i,tabs,j;
408 lpxkey = lpkey;
409 while (lpxkey) {
410 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
411 (all || (lpxkey->flags & REG_OPTION_TAINTED))
413 for (tabs=level;tabs--;)
414 fputc('\t',F);
415 _save_USTRING(F,lpxkey->keyname,1);
416 fputs("\n",F);
417 for (i=0;i<lpxkey->nrofvalues;i++) {
418 LPKEYVALUE val=lpxkey->values+i;
420 for (tabs=level+1;tabs--;)
421 fputc('\t',F);
422 _save_USTRING(F,val->name,0);
423 fputc('=',F);
424 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
425 if ((1<<val->type) & UNICONVMASK)
426 _save_USTRING(F,(LPWSTR)val->data,0);
427 else
428 for (j=0;j<val->len;j++)
429 fprintf(F,"%02x",*((unsigned char*)val->data+j));
430 fputs("\n",F);
432 /* descend recursively */
433 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
434 return 0;
436 lpxkey=lpxkey->next;
438 return 1;
441 static int
442 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
443 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
444 _save_check_tainted(lpkey->nextsub);
445 return _savesubkey(F,lpkey->nextsub,0,all);
448 static BOOL32
449 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
450 FILE *F;
452 F=fopen(fn,"w");
453 if (F==NULL) {
454 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
455 fn,strerror(errno)
457 return FALSE;
459 if (!_savesubreg(F,lpkey,all)) {
460 fclose(F);
461 unlink(fn);
462 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
463 return FALSE;
465 fclose(F);
466 return TRUE;
469 void
470 SHELL_SaveRegistry() {
471 char *fn;
472 struct passwd *pwd;
473 char buf[4];
474 HKEY hkey;
475 int all;
477 all=0;
478 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
479 strcpy(buf,"yes");
480 } else {
481 DWORD len,junk,type;
483 len=4;
484 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
485 hkey,
486 VAL_SAVEUPDATED,
487 &junk,
488 &type,
489 buf,
490 &len
491 ))|| (type!=REG_SZ)
493 strcpy(buf,"yes");
494 RegCloseKey(hkey);
496 if (lstrcmpi32A(buf,"yes"))
497 all=1;
498 pwd=getpwuid(getuid());
499 if (pwd!=NULL && pwd->pw_dir!=NULL)
501 char *tmp;
503 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
504 strlen(SAVE_CURRENT_USER) + 2 );
505 strcpy(fn,pwd->pw_dir);
506 strcat(fn,WINE_PREFIX);
507 /* create the directory. don't care about errorcodes. */
508 mkdir(fn,0755); /* drwxr-xr-x */
509 strcat(fn,"/"SAVE_CURRENT_USER);
510 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
511 strcpy(tmp,fn);strcat(tmp,".tmp");
512 if (_savereg(key_current_user,tmp,all)) {
513 if (-1==rename(tmp,fn)) {
514 perror("rename tmp registry");
515 unlink(tmp);
518 free(tmp);
519 free(fn);
520 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
521 strcpy(fn,pwd->pw_dir);
522 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
523 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
524 strcpy(tmp,fn);strcat(tmp,".tmp");
525 if (_savereg(key_local_machine,tmp,all)) {
526 if (-1==rename(tmp,fn)) {
527 perror("rename tmp registry");
528 unlink(tmp);
531 free(tmp);
532 free(fn);
533 } else
534 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
537 /************************ LOAD Registry Function ****************************/
539 static LPKEYSTRUCT
540 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
541 LPKEYSTRUCT lpxkey,*lplpkey;
543 lplpkey= &(lpkey->nextsub);
544 lpxkey = *lplpkey;
545 while (lpxkey) {
546 if (!lstrcmpi32W(lpxkey->keyname,keyname))
547 break;
548 lplpkey = &(lpxkey->next);
549 lpxkey = *lplpkey;
551 if (lpxkey==NULL) {
552 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
553 lpxkey = *lplpkey;
554 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
555 lpxkey->keyname = keyname;
556 } else
557 free(keyname);
558 return lpxkey;
561 static void
562 _find_or_add_value(
563 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
564 DWORD lastmodified
566 LPKEYVALUE val=NULL;
567 int i;
569 for (i=0;i<lpkey->nrofvalues;i++) {
570 val=lpkey->values+i;
571 if (name==NULL) {
572 if (val->name==NULL)
573 break;
574 } else {
575 if ( val->name!=NULL &&
576 !lstrcmpi32W(val->name,name)
578 break;
581 if (i==lpkey->nrofvalues) {
582 lpkey->values = xrealloc(
583 lpkey->values,
584 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
586 val=lpkey->values+i;
587 memset(val,'\0',sizeof(KEYVALUE));
588 val->name = name;
589 } else {
590 if (name)
591 free(name);
593 if (val->lastmodified<lastmodified) {
594 val->lastmodified=lastmodified;
595 val->type = type;
596 val->len = len;
597 if (val->data)
598 free(val->data);
599 val->data = data;
600 } else
601 free(data);
605 /* reads a line including dynamically enlarging the readbuffer and throwing
606 * away comments
608 static int
609 _wine_read_line(FILE *F,char **buf,int *len) {
610 char *s,*curread;
611 int mylen,curoff;
613 curread = *buf;
614 mylen = *len;
615 **buf = '\0';
616 while (1) {
617 while (1) {
618 s=fgets(curread,mylen,F);
619 if (s==NULL)
620 return 0; /* EOF */
621 if (NULL==(s=strchr(curread,'\n'))) {
622 /* buffer wasn't large enough */
623 curoff = strlen(*buf);
624 *buf = xrealloc(*buf,*len*2);
625 curread = *buf + curoff;
626 mylen = *len; /* we filled up the buffer and
627 * got new '*len' bytes to fill
629 *len = *len * 2;
630 } else {
631 *s='\0';
632 break;
635 /* throw away comments */
636 if (**buf=='#' || **buf==';') {
637 curread = *buf;
638 mylen = *len;
639 continue;
641 if (s) /* got end of line */
642 break;
644 return 1;
647 /* converts a char* into a UNICODE string (up to a special char)
648 * and returns the position exactly after that string
650 static char*
651 _wine_read_USTRING(char *buf,LPWSTR *str) {
652 char *s;
653 LPWSTR ws;
655 /* read up to "=" or "\0" or "\n" */
656 s = buf;
657 if (*s == '=') {
658 /* empty string is the win3.1 default value(NULL)*/
659 *str = NULL;
660 return s;
662 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
663 ws = *str;
664 while (*s && (*s!='\n') && (*s!='=')) {
665 if (*s!='\\')
666 *ws++=*((unsigned char*)s++);
667 else {
668 s++;
669 if (*s=='\\') {
670 *ws++='\\';
671 s++;
672 continue;
674 if (*s!='u') {
675 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
676 *ws++='\\';
677 *ws++=*s++;
678 } else {
679 char xbuf[5];
680 int wc;
682 s++;
683 memcpy(xbuf,s,4);xbuf[4]='\0';
684 if (!sscanf(xbuf,"%x",&wc))
685 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
686 s+=4;
687 *ws++ =(unsigned short)wc;
691 *ws = 0;
692 ws = *str;
693 *str = strdupW(*str);
694 free(ws);
695 return s;
698 static int
699 _wine_loadsubkey(
700 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
702 LPKEYSTRUCT lpxkey;
703 int i;
704 char *s;
705 LPWSTR name;
707 lpkey->flags |= optflag;
709 /* good. we already got a line here ... so parse it */
710 lpxkey = NULL;
711 while (1) {
712 i=0;s=*buf;
713 while (*s=='\t') {
714 s++;
715 i++;
717 if (i>level) {
718 if (lpxkey==NULL) {
719 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
720 return 0;
722 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
723 continue;
725 /* let the caller handle this line */
726 if (i<level || **buf=='\0')
727 return 1;
729 /* it can be: a value or a keyname. Parse the name first */
730 s=_wine_read_USTRING(s,&name);
732 /* switch() default: hack to avoid gotos */
733 switch (0) {
734 default:
735 if (*s=='\0') {
736 lpxkey=_find_or_add_key(lpkey,name);
737 } else {
738 LPBYTE data;
739 int len,lastmodified,type;
741 if (*s!='=') {
742 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
743 break;
745 s++;
746 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
747 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
748 break;
750 /* skip the 2 , */
751 s=strchr(s,',');s++;
752 s=strchr(s,',');s++;
753 if ((1<<type) & UNICONVMASK) {
754 s=_wine_read_USTRING(s,(LPWSTR*)&data);
755 if (data)
756 len = lstrlen32W((LPWSTR)data)*2+2;
757 else
758 len = 0;
759 } else {
760 len=strlen(s)/2;
761 data = (LPBYTE)xmalloc(len+1);
762 for (i=0;i<len;i++) {
763 data[i]=0;
764 if (*s>='0' && *s<='9')
765 data[i]=(*s-'0')<<4;
766 if (*s>='a' && *s<='f')
767 data[i]=(*s-'a')<<4;
768 if (*s>='A' && *s<='F')
769 data[i]=(*s-'A')<<4;
770 s++;
771 if (*s>='0' && *s<='9')
772 data[i]|=*s-'0';
773 if (*s>='a' && *s<='f')
774 data[i]|=*s-'a';
775 if (*s>='A' && *s<='F')
776 data[i]|=*s-'A';
777 s++;
780 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
783 /* read the next line */
784 if (!_wine_read_line(F,buf,buflen))
785 return 1;
787 return 1;
790 static int
791 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
792 int ver;
793 char *buf;
794 int buflen;
796 buf=xmalloc(10);buflen=10;
797 if (!_wine_read_line(F,&buf,&buflen)) {
798 free(buf);
799 return 0;
801 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
802 free(buf);
803 return 0;
805 if (ver!=REGISTRY_SAVE_VERSION) {
806 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
807 free(buf);
808 return 0;
810 if (!_wine_read_line(F,&buf,&buflen)) {
811 free(buf);
812 return 0;
814 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
815 free(buf);
816 return 0;
818 free(buf);
819 return 1;
822 static void
823 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
824 FILE *F;
826 F=fopen(fn,"rb");
827 if (F==NULL) {
828 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
829 fn,strerror(errno)
831 return;
833 if (!_wine_loadsubreg(F,lpkey,optflag)) {
834 fclose(F);
835 unlink(fn);
836 return;
838 fclose(F);
841 static void
842 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
843 LPKEYSTRUCT lpxkey;
844 int j;
845 LPKEYVALUE valfrom;
847 from=from->nextsub;
848 while (from) {
849 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
851 for (j=0;j<from->nrofvalues;j++) {
852 LPWSTR name;
853 LPBYTE data;
855 valfrom = from->values+j;
856 name=valfrom->name;
857 if (name) name=strdupW(name);
858 data=(LPBYTE)malloc(valfrom->len);
859 memcpy(data,valfrom->data,valfrom->len);
861 _find_or_add_value(
862 lpxkey,
863 name,
864 valfrom->type,
865 data,
866 valfrom->len,
867 valfrom->lastmodified
870 _copy_registry(from,lpxkey);
871 from = from->next;
875 /* WINDOWS 95 REGISTRY LOADER */
877 * Structure of a win95 registry database.
878 * main header:
879 * 0 : "CREG" - magic
880 * 4 : DWORD version
881 * 8 : DWORD offset_of_RGDB_part
882 * 0C..1F: ? (someone fill in please)
884 * 20: RGKN_section:
885 * header:
886 * 0 : "RGKN" - magic
887 * 4..0x1B: ? (fill in)
888 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
890 * Disk Key Entry Structure:
891 * 00: DWORD - unknown
892 * 04: DWORD - unknown
893 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
894 * 0C: DWORD - disk address of PreviousLevel Key.
895 * 10: DWORD - disk address of Next Sublevel Key.
896 * 14: DWORD - disk address of Next Key (on same level).
897 * DKEP>18: WORD - Nr, Low Significant part.
898 * 1A: WORD - Nr, High Significant part.
900 * The disk address always points to the nr part of the previous key entry
901 * of the referenced key. Don't ask me why, or even if I got this correct
902 * from staring at 1kg of hexdumps. (DKEP)
904 * The number of the entry is the low byte of the Low Significant Part ored
905 * with 0x100 * (low byte of the High Significant part)
906 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
908 * There are two minor corrections to the position of that structure.
909 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
910 * the DKE reread from there.
911 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
912 * (FIXME: slightly better explanation needed here)
914 * RGDB_section:
915 * 00: "RGDB" - magic
916 * 04: DWORD offset to next RGDB section (perhaps WORD)
917 * 08...1F: ?
918 * 20.....: disk keys
920 * disk key:
921 * 00: DWORD nextkeyoffset - offset to the next disk key structure
922 * 08: WORD nrLS - low significant part of NR
923 * 0A: WORD nrHS - high significant part of NR
924 * 0C: DWORD bytesused - bytes used in this structure.
925 * 10: WORD name_len - length of name in bytes. without \0
926 * 12: WORD nr_of_values - number of values.
927 * 14: char name[name_len] - name string. No \0.
928 * 14+name_len: disk values
929 * nextkeyoffset: ... next disk key
931 * disk value:
932 * 00: DWORD type - value type (hmm, could be WORD too)
933 * 04: DWORD - unknown, usually 0
934 * 08: WORD namelen - length of Name. 0 means name=NULL
935 * 0C: WORD datalen - length of Data.
936 * 10: char name[namelen] - name, no \0
937 * 10+namelen: BYTE data[datalen] - data, without \0 if string
938 * 10+namelen+datalen: next values or disk key
940 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
941 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
942 * structure) and reading another RGDB_section.
943 * repeat until end of file.
945 * FIXME: this description needs some serious help, yes.
948 struct _w95keyvalue {
949 unsigned long type;
950 unsigned short datalen;
951 char *name;
952 unsigned char *data;
953 unsigned long x1;
954 int lastmodified;
957 struct _w95key {
958 char *name;
959 int nrofvals;
960 struct _w95keyvalue *values;
961 unsigned long dkeaddr;
962 unsigned long x1;
963 unsigned long x2;
964 unsigned long x3;
965 unsigned long xx1;
966 struct _w95key *prevlvl;
967 struct _w95key *nextsub;
968 struct _w95key *next;
971 /* fast lookup table dkeaddr->nr */
972 struct _w95nr2da {
973 unsigned long dkeaddr;
974 unsigned long nr;
978 static void
979 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
980 int i;
981 LPKEYSTRUCT lpxkey;
982 LPWSTR name;
984 while (key) {
985 if (key->name == NULL) {
986 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
987 key->dkeaddr
989 return;
991 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
993 if (key->nrofvals<0) {
994 /* shouldn't happen */
995 fprintf(stderr,"key %s already processed!\n",key->name);
996 key = key->next;
997 continue;
999 for (i=0;i<key->nrofvals;i++) {
1000 LPBYTE data;
1001 int len;
1003 name = strdupA2W(key->values[i].name);
1004 if (!*name) name = NULL;
1005 free(key->values[i].name);
1007 len = key->values[i].datalen;
1008 data = key->values[i].data;
1009 if ((1<<key->values[i].type) & UNICONVMASK) {
1010 data = (BYTE*)strdupA2W(data);
1011 len = lstrlen32W((LPWSTR)data)*2+2;
1012 free(key->values[i].data);
1014 _find_or_add_value(
1015 lpxkey,
1016 name,
1017 key->values[i].type,
1018 data,
1019 len,
1020 key->values[i].lastmodified
1023 if (key->values) {
1024 free(key->values);
1025 key->values = NULL;
1027 key->nrofvals=-key->nrofvals-1;
1028 _w95_walk_tree(lpxkey,key->nextsub);
1029 key=key->next;
1033 /* small helper function to adjust address offset (dkeaddrs) */
1034 static unsigned long
1035 _w95_adj_da(unsigned long dkeaddr) {
1036 if ((dkeaddr&0xFFF)<0x018) {
1037 int diff;
1039 diff=0x1C-(dkeaddr&0xFFF);
1040 return dkeaddr+diff;
1042 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1043 /* readjust to 0x000,
1044 * but ONLY if we are >0x1000 already
1046 if (dkeaddr & ~0xFFF)
1047 return dkeaddr & ~0xFFF;
1049 return dkeaddr;
1052 static int
1053 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1055 static struct _w95key*
1056 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1057 int i,off;
1059 if (dkeaddr == 0xFFFFFFFF)
1060 return NULL;
1061 if (dkeaddr<0x20)
1062 return NULL;
1063 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1064 off = (dkeaddr-0x3c)/0x1c;
1065 for (i=0;i<n;i++)
1066 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1067 return keys+nr2da[(i+off)%n].nr;
1068 /* 0x3C happens often, just report unusual values */
1069 if (dkeaddr!=0x3c)
1070 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1071 return NULL;
1074 static void
1075 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1076 /* Disk Key Entry structure (RGKN part) */
1077 struct dke {
1078 unsigned long x1;
1079 unsigned long x2;
1080 unsigned long x3;/*usually 0xFFFFFFFF */
1081 unsigned long prevlvl;
1082 unsigned long nextsub;
1083 unsigned long next;
1084 unsigned short nrLS;
1085 unsigned short nrMS;
1087 /* Disk Key Header structure (RGDB part) */
1088 struct dkh {
1089 unsigned long nextkeyoff;
1090 unsigned short nrLS;
1091 unsigned short nrMS;
1092 unsigned long bytesused;
1093 unsigned short keynamelen;
1094 unsigned short values;
1095 unsigned long xx1;
1096 /* keyname */
1097 /* disk key values or nothing */
1099 /* Disk Key Value structure */
1100 struct dkv {
1101 unsigned long type;
1102 unsigned long x1;
1103 unsigned short valnamelen;
1104 unsigned short valdatalen;
1105 /* valname, valdata */
1107 struct _w95nr2da *nr2da;
1109 HFILE32 hfd;
1110 int lastmodified;
1111 char magic[5];
1112 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1113 struct _w95key *keys;
1114 int nrofdkes;
1115 unsigned char *data,*curdata,*nextrgdb;
1116 OFSTRUCT ofs;
1117 BY_HANDLE_FILE_INFORMATION hfdinfo;
1119 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1120 hfd=OpenFile32(fn,&ofs,OF_READ);
1121 if (hfd==HFILE_ERROR32)
1122 return;
1123 magic[4]=0;
1124 if (4!=_lread32(hfd,magic,4))
1125 return;
1126 if (strcmp(magic,"CREG")) {
1127 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1128 return;
1130 if (4!=_lread32(hfd,&version,4))
1131 return;
1132 if (4!=_lread32(hfd,&rgdbsection,4))
1133 return;
1134 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1135 return;
1136 if (4!=_lread32(hfd,magic,4))
1137 return;
1138 if (strcmp(magic,"RGKN")) {
1139 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1140 return;
1143 /* STEP 1: Keylink structures */
1144 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1145 return;
1146 where = 0x40;
1147 end = rgdbsection;
1149 nrofdkes = (end-where)/sizeof(struct dke)+100;
1150 data = (char*)xmalloc(end-where);
1151 if ((end-where)!=_lread32(hfd,data,end-where))
1152 return;
1153 curdata = data;
1155 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1156 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1157 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1158 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1160 for (i=0;i<nrofdkes;i++) {
1161 struct dke dke;
1162 unsigned long dkeaddr;
1164 pos=curdata-data+0x40;
1165 memcpy(&dke,curdata,sizeof(dke));
1166 curdata+=sizeof(dke);
1167 nr = dke.nrLS + (dke.nrMS<<8);
1168 dkeaddr=pos-4;
1169 if ((dkeaddr&0xFFF)<0x018) {
1170 int diff;
1172 diff=0x1C-(dkeaddr&0xFFF);
1173 dkeaddr+=diff;
1174 curdata+=diff-sizeof(dke);
1175 memcpy(&dke,curdata,sizeof(dke));
1176 nr = dke.nrLS + (dke.nrMS<<8);
1177 curdata+=sizeof(dke);
1179 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1180 /* readjust to 0x000,
1181 * but ONLY if we are >0x1000 already
1183 if (dkeaddr & ~0xFFF)
1184 dkeaddr = dkeaddr & ~0xFFF;
1186 if (nr>nrofdkes) {
1187 /* 0xFFFFFFFF happens often, just report unusual values */
1188 if (nr!=0xFFFFFFFF)
1189 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1190 continue;
1192 if (keys[nr].dkeaddr) {
1193 int x;
1195 for (x=sizeof(dke);x--;)
1196 if (((char*)&dke)[x])
1197 break;
1198 if (x==-1)
1199 break; /* finished reading if we got only 0 */
1200 if (nr) {
1201 if ( (dke.next!=(long)keys[nr].next) ||
1202 (dke.nextsub!=(long)keys[nr].nextsub) ||
1203 (dke.prevlvl!=(long)keys[nr].prevlvl)
1205 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1207 continue;
1209 nr2da[i].nr = nr;
1210 nr2da[i].dkeaddr = dkeaddr;
1212 keys[nr].dkeaddr = dkeaddr;
1213 keys[nr].x1 = dke.x1;
1214 keys[nr].x2 = dke.x2;
1215 keys[nr].x3 = dke.x3;
1216 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1217 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1218 keys[nr].next = (struct _w95key*)dke.next;
1220 free(data);
1222 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1223 (int(*)(const void *,const void*))_w95dkecomp);
1225 /* STEP 2: keydata & values */
1226 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1227 return;
1228 end = hfdinfo.nFileSizeLow;
1229 lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1231 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1232 return;
1233 data = (char*)xmalloc(end-rgdbsection);
1234 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1235 return;
1236 _lclose32(hfd);
1237 curdata = data;
1238 memcpy(magic,curdata,4);
1239 memcpy(&off_next_rgdb,curdata+4,4);
1240 nextrgdb = curdata+off_next_rgdb;
1241 if (strcmp(magic,"RGDB")) {
1242 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1243 return;
1245 curdata=data+0x20;
1246 while (1) {
1247 struct dkh dkh;
1248 int bytesread;
1249 struct _w95key *key,xkey;
1251 bytesread = 0;
1252 if (curdata>=nextrgdb) {
1253 curdata = nextrgdb;
1254 if (!strncmp(curdata,"RGDB",4)) {
1255 memcpy(&off_next_rgdb,curdata+4,4);
1256 nextrgdb = curdata+off_next_rgdb;
1257 curdata+=0x20;
1258 } else {
1259 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1260 break;
1263 #define XREAD(whereto,len) \
1264 if ((curdata-data+len)<end) {\
1265 memcpy(whereto,curdata,len);\
1266 curdata+=len;\
1267 bytesread+=len;\
1270 XREAD(&dkh,sizeof(dkh));
1271 nr = dkh.nrLS + (dkh.nrMS<<8);
1272 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1273 if (dkh.nrLS == 0xFFFF) {
1274 /* skip over key using nextkeyoff */
1275 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1276 continue;
1278 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1279 key = &xkey;
1280 memset(key,'\0',sizeof(xkey));
1281 } else {
1282 key = keys+nr;
1283 if (!key->dkeaddr)
1284 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1286 key->nrofvals = dkh.values;
1287 key->name = (char*)xmalloc(dkh.keynamelen+1);
1288 key->xx1 = dkh.xx1;
1289 XREAD(key->name,dkh.keynamelen);
1290 key->name[dkh.keynamelen]=0;
1291 if (key->nrofvals) {
1292 key->values = (struct _w95keyvalue*)xmalloc(
1293 sizeof(struct _w95keyvalue)*key->nrofvals
1295 for (i=0;i<key->nrofvals;i++) {
1296 struct dkv dkv;
1298 XREAD(&dkv,sizeof(dkv));
1299 key->values[i].type = dkv.type;
1300 key->values[i].name = (char*)xmalloc(
1301 dkv.valnamelen+1
1303 key->values[i].datalen = dkv.valdatalen;
1304 key->values[i].data = (unsigned char*)xmalloc(
1305 dkv.valdatalen+1
1307 key->values[i].x1 = dkv.x1;
1308 XREAD(key->values[i].name,dkv.valnamelen);
1309 XREAD(key->values[i].data,dkv.valdatalen);
1310 key->values[i].data[dkv.valdatalen]=0;
1311 key->values[i].name[dkv.valnamelen]=0;
1312 key->values[i].lastmodified=lastmodified;
1315 if (bytesread != dkh.nextkeyoff) {
1316 if (dkh.bytesused != bytesread)
1317 dprintf_reg(stddeb,
1318 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1319 dkh.bytesused
1321 curdata += dkh.nextkeyoff-bytesread;
1323 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1324 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1325 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1326 if (!bytesread)
1327 break;
1329 free(data);
1330 _w95_walk_tree(lpkey,keys);
1331 free(keys);
1334 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1337 reghack - windows 3.11 registry data format demo program.
1339 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1340 a combined hash table and tree description, and finally a text table.
1342 The header is obvious from the struct header. The taboff1 and taboff2
1343 fields are always 0x20, and their usage is unknown.
1345 The 8-byte entry table has various entry types.
1347 tabent[0] is a root index. The second word has the index of the root of
1348 the directory.
1349 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1350 the index of the key/value that has that hash. Data with the same
1351 hash value are on a circular list. The other three words in the
1352 hash entry are always zero.
1353 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1354 entry: dirent and keyent/valent. They are identified by context.
1355 tabent[freeidx] is the first free entry. The first word in a free entry
1356 is the index of the next free entry. The last has 0 as a link.
1357 The other three words in the free list are probably irrelevant.
1359 Entries in text table are preceeded by a word at offset-2. This word
1360 has the value (2*index)+1, where index is the referring keyent/valent
1361 entry in the table. I have no suggestion for the 2* and the +1.
1362 Following the word, there are N bytes of data, as per the keyent/valent
1363 entry length. The offset of the keyent/valent entry is from the start
1364 of the text table to the first data byte.
1366 This information is not available from Microsoft. The data format is
1367 deduced from the reg.dat file by me. Mistakes may
1368 have been made. I claim no rights and give no guarantees for this program.
1370 Tor Sjøwall, tor@sn.no
1373 /* reg.dat header format */
1374 struct _w31_header {
1375 char cookie[8]; /* 'SHCC3.10' */
1376 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1377 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1378 unsigned long tabcnt; /* number of entries in index table */
1379 unsigned long textoff; /* offset of text part */
1380 unsigned long textsize; /* byte size of text part */
1381 unsigned short hashsize; /* hash size */
1382 unsigned short freeidx; /* free index */
1385 /* generic format of table entries */
1386 struct _w31_tabent {
1387 unsigned short w0, w1, w2, w3;
1390 /* directory tabent: */
1391 struct _w31_dirent {
1392 unsigned short sibling_idx; /* table index of sibling dirent */
1393 unsigned short child_idx; /* table index of child dirent */
1394 unsigned short key_idx; /* table index of key keyent */
1395 unsigned short value_idx; /* table index of value valent */
1398 /* key tabent: */
1399 struct _w31_keyent {
1400 unsigned short hash_idx; /* hash chain index for string */
1401 unsigned short refcnt; /* reference count */
1402 unsigned short length; /* length of string */
1403 unsigned short string_off; /* offset of string in text table */
1406 /* value tabent: */
1407 struct _w31_valent {
1408 unsigned short hash_idx; /* hash chain index for string */
1409 unsigned short refcnt; /* reference count */
1410 unsigned short length; /* length of string */
1411 unsigned short string_off; /* offset of string in text table */
1414 /* recursive helper function to display a directory tree */
1415 void
1416 __w31_dumptree( unsigned short idx,
1417 unsigned char *txt,
1418 struct _w31_tabent *tab,
1419 struct _w31_header *head,
1420 LPKEYSTRUCT lpkey,
1421 time_t lastmodified,
1422 int level
1424 struct _w31_dirent *dir;
1425 struct _w31_keyent *key;
1426 struct _w31_valent *val;
1427 LPKEYSTRUCT xlpkey = NULL;
1428 LPWSTR name,value;
1429 static char tail[400];
1431 while (idx!=0) {
1432 dir=(struct _w31_dirent*)&tab[idx];
1434 if (dir->key_idx) {
1435 key = (struct _w31_keyent*)&tab[dir->key_idx];
1437 memcpy(tail,&txt[key->string_off],key->length);
1438 tail[key->length]='\0';
1439 /* all toplevel entries AND the entries in the
1440 * toplevel subdirectory belong to \SOFTWARE\Classes
1442 if (!level && !lstrcmp32A(tail,".classes")) {
1443 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1444 idx=dir->sibling_idx;
1445 continue;
1447 name=STRING32_DupAnsiToUni(tail);
1449 xlpkey=_find_or_add_key(lpkey,name);
1451 /* only add if leaf node or valued node */
1452 if (dir->value_idx!=0||dir->child_idx==0) {
1453 if (dir->value_idx) {
1454 val=(struct _w31_valent*)&tab[dir->value_idx];
1455 memcpy(tail,&txt[val->string_off],val->length);
1456 tail[val->length]='\0';
1457 value=STRING32_DupAnsiToUni(tail);
1458 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1461 } else {
1462 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1464 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1465 idx=dir->sibling_idx;
1469 void
1470 _w31_loadreg() {
1471 HFILE32 hf;
1472 struct _w31_header head;
1473 struct _w31_tabent *tab;
1474 unsigned char *txt;
1475 int len;
1476 OFSTRUCT ofs;
1477 BY_HANDLE_FILE_INFORMATION hfinfo;
1478 time_t lastmodified;
1479 HKEY hkey;
1480 LPKEYSTRUCT lpkey;
1482 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1483 if (hf==HFILE_ERROR32)
1484 return;
1486 /* read & dump header */
1487 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1488 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1489 _lclose32(hf);
1490 return;
1492 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1493 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1494 _lclose32(hf);
1495 return;
1498 len = head.tabcnt * sizeof(struct _w31_tabent);
1499 /* read and dump index table */
1500 tab = xmalloc(len);
1501 if (len!=_lread32(hf,tab,len)) {
1502 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1503 free(tab);
1504 _lclose32(hf);
1505 return;
1508 /* read text */
1509 txt = xmalloc(head.textsize);
1510 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1511 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1512 free(tab);
1513 free(txt);
1514 _lclose32(hf);
1515 return;
1517 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1518 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1519 free(tab);
1520 free(txt);
1521 _lclose32(hf);
1522 return;
1525 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1526 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1527 free(tab);
1528 free(txt);
1529 _lclose32(hf);
1530 return;
1532 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1534 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1535 return;
1536 lpkey = lookup_hkey(hkey);
1537 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1538 free(tab);
1539 free(txt);
1540 _lclose32(hf);
1541 return;
1544 void
1545 SHELL_LoadRegistry() {
1546 char *fn;
1547 struct passwd *pwd;
1548 LPKEYSTRUCT lpkey;
1549 HKEY hkey;
1552 if (key_classes_root==NULL)
1553 SHELL_Init();
1555 /* Load windows 3.1 entries */
1556 _w31_loadreg();
1557 /* Load windows 95 entries */
1558 _w95_loadreg("C:\\system.1st", key_local_machine);
1559 _w95_loadreg("system.dat", key_local_machine);
1560 _w95_loadreg("user.dat", key_users);
1562 /* the global user default is loaded under HKEY_USERS\\.Default */
1563 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1564 lpkey = lookup_hkey(hkey);
1565 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1567 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1568 _copy_registry(lpkey,key_current_user);
1569 RegCloseKey(hkey);
1571 /* the global machine defaults */
1572 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1574 /* load the user saved registries */
1576 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1578 pwd=getpwuid(getuid());
1579 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1580 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1581 strcpy(fn,pwd->pw_dir);
1582 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1583 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1584 free(fn);
1585 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1586 strcpy(fn,pwd->pw_dir);
1587 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1588 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1589 free(fn);
1590 } else
1591 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1592 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1593 DWORD junk,type,len;
1594 char data[5];
1596 len=4;
1597 if (( RegQueryValueEx32A(
1598 hkey,
1599 VAL_SAVEUPDATED,
1600 &junk,
1601 &type,
1602 data,
1603 &len
1604 )!=ERROR_SUCCESS) ||
1605 type != REG_SZ
1607 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1608 RegCloseKey(hkey);
1613 /********************* API FUNCTIONS ***************************************/
1615 * Open Keys.
1617 * All functions are stubs to RegOpenKeyEx32W where all the
1618 * magic happens.
1620 * FIXME: security,options,desiredaccess,...
1622 * Callpath:
1623 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1624 * RegOpenKey32W -> RegOpenKeyEx32W
1627 /* RegOpenKeyExW [ADVAPI32.150] */
1628 DWORD WINAPI RegOpenKeyEx32W(
1629 HKEY hkey,
1630 LPCWSTR lpszSubKey,
1631 DWORD dwReserved,
1632 REGSAM samDesired,
1633 LPHKEY retkey
1635 LPKEYSTRUCT lpNextKey,lpxkey;
1636 LPWSTR *wps;
1637 int wpc,i;
1638 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1639 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1642 lpNextKey = lookup_hkey(hkey);
1643 if (!lpNextKey)
1644 return SHELL_ERROR_BADKEY;
1645 if (!lpszSubKey || !*lpszSubKey) {
1646 add_handle(++currenthandle,lpNextKey,samDesired);
1647 *retkey=currenthandle;
1648 return SHELL_ERROR_SUCCESS;
1650 split_keypath(lpszSubKey,&wps,&wpc);
1651 i = 0;
1652 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1653 lpxkey = lpNextKey;
1654 while (wps[i]) {
1655 lpxkey=lpNextKey->nextsub;
1656 while (lpxkey) {
1657 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1658 break;
1659 lpxkey=lpxkey->next;
1661 if (!lpxkey) {
1662 FREE_KEY_PATH;
1663 return SHELL_ERROR_BADKEY;
1665 i++;
1666 lpNextKey = lpxkey;
1668 add_handle(++currenthandle,lpxkey,samDesired);
1669 *retkey = currenthandle;
1670 FREE_KEY_PATH;
1671 return SHELL_ERROR_SUCCESS;
1674 /* RegOpenKeyW [ADVAPI32.151] */
1675 DWORD WINAPI RegOpenKey32W(
1676 HKEY hkey,
1677 LPCWSTR lpszSubKey,
1678 LPHKEY retkey
1680 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1681 (LONG)hkey,W2C(lpszSubKey,0),retkey
1683 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1687 /* RegOpenKeyExA [ADVAPI32.149] */
1688 DWORD WINAPI RegOpenKeyEx32A(
1689 HKEY hkey,
1690 LPCSTR lpszSubKey,
1691 DWORD dwReserved,
1692 REGSAM samDesired,
1693 LPHKEY retkey
1695 LPWSTR lpszSubKeyW;
1696 DWORD ret;
1698 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1699 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1701 if (lpszSubKey)
1702 lpszSubKeyW=strdupA2W(lpszSubKey);
1703 else
1704 lpszSubKeyW=NULL;
1705 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1706 if (lpszSubKeyW)
1707 free(lpszSubKeyW);
1708 return ret;
1711 /* RegOpenKeyA [ADVAPI32.148] */
1712 DWORD WINAPI RegOpenKey32A(
1713 HKEY hkey,
1714 LPCSTR lpszSubKey,
1715 LPHKEY retkey
1717 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1718 (LONG)hkey,lpszSubKey,retkey
1720 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1723 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1724 DWORD WINAPI RegOpenKey16(
1725 HKEY hkey,
1726 LPCSTR lpszSubKey,
1727 LPHKEY retkey
1729 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1730 (LONG)hkey,lpszSubKey,retkey
1732 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1736 * Create keys
1738 * All those functions convert their respective
1739 * arguments and call RegCreateKeyExW at the end.
1741 * FIXME: no security,no access attrib,no optionhandling yet.
1743 * Callpath:
1744 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1745 * RegCreateKey32W -> RegCreateKeyEx32W
1748 /* RegCreateKeyExW [ADVAPI32.131] */
1749 DWORD WINAPI RegCreateKeyEx32W(
1750 HKEY hkey,
1751 LPCWSTR lpszSubKey,
1752 DWORD dwReserved,
1753 LPWSTR lpszClass,
1754 DWORD fdwOptions,
1755 REGSAM samDesired,
1756 LPSECURITY_ATTRIBUTES lpSecAttribs,
1757 LPHKEY retkey,
1758 LPDWORD lpDispos
1760 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1761 LPWSTR *wps;
1762 int wpc,i;
1764 /*FIXME: handle security/access/whatever */
1765 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1766 (LONG)hkey,
1767 W2C(lpszSubKey,0),
1768 dwReserved,
1769 W2C(lpszClass,1),
1770 fdwOptions,
1771 samDesired,
1772 lpSecAttribs,
1773 retkey,
1774 lpDispos
1777 lpNextKey = lookup_hkey(hkey);
1778 if (!lpNextKey)
1779 return SHELL_ERROR_BADKEY;
1780 if (!lpszSubKey || !*lpszSubKey) {
1781 add_handle(++currenthandle,lpNextKey,samDesired);
1782 *retkey=currenthandle;
1783 lpNextKey->flags|=REG_OPTION_TAINTED;
1784 return SHELL_ERROR_SUCCESS;
1786 split_keypath(lpszSubKey,&wps,&wpc);
1787 i = 0;
1788 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1789 lpxkey = lpNextKey;
1790 while (wps[i]) {
1791 lpxkey=lpNextKey->nextsub;
1792 while (lpxkey) {
1793 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1794 break;
1795 lpxkey=lpxkey->next;
1797 if (!lpxkey)
1798 break;
1799 i++;
1800 lpNextKey = lpxkey;
1802 if (lpxkey) {
1803 add_handle(++currenthandle,lpxkey,samDesired);
1804 lpxkey->flags |= REG_OPTION_TAINTED;
1805 *retkey = currenthandle;
1806 if (lpDispos)
1807 *lpDispos = REG_OPENED_EXISTING_KEY;
1808 FREE_KEY_PATH;
1809 return SHELL_ERROR_SUCCESS;
1811 /* good. now the hard part */
1812 while (wps[i]) {
1813 lplpPrevKey = &(lpNextKey->nextsub);
1814 lpxkey = *lplpPrevKey;
1815 while (lpxkey) {
1816 lplpPrevKey = &(lpxkey->next);
1817 lpxkey = *lplpPrevKey;
1819 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1820 if (!*lplpPrevKey) {
1821 FREE_KEY_PATH;
1822 return SHELL_ERROR_OUTOFMEMORY;
1824 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1825 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1826 (*lplpPrevKey)->next = NULL;
1827 (*lplpPrevKey)->nextsub = NULL;
1828 (*lplpPrevKey)->values = NULL;
1829 (*lplpPrevKey)->nrofvalues = 0;
1830 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1831 if (lpszClass)
1832 (*lplpPrevKey)->class = strdupW(lpszClass);
1833 else
1834 (*lplpPrevKey)->class = NULL;
1835 lpNextKey = *lplpPrevKey;
1836 i++;
1838 add_handle(++currenthandle,lpNextKey,samDesired);
1840 /*FIXME: flag handling correct? */
1841 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1842 if (lpszClass)
1843 lpNextKey->class = strdupW(lpszClass);
1844 else
1845 lpNextKey->class = NULL;
1846 *retkey = currenthandle;
1847 if (lpDispos)
1848 *lpDispos = REG_CREATED_NEW_KEY;
1849 FREE_KEY_PATH;
1850 return SHELL_ERROR_SUCCESS;
1853 /* RegCreateKeyW [ADVAPI32.132] */
1854 DWORD WINAPI RegCreateKey32W(
1855 HKEY hkey,
1856 LPCWSTR lpszSubKey,
1857 LPHKEY retkey
1859 DWORD junk,ret;
1861 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1862 (LONG)hkey,W2C(lpszSubKey,0),retkey
1864 ret=RegCreateKeyEx32W(
1865 hkey, /* key handle */
1866 lpszSubKey, /* subkey name */
1867 0, /* reserved = 0 */
1868 NULL, /* lpszClass? FIXME: ? */
1869 REG_OPTION_NON_VOLATILE, /* options */
1870 KEY_ALL_ACCESS, /* desired access attribs */
1871 NULL, /* lpsecurity attributes */
1872 retkey, /* lpretkey */
1873 &junk /* disposition value */
1875 return ret;
1878 /* RegCreateKeyExA [ADVAPI32.130] */
1879 DWORD WINAPI RegCreateKeyEx32A(
1880 HKEY hkey,
1881 LPCSTR lpszSubKey,
1882 DWORD dwReserved,
1883 LPSTR lpszClass,
1884 DWORD fdwOptions,
1885 REGSAM samDesired,
1886 LPSECURITY_ATTRIBUTES lpSecAttribs,
1887 LPHKEY retkey,
1888 LPDWORD lpDispos
1890 LPWSTR lpszSubKeyW,lpszClassW;
1891 DWORD ret;
1893 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1894 (LONG)hkey,
1895 lpszSubKey,
1896 dwReserved,
1897 lpszClass,
1898 fdwOptions,
1899 samDesired,
1900 lpSecAttribs,
1901 retkey,
1902 lpDispos
1904 if (lpszSubKey)
1905 lpszSubKeyW=strdupA2W(lpszSubKey);
1906 else
1907 lpszSubKeyW=NULL;
1908 if (lpszClass)
1909 lpszClassW=strdupA2W(lpszClass);
1910 else
1911 lpszClassW=NULL;
1912 ret=RegCreateKeyEx32W(
1913 hkey,
1914 lpszSubKeyW,
1915 dwReserved,
1916 lpszClassW,
1917 fdwOptions,
1918 samDesired,
1919 lpSecAttribs,
1920 retkey,
1921 lpDispos
1923 if (lpszSubKeyW)
1924 free(lpszSubKeyW);
1925 if (lpszClassW)
1926 free(lpszClassW);
1927 return ret;
1930 /* RegCreateKeyA [ADVAPI32.129] */
1931 DWORD WINAPI RegCreateKey32A(
1932 HKEY hkey,
1933 LPCSTR lpszSubKey,
1934 LPHKEY retkey
1936 DWORD junk;
1938 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1939 (LONG)hkey,lpszSubKey,retkey
1941 return RegCreateKeyEx32A(
1942 hkey, /* key handle */
1943 lpszSubKey, /* subkey name */
1944 0, /* reserved = 0 */
1945 NULL, /* lpszClass? FIXME: ? */
1946 REG_OPTION_NON_VOLATILE,/* options */
1947 KEY_ALL_ACCESS, /* desired access attribs */
1948 NULL, /* lpsecurity attributes */
1949 retkey, /* lpretkey */
1950 &junk /* disposition value */
1954 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1955 DWORD WINAPI RegCreateKey16(
1956 HKEY hkey,
1957 LPCSTR lpszSubKey,
1958 LPHKEY retkey
1960 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1961 (LONG)hkey,lpszSubKey,retkey
1963 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1967 * Query Value Functions
1968 * Win32 differs between keynames and valuenames.
1969 * multiple values may belong to one key, the special value
1970 * with name NULL is the default value used by the win31
1971 * compat functions.
1973 * Callpath:
1974 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1975 * RegQueryValue32W -> RegQueryValueEx32W
1978 /* RegQueryValueExW [ADVAPI32.158] */
1979 DWORD WINAPI RegQueryValueEx32W(
1980 HKEY hkey,
1981 LPWSTR lpszValueName,
1982 LPDWORD lpdwReserved,
1983 LPDWORD lpdwType,
1984 LPBYTE lpbData,
1985 LPDWORD lpcbData
1987 LPKEYSTRUCT lpkey;
1988 int i;
1990 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1991 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1992 lpcbData?*lpcbData:0
1995 lpkey = lookup_hkey(hkey);
1996 if (!lpkey)
1997 return SHELL_ERROR_BADKEY;
1998 if (lpszValueName==NULL) {
1999 for (i=0;i<lpkey->nrofvalues;i++)
2000 if (lpkey->values[i].name==NULL)
2001 break;
2002 } else {
2003 for (i=0;i<lpkey->nrofvalues;i++)
2004 if ( lpkey->values[i].name &&
2005 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2007 break;
2009 if (i==lpkey->nrofvalues) {
2010 if (lpszValueName==NULL) {
2011 if (lpbData) {
2012 *(WCHAR*)lpbData = 0;
2013 *lpcbData = 2;
2015 if (lpdwType)
2016 *lpdwType = REG_SZ;
2017 return SHELL_ERROR_SUCCESS;
2019 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2021 if (lpdwType)
2022 *lpdwType = lpkey->values[i].type;
2023 if (lpbData==NULL) {
2024 if (lpcbData==NULL)
2025 return SHELL_ERROR_SUCCESS;
2026 *lpcbData = lpkey->values[i].len;
2027 return SHELL_ERROR_SUCCESS;
2029 if (*lpcbData<lpkey->values[i].len) {
2030 *(WCHAR*)lpbData
2031 = 0;
2032 *lpcbData = lpkey->values[i].len;
2033 return ERROR_MORE_DATA;
2035 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2036 *lpcbData = lpkey->values[i].len;
2037 return SHELL_ERROR_SUCCESS;
2040 /* RegQueryValueW [ADVAPI32.159] */
2041 DWORD WINAPI RegQueryValue32W(
2042 HKEY hkey,
2043 LPWSTR lpszSubKey,
2044 LPWSTR lpszData,
2045 LPDWORD lpcbData
2047 HKEY xhkey;
2048 DWORD ret,lpdwType;
2050 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2051 hkey,W2C(lpszSubKey,0),lpszData,
2052 lpcbData?*lpcbData:0
2055 /* only open subkey, if we really do descend */
2056 if (lpszSubKey && *lpszSubKey) {
2057 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2058 if (ret!=ERROR_SUCCESS)
2059 return ret;
2060 } else
2061 xhkey = hkey;
2063 lpdwType = REG_SZ;
2064 ret = RegQueryValueEx32W(
2065 xhkey,
2066 NULL, /* varname NULL -> compat */
2067 NULL, /* lpdwReserved, must be NULL */
2068 &lpdwType,
2069 (LPBYTE)lpszData,
2070 lpcbData
2072 if (xhkey!=hkey)
2073 RegCloseKey(xhkey);
2074 return ret;
2077 /* RegQueryValueExA [ADVAPI32.157] */
2078 DWORD WINAPI RegQueryValueEx32A(
2079 HKEY hkey,
2080 LPSTR lpszValueName,
2081 LPDWORD lpdwReserved,
2082 LPDWORD lpdwType,
2083 LPBYTE lpbData,
2084 LPDWORD lpcbData
2086 LPWSTR lpszValueNameW;
2087 LPBYTE buf;
2088 DWORD ret,myxlen;
2089 DWORD *mylen;
2090 DWORD type;
2092 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2093 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2094 lpcbData?*lpcbData:0
2096 if (lpszValueName)
2097 lpszValueNameW=strdupA2W(lpszValueName);
2098 else
2099 lpszValueNameW=NULL;
2101 if (lpdwType)
2102 type=*lpdwType;
2104 if (lpbData) {
2105 myxlen = 0;
2106 mylen = &myxlen;
2107 buf = xmalloc(4);
2108 ret=RegQueryValueEx32W(
2109 hkey,
2110 lpszValueNameW,
2111 lpdwReserved,
2112 &type,
2113 buf,
2114 mylen
2116 free(buf);
2117 if (ret==ERROR_MORE_DATA) {
2118 buf = (LPBYTE)xmalloc(*mylen);
2119 } else {
2120 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2121 myxlen = 2*(*lpcbData);
2123 } else {
2124 buf=NULL;
2125 if (lpcbData) {
2126 myxlen = *lpcbData*2;
2127 mylen = &myxlen;
2128 } else
2129 mylen = NULL;
2131 ret=RegQueryValueEx32W(
2132 hkey,
2133 lpszValueNameW,
2134 lpdwReserved,
2135 &type,
2136 buf,
2137 mylen
2139 if (lpdwType)
2140 *lpdwType=type;
2141 if (ret==ERROR_SUCCESS) {
2142 if (buf) {
2143 if (UNICONVMASK & (1<<(type))) {
2144 /* convert UNICODE to ASCII */
2145 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2146 *lpcbData = myxlen/2;
2147 } else {
2148 if (myxlen>*lpcbData)
2149 ret = ERROR_MORE_DATA;
2150 else
2151 memcpy(lpbData,buf,myxlen);
2153 *lpcbData = myxlen;
2155 } else {
2156 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2157 *lpcbData = myxlen/2;
2159 } else {
2160 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2161 *lpcbData = myxlen/2;
2163 if (buf)
2164 free(buf);
2165 return ret;
2168 /* RegQueryValueEx [KERNEL.225] */
2169 DWORD WINAPI RegQueryValueEx16(
2170 HKEY hkey,
2171 LPSTR lpszValueName,
2172 LPDWORD lpdwReserved,
2173 LPDWORD lpdwType,
2174 LPBYTE lpbData,
2175 LPDWORD lpcbData
2177 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2178 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2179 lpcbData?*lpcbData:0
2181 return RegQueryValueEx32A(
2182 hkey,
2183 lpszValueName,
2184 lpdwReserved,
2185 lpdwType,
2186 lpbData,
2187 lpcbData
2191 /* RegQueryValueA [ADVAPI32.156] */
2192 DWORD WINAPI RegQueryValue32A(
2193 HKEY hkey,
2194 LPSTR lpszSubKey,
2195 LPSTR lpszData,
2196 LPDWORD lpcbData
2198 HKEY xhkey;
2199 DWORD ret,lpdwType;
2201 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2202 hkey,lpszSubKey,lpszData,
2203 lpcbData?*lpcbData:0
2206 /* only open subkey, if we really do descend */
2207 if (lpszSubKey && *lpszSubKey) {
2208 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2209 if (ret!=ERROR_SUCCESS)
2210 return ret;
2211 } else
2212 xhkey = hkey;
2214 lpdwType = REG_SZ;
2215 ret = RegQueryValueEx32A(
2216 xhkey,
2217 NULL, /* lpszValueName NULL -> compat */
2218 NULL, /* lpdwReserved, must be NULL */
2219 &lpdwType,
2220 (LPBYTE)lpszData,
2221 lpcbData
2223 if (xhkey!=hkey)
2224 RegCloseKey(xhkey);
2225 return ret;
2228 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2229 DWORD WINAPI RegQueryValue16(
2230 HKEY hkey,
2231 LPSTR lpszSubKey,
2232 LPSTR lpszData,
2233 LPDWORD lpcbData
2235 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2236 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2238 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2239 * anyway, so we just mask out the high 16 bit.
2240 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2242 if (lpcbData)
2243 *lpcbData &= 0xFFFF;
2244 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2248 * Setting values of Registry keys
2250 * Callpath:
2251 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2252 * RegSetValue32W -> RegSetValueEx32W
2255 /* RegSetValueExW [ADVAPI32.170] */
2256 DWORD WINAPI RegSetValueEx32W(
2257 HKEY hkey,
2258 LPWSTR lpszValueName,
2259 DWORD dwReserved,
2260 DWORD dwType,
2261 LPBYTE lpbData,
2262 DWORD cbData
2264 LPKEYSTRUCT lpkey;
2265 int i;
2267 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2268 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2270 /* we no longer care about the lpbData type here... */
2271 lpkey = lookup_hkey(hkey);
2272 if (!lpkey)
2273 return SHELL_ERROR_BADKEY;
2275 lpkey->flags |= REG_OPTION_TAINTED;
2277 if (lpszValueName==NULL) {
2278 for (i=0;i<lpkey->nrofvalues;i++)
2279 if (lpkey->values[i].name==NULL)
2280 break;
2281 } else {
2282 for (i=0;i<lpkey->nrofvalues;i++)
2283 if ( lpkey->values[i].name &&
2284 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2286 break;
2288 if (i==lpkey->nrofvalues) {
2289 lpkey->values = (LPKEYVALUE)xrealloc(
2290 lpkey->values,
2291 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2293 lpkey->nrofvalues++;
2294 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2296 if (lpkey->values[i].name==NULL)
2297 if (lpszValueName)
2298 lpkey->values[i].name = strdupW(lpszValueName);
2299 else
2300 lpkey->values[i].name = NULL;
2301 lpkey->values[i].len = cbData;
2302 lpkey->values[i].type = dwType;
2303 if (lpkey->values[i].data !=NULL)
2304 free(lpkey->values[i].data);
2305 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2306 lpkey->values[i].lastmodified = time(NULL);
2307 memcpy(lpkey->values[i].data,lpbData,cbData);
2308 return SHELL_ERROR_SUCCESS;
2311 /* RegSetValueExA [ADVAPI32.169] */
2312 DWORD WINAPI RegSetValueEx32A(
2313 HKEY hkey,
2314 LPSTR lpszValueName,
2315 DWORD dwReserved,
2316 DWORD dwType,
2317 LPBYTE lpbData,
2318 DWORD cbData
2320 LPBYTE buf;
2321 LPWSTR lpszValueNameW;
2322 DWORD ret;
2324 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2325 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2327 if ((1<<dwType) & UNICONVMASK) {
2328 buf=(LPBYTE)strdupA2W(lpbData);
2329 cbData=2*strlen(lpbData)+2;
2330 } else
2331 buf=lpbData;
2332 if (lpszValueName)
2333 lpszValueNameW = strdupA2W(lpszValueName);
2334 else
2335 lpszValueNameW = NULL;
2336 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2337 if (lpszValueNameW)
2338 free(lpszValueNameW);
2339 if (buf!=lpbData)
2340 free(buf);
2341 return ret;
2344 /* RegSetValueEx [KERNEL.226] */
2345 DWORD WINAPI RegSetValueEx16(
2346 HKEY hkey,
2347 LPSTR lpszValueName,
2348 DWORD dwReserved,
2349 DWORD dwType,
2350 LPBYTE lpbData,
2351 DWORD cbData
2353 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2354 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2356 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2359 /* RegSetValueW [ADVAPI32.171] */
2360 DWORD WINAPI RegSetValue32W(
2361 HKEY hkey,
2362 LPCWSTR lpszSubKey,
2363 DWORD dwType,
2364 LPCWSTR lpszData,
2365 DWORD cbData
2367 HKEY xhkey;
2368 DWORD ret;
2370 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2371 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2373 if (lpszSubKey && *lpszSubKey) {
2374 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2375 if (ret!=ERROR_SUCCESS)
2376 return ret;
2377 } else
2378 xhkey=hkey;
2379 if (dwType!=REG_SZ) {
2380 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2381 dwType=REG_SZ;
2383 if (cbData!=2*lstrlen32W(lpszData)+2) {
2384 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2385 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2387 cbData=2*lstrlen32W(lpszData)+2;
2389 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2390 if (hkey!=xhkey)
2391 RegCloseKey(xhkey);
2392 return ret;
2395 /* RegSetValueA [ADVAPI32.168] */
2396 DWORD WINAPI RegSetValue32A(
2397 HKEY hkey,
2398 LPCSTR lpszSubKey,
2399 DWORD dwType,
2400 LPCSTR lpszData,
2401 DWORD cbData
2403 DWORD ret;
2404 HKEY xhkey;
2406 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2407 hkey,lpszSubKey,dwType,lpszData,cbData
2409 if (lpszSubKey && *lpszSubKey) {
2410 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2411 if (ret!=ERROR_SUCCESS)
2412 return ret;
2413 } else
2414 xhkey=hkey;
2416 if (dwType!=REG_SZ) {
2417 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2418 dwType=REG_SZ;
2420 if (cbData!=strlen(lpszData)+1)
2421 cbData=strlen(lpszData)+1;
2422 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2423 if (xhkey!=hkey)
2424 RegCloseKey(xhkey);
2425 return ret;
2428 /* RegSetValue [KERNEL.221] [SHELL.5] */
2429 DWORD WINAPI RegSetValue16(
2430 HKEY hkey,
2431 LPCSTR lpszSubKey,
2432 DWORD dwType,
2433 LPCSTR lpszData,
2434 DWORD cbData
2436 DWORD ret;
2437 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2438 hkey,lpszSubKey,dwType,lpszData,cbData
2440 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2441 return ret;
2445 * Key Enumeration
2447 * Callpath:
2448 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2449 * RegEnumKey32W -> RegEnumKeyEx32W
2452 /* RegEnumKeyExW [ADVAPI32.139] */
2453 DWORD WINAPI RegEnumKeyEx32W(
2454 HKEY hkey,
2455 DWORD iSubkey,
2456 LPWSTR lpszName,
2457 LPDWORD lpcchName,
2458 LPDWORD lpdwReserved,
2459 LPWSTR lpszClass,
2460 LPDWORD lpcchClass,
2461 FILETIME *ft
2463 LPKEYSTRUCT lpkey,lpxkey;
2465 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2466 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2468 lpkey=lookup_hkey(hkey);
2469 if (!lpkey)
2470 return SHELL_ERROR_BADKEY;
2471 if (!lpkey->nextsub)
2472 return ERROR_NO_MORE_ITEMS;
2473 lpxkey=lpkey->nextsub;
2474 while (iSubkey && lpxkey) {
2475 iSubkey--;
2476 lpxkey=lpxkey->next;
2478 if (iSubkey || !lpxkey)
2479 return ERROR_NO_MORE_ITEMS;
2480 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2481 return ERROR_MORE_DATA;
2482 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2483 if (lpszClass) {
2484 /* what should we write into it? */
2485 *lpszClass = 0;
2486 *lpcchClass = 2;
2488 return ERROR_SUCCESS;
2492 /* RegEnumKeyW [ADVAPI32.140] */
2493 DWORD WINAPI RegEnumKey32W(
2494 HKEY hkey,
2495 DWORD iSubkey,
2496 LPWSTR lpszName,
2497 DWORD lpcchName
2499 FILETIME ft;
2501 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2502 hkey,iSubkey,lpszName,lpcchName
2504 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2506 /* RegEnumKeyExA [ADVAPI32.138] */
2507 DWORD WINAPI RegEnumKeyEx32A(
2508 HKEY hkey,
2509 DWORD iSubkey,
2510 LPSTR lpszName,
2511 LPDWORD lpcchName,
2512 LPDWORD lpdwReserved,
2513 LPSTR lpszClass,
2514 LPDWORD lpcchClass,
2515 FILETIME *ft
2517 DWORD ret,lpcchNameW,lpcchClassW;
2518 LPWSTR lpszNameW,lpszClassW;
2521 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2522 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2524 if (lpszName) {
2525 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2526 lpcchNameW = *lpcchName*2;
2527 } else {
2528 lpszNameW = NULL;
2529 lpcchNameW = 0;
2531 if (lpszClass) {
2532 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2533 lpcchClassW = *lpcchClass*2;
2534 } else {
2535 lpszClassW =0;
2536 lpcchClassW=0;
2538 ret=RegEnumKeyEx32W(
2539 hkey,
2540 iSubkey,
2541 lpszNameW,
2542 &lpcchNameW,
2543 lpdwReserved,
2544 lpszClassW,
2545 &lpcchClassW,
2548 if (ret==ERROR_SUCCESS) {
2549 lstrcpyWtoA(lpszName,lpszNameW);
2550 *lpcchName=strlen(lpszName);
2551 if (lpszClassW) {
2552 lstrcpyWtoA(lpszClass,lpszClassW);
2553 *lpcchClass=strlen(lpszClass);
2556 if (lpszNameW)
2557 free(lpszNameW);
2558 if (lpszClassW)
2559 free(lpszClassW);
2560 return ret;
2563 /* RegEnumKeyA [ADVAPI32.137] */
2564 DWORD WINAPI RegEnumKey32A(
2565 HKEY hkey,
2566 DWORD iSubkey,
2567 LPSTR lpszName,
2568 DWORD lpcchName
2570 FILETIME ft;
2572 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2573 hkey,iSubkey,lpszName,lpcchName
2575 return RegEnumKeyEx32A(
2576 hkey,
2577 iSubkey,
2578 lpszName,
2579 &lpcchName,
2580 NULL,
2581 NULL,
2582 NULL,
2587 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2588 DWORD WINAPI RegEnumKey16(
2589 HKEY hkey,
2590 DWORD iSubkey,
2591 LPSTR lpszName,
2592 DWORD lpcchName
2594 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2595 hkey,iSubkey,lpszName,lpcchName
2597 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2601 * Enumerate Registry Values
2603 * Callpath:
2604 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2607 /* RegEnumValueW [ADVAPI32.142] */
2608 DWORD WINAPI RegEnumValue32W(
2609 HKEY hkey,
2610 DWORD iValue,
2611 LPWSTR lpszValue,
2612 LPDWORD lpcchValue,
2613 LPDWORD lpdReserved,
2614 LPDWORD lpdwType,
2615 LPBYTE lpbData,
2616 LPDWORD lpcbData
2618 LPKEYSTRUCT lpkey;
2619 LPKEYVALUE val;
2621 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2622 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2624 lpkey = lookup_hkey(hkey);
2625 if (!lpkey)
2626 return SHELL_ERROR_BADKEY;
2627 if (lpkey->nrofvalues<=iValue)
2628 return ERROR_NO_MORE_ITEMS;
2629 val = lpkey->values+iValue;
2631 if (val->name) {
2632 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2633 *lpcchValue = lstrlen32W(val->name)*2+2;
2634 return ERROR_MORE_DATA;
2636 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2637 *lpcchValue=lstrlen32W(val->name)*2+2;
2638 } else {
2639 /* how to handle NULL value? */
2640 *lpszValue = 0;
2641 *lpcchValue = 2;
2643 *lpdwType=val->type;
2644 if (lpbData) {
2645 if (val->len>*lpcbData)
2646 return ERROR_MORE_DATA;
2647 memcpy(lpbData,val->data,val->len);
2648 *lpcbData = val->len;
2650 return SHELL_ERROR_SUCCESS;
2653 /* RegEnumValueA [ADVAPI32.141] */
2654 DWORD WINAPI RegEnumValue32A(
2655 HKEY hkey,
2656 DWORD iValue,
2657 LPSTR lpszValue,
2658 LPDWORD lpcchValue,
2659 LPDWORD lpdReserved,
2660 LPDWORD lpdwType,
2661 LPBYTE lpbData,
2662 LPDWORD lpcbData
2664 LPWSTR lpszValueW;
2665 LPBYTE lpbDataW;
2666 DWORD ret,lpcbDataW;
2668 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2669 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2672 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2673 if (lpbData) {
2674 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2675 lpcbDataW = *lpcbData*2;
2676 } else
2677 lpbDataW = NULL;
2678 ret=RegEnumValue32W(
2679 hkey,
2680 iValue,
2681 lpszValueW,
2682 lpcchValue,
2683 lpdReserved,
2684 lpdwType,
2685 lpbDataW,
2686 &lpcbDataW
2689 if (ret==ERROR_SUCCESS) {
2690 lstrcpyWtoA(lpszValue,lpszValueW);
2691 if (lpbData) {
2692 if ((1<<*lpdwType) & UNICONVMASK) {
2693 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2694 } else {
2695 if (lpcbDataW > *lpcbData)
2696 ret = ERROR_MORE_DATA;
2697 else
2698 memcpy(lpbData,lpbDataW,lpcbDataW);
2700 *lpcbData = lpcbDataW;
2703 if (lpbDataW)
2704 free(lpbDataW);
2705 if (lpszValueW)
2706 free(lpszValueW);
2707 return ret;
2710 /* RegEnumValue [KERNEL.223] */
2711 DWORD WINAPI RegEnumValue16(
2712 HKEY hkey,
2713 DWORD iValue,
2714 LPSTR lpszValue,
2715 LPDWORD lpcchValue,
2716 LPDWORD lpdReserved,
2717 LPDWORD lpdwType,
2718 LPBYTE lpbData,
2719 LPDWORD lpcbData
2721 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2722 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2724 return RegEnumValue32A(
2725 hkey,
2726 iValue,
2727 lpszValue,
2728 lpcchValue,
2729 lpdReserved,
2730 lpdwType,
2731 lpbData,
2732 lpcbData
2737 * Close registry key
2739 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2740 DWORD WINAPI RegCloseKey(HKEY hkey) {
2741 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2742 remove_handle(hkey);
2743 return ERROR_SUCCESS;
2746 * Delete registry key
2748 * Callpath:
2749 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2751 /* RegDeleteKeyW [ADVAPI32.134] */
2752 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2753 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2754 LPWSTR *wps;
2755 int wpc,i;
2757 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2758 hkey,W2C(lpszSubKey,0)
2760 lpNextKey = lookup_hkey(hkey);
2761 if (!lpNextKey)
2762 return SHELL_ERROR_BADKEY;
2763 /* we need to know the previous key in the hier. */
2764 if (!lpszSubKey || !*lpszSubKey)
2765 return SHELL_ERROR_BADKEY;
2766 split_keypath(lpszSubKey,&wps,&wpc);
2767 i = 0;
2768 lpxkey = lpNextKey;
2769 while (i<wpc-1) {
2770 lpxkey=lpNextKey->nextsub;
2771 while (lpxkey) {
2772 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2773 break;
2774 lpxkey=lpxkey->next;
2776 if (!lpxkey) {
2777 FREE_KEY_PATH;
2778 /* not found is success */
2779 return SHELL_ERROR_SUCCESS;
2781 i++;
2782 lpNextKey = lpxkey;
2784 lpxkey = lpNextKey->nextsub;
2785 lplpPrevKey = &(lpNextKey->nextsub);
2786 while (lpxkey) {
2787 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2788 break;
2789 lplpPrevKey = &(lpxkey->next);
2790 lpxkey = lpxkey->next;
2792 if (!lpxkey)
2793 return SHELL_ERROR_SUCCESS;
2794 if (lpxkey->nextsub)
2795 return SHELL_ERROR_CANTWRITE;
2796 *lplpPrevKey = lpxkey->next;
2797 free(lpxkey->keyname);
2798 if (lpxkey->class)
2799 free(lpxkey->class);
2800 if (lpxkey->values)
2801 free(lpxkey->values);
2802 free(lpxkey);
2803 FREE_KEY_PATH;
2804 return SHELL_ERROR_SUCCESS;
2807 /* RegDeleteKeyA [ADVAPI32.133] */
2808 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2809 LPWSTR lpszSubKeyW;
2810 DWORD ret;
2812 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2813 hkey,lpszSubKey
2815 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2816 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2817 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2818 return ret;
2821 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2822 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2823 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2824 hkey,lpszSubKey
2826 return RegDeleteKey32A(hkey,lpszSubKey);
2830 * Delete registry value
2832 * Callpath:
2833 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2835 /* RegDeleteValueW [ADVAPI32.136] */
2836 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2838 DWORD i;
2839 LPKEYSTRUCT lpkey;
2840 LPKEYVALUE val;
2842 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2843 hkey,W2C(lpszValue,0)
2845 lpkey=lookup_hkey(hkey);
2846 if (!lpkey)
2847 return SHELL_ERROR_BADKEY;
2848 if (lpszValue) {
2849 for (i=0;i<lpkey->nrofvalues;i++)
2850 if ( lpkey->values[i].name &&
2851 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2853 break;
2854 } else {
2855 for (i=0;i<lpkey->nrofvalues;i++)
2856 if (lpkey->values[i].name==NULL)
2857 break;
2859 if (i==lpkey->nrofvalues)
2860 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2861 val = lpkey->values+i;
2862 if (val->name) free(val->name);
2863 if (val->data) free(val->data);
2864 memcpy(
2865 lpkey->values+i,
2866 lpkey->values+i+1,
2867 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2869 lpkey->values = (LPKEYVALUE)xrealloc(
2870 lpkey->values,
2871 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2873 lpkey->nrofvalues--;
2874 return SHELL_ERROR_SUCCESS;
2877 /* RegDeleteValueA [ADVAPI32.135] */
2878 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2880 LPWSTR lpszValueW;
2881 DWORD ret;
2883 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2884 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2885 ret=RegDeleteValue32W(hkey,lpszValueW);
2886 HeapFree(GetProcessHeap(),0,lpszValueW);
2887 return ret;
2890 /* RegDeleteValue [KERNEL.222] */
2891 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2893 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2894 return RegDeleteValue32A(hkey,lpszValue);
2897 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2898 DWORD WINAPI RegFlushKey(HKEY hkey)
2900 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2901 return SHELL_ERROR_SUCCESS;
2904 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2906 /* RegQueryInfoKeyW [ADVAPI32.153] */
2907 DWORD WINAPI RegQueryInfoKey32W(
2908 HKEY hkey,
2909 LPWSTR lpszClass,
2910 LPDWORD lpcchClass,
2911 LPDWORD lpdwReserved,
2912 LPDWORD lpcSubKeys,
2913 LPDWORD lpcchMaxSubkey,
2914 LPDWORD lpcchMaxClass,
2915 LPDWORD lpcValues,
2916 LPDWORD lpcchMaxValueName,
2917 LPDWORD lpccbMaxValueData,
2918 LPDWORD lpcbSecurityDescriptor,
2919 FILETIME *ft
2921 LPKEYSTRUCT lpkey,lpxkey;
2922 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2923 int i;
2925 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2926 lpkey=lookup_hkey(hkey);
2927 if (!lpkey)
2928 return SHELL_ERROR_BADKEY;
2929 if (lpszClass) {
2930 if (lpkey->class) {
2931 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2932 *lpcchClass=lstrlen32W(lpkey->class)*2;
2933 return ERROR_MORE_DATA;
2935 *lpcchClass=lstrlen32W(lpkey->class)*2;
2936 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2937 } else {
2938 *lpszClass = 0;
2939 *lpcchClass = 0;
2941 } else {
2942 if (lpcchClass)
2943 *lpcchClass = lstrlen32W(lpkey->class)*2;
2945 lpxkey=lpkey->nextsub;
2946 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2947 while (lpxkey) {
2948 nrofkeys++;
2949 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2950 maxsubkey=lstrlen32W(lpxkey->keyname);
2951 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2952 maxclass=lstrlen32W(lpxkey->class);
2953 if (lpxkey->nrofvalues>maxvalues)
2954 maxvalues=lpxkey->nrofvalues;
2955 for (i=0;i<lpxkey->nrofvalues;i++) {
2956 LPKEYVALUE val=lpxkey->values+i;
2958 if (val->name && lstrlen32W(val->name)>maxvname)
2959 maxvname=lstrlen32W(val->name);
2960 if (val->len>maxvdata)
2961 maxvdata=val->len;
2963 lpxkey=lpxkey->next;
2965 if (!maxclass) maxclass = 1;
2966 if (!maxvname) maxvname = 1;
2967 if (lpcSubKeys)
2968 *lpcSubKeys = nrofkeys;
2969 if (lpcchMaxSubkey)
2970 *lpcchMaxSubkey = maxsubkey*2;
2971 if (lpcchMaxClass)
2972 *lpcchMaxClass = maxclass*2;
2973 if (lpcValues)
2974 *lpcValues = maxvalues;
2975 if (lpcchMaxValueName)
2976 *lpcchMaxValueName= maxvname;
2977 if (lpccbMaxValueData)
2978 *lpccbMaxValueData= maxvdata;
2979 return SHELL_ERROR_SUCCESS;
2982 /* RegQueryInfoKeyA [ADVAPI32.152] */
2983 DWORD WINAPI RegQueryInfoKey32A(
2984 HKEY hkey,
2985 LPSTR lpszClass,
2986 LPDWORD lpcchClass,
2987 LPDWORD lpdwReserved,
2988 LPDWORD lpcSubKeys,
2989 LPDWORD lpcchMaxSubkey,
2990 LPDWORD lpcchMaxClass,
2991 LPDWORD lpcValues,
2992 LPDWORD lpcchMaxValueName,
2993 LPDWORD lpccbMaxValueData,
2994 LPDWORD lpcbSecurityDescriptor,
2995 FILETIME *ft
2997 LPWSTR lpszClassW;
2998 DWORD ret;
3000 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
3001 if (lpszClass) {
3002 *lpcchClass*= 2;
3003 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
3005 } else
3006 lpszClassW = NULL;
3007 ret=RegQueryInfoKey32W(
3008 hkey,
3009 lpszClassW,
3010 lpcchClass,
3011 lpdwReserved,
3012 lpcSubKeys,
3013 lpcchMaxSubkey,
3014 lpcchMaxClass,
3015 lpcValues,
3016 lpcchMaxValueName,
3017 lpccbMaxValueData,
3018 lpcbSecurityDescriptor,
3021 if (ret==ERROR_SUCCESS && lpszClass)
3022 lstrcpyWtoA(lpszClass,lpszClassW);
3023 if (lpcchClass)
3024 *lpcchClass/=2;
3025 if (lpcchMaxSubkey)
3026 *lpcchMaxSubkey/=2;
3027 if (lpcchMaxClass)
3028 *lpcchMaxClass/=2;
3029 if (lpcchMaxValueName)
3030 *lpcchMaxValueName/=2;
3031 if (lpszClassW)
3032 free(lpszClassW);
3033 return ret;
3035 /* RegConnectRegistryA [ADVAPI32.127] */
3036 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
3038 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
3039 machine,hkey,reskey
3041 return ERROR_FILE_NOT_FOUND; /* FIXME */