Release 970824
[wine/multimedia.git] / misc / registry.c
blob56dea7d12eb63893b10abd19b5d1eb5210d4ee07
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 (lpbData) {
2097 /* double buffer */
2098 buf = (LPBYTE)xmalloc((*lpcbData)*2);
2099 myxlen = *lpcbData*2;
2100 mylen = &myxlen;
2101 } else {
2102 buf=NULL;
2103 if (lpcbData) {
2104 myxlen = *lpcbData*2;
2105 mylen = &myxlen;
2106 } else
2107 mylen = NULL;
2109 if (lpszValueName)
2110 lpszValueNameW=strdupA2W(lpszValueName);
2111 else
2112 lpszValueNameW=NULL;
2114 if (lpdwType)
2115 type=*lpdwType;
2116 ret=RegQueryValueEx32W(
2117 hkey,
2118 lpszValueNameW,
2119 lpdwReserved,
2120 &type,
2121 buf,
2122 mylen
2124 if (lpdwType)
2125 *lpdwType=type;
2126 if (ret==ERROR_SUCCESS) {
2127 if (buf) {
2128 if (UNICONVMASK & (1<<(type))) {
2129 /* convert UNICODE to ASCII */
2130 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2131 *lpcbData = myxlen/2;
2132 } else {
2133 if (myxlen>*lpcbData)
2134 ret = ERROR_MORE_DATA;
2135 else
2136 memcpy(lpbData,buf,myxlen);
2138 *lpcbData = myxlen;
2140 } else {
2141 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2142 *lpcbData = myxlen/2;
2144 } else {
2145 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2146 *lpcbData = myxlen/2;
2148 if (buf)
2149 free(buf);
2150 return ret;
2153 /* RegQueryValueEx [KERNEL.225] */
2154 DWORD WINAPI RegQueryValueEx16(
2155 HKEY hkey,
2156 LPSTR lpszValueName,
2157 LPDWORD lpdwReserved,
2158 LPDWORD lpdwType,
2159 LPBYTE lpbData,
2160 LPDWORD lpcbData
2162 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2163 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2164 lpcbData?*lpcbData:0
2166 return RegQueryValueEx32A(
2167 hkey,
2168 lpszValueName,
2169 lpdwReserved,
2170 lpdwType,
2171 lpbData,
2172 lpcbData
2176 /* RegQueryValueA [ADVAPI32.156] */
2177 DWORD WINAPI RegQueryValue32A(
2178 HKEY hkey,
2179 LPSTR lpszSubKey,
2180 LPSTR lpszData,
2181 LPDWORD lpcbData
2183 HKEY xhkey;
2184 DWORD ret,lpdwType;
2186 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2187 hkey,lpszSubKey,lpszData,
2188 lpcbData?*lpcbData:0
2191 /* only open subkey, if we really do descend */
2192 if (lpszSubKey && *lpszSubKey) {
2193 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2194 if (ret!=ERROR_SUCCESS)
2195 return ret;
2196 } else
2197 xhkey = hkey;
2199 lpdwType = REG_SZ;
2200 ret = RegQueryValueEx32A(
2201 xhkey,
2202 NULL, /* lpszValueName NULL -> compat */
2203 NULL, /* lpdwReserved, must be NULL */
2204 &lpdwType,
2205 (LPBYTE)lpszData,
2206 lpcbData
2208 if (xhkey!=hkey)
2209 RegCloseKey(xhkey);
2210 return ret;
2213 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2214 DWORD WINAPI RegQueryValue16(
2215 HKEY hkey,
2216 LPSTR lpszSubKey,
2217 LPSTR lpszData,
2218 LPDWORD lpcbData
2220 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2221 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2223 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2224 * anyway, so we just mask out the high 16 bit.
2225 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2227 if (lpcbData)
2228 *lpcbData &= 0xFFFF;
2229 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2233 * Setting values of Registry keys
2235 * Callpath:
2236 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2237 * RegSetValue32W -> RegSetValueEx32W
2240 /* RegSetValueExW [ADVAPI32.170] */
2241 DWORD WINAPI RegSetValueEx32W(
2242 HKEY hkey,
2243 LPWSTR lpszValueName,
2244 DWORD dwReserved,
2245 DWORD dwType,
2246 LPBYTE lpbData,
2247 DWORD cbData
2249 LPKEYSTRUCT lpkey;
2250 int i;
2252 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2253 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2255 /* we no longer care about the lpbData type here... */
2256 lpkey = lookup_hkey(hkey);
2257 if (!lpkey)
2258 return SHELL_ERROR_BADKEY;
2260 lpkey->flags |= REG_OPTION_TAINTED;
2262 if (lpszValueName==NULL) {
2263 for (i=0;i<lpkey->nrofvalues;i++)
2264 if (lpkey->values[i].name==NULL)
2265 break;
2266 } else {
2267 for (i=0;i<lpkey->nrofvalues;i++)
2268 if ( lpkey->values[i].name &&
2269 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2271 break;
2273 if (i==lpkey->nrofvalues) {
2274 lpkey->values = (LPKEYVALUE)xrealloc(
2275 lpkey->values,
2276 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2278 lpkey->nrofvalues++;
2279 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2281 if (lpkey->values[i].name==NULL)
2282 if (lpszValueName)
2283 lpkey->values[i].name = strdupW(lpszValueName);
2284 else
2285 lpkey->values[i].name = NULL;
2286 lpkey->values[i].len = cbData;
2287 lpkey->values[i].type = dwType;
2288 if (lpkey->values[i].data !=NULL)
2289 free(lpkey->values[i].data);
2290 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2291 lpkey->values[i].lastmodified = time(NULL);
2292 memcpy(lpkey->values[i].data,lpbData,cbData);
2293 return SHELL_ERROR_SUCCESS;
2296 /* RegSetValueExA [ADVAPI32.169] */
2297 DWORD WINAPI RegSetValueEx32A(
2298 HKEY hkey,
2299 LPSTR lpszValueName,
2300 DWORD dwReserved,
2301 DWORD dwType,
2302 LPBYTE lpbData,
2303 DWORD cbData
2305 LPBYTE buf;
2306 LPWSTR lpszValueNameW;
2307 DWORD ret;
2309 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2310 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2312 if ((1<<dwType) & UNICONVMASK) {
2313 buf=(LPBYTE)strdupA2W(lpbData);
2314 cbData=2*strlen(lpbData)+2;
2315 } else
2316 buf=lpbData;
2317 if (lpszValueName)
2318 lpszValueNameW = strdupA2W(lpszValueName);
2319 else
2320 lpszValueNameW = NULL;
2321 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2322 if (lpszValueNameW)
2323 free(lpszValueNameW);
2324 if (buf!=lpbData)
2325 free(buf);
2326 return ret;
2329 /* RegSetValueEx [KERNEL.226] */
2330 DWORD WINAPI RegSetValueEx16(
2331 HKEY hkey,
2332 LPSTR lpszValueName,
2333 DWORD dwReserved,
2334 DWORD dwType,
2335 LPBYTE lpbData,
2336 DWORD cbData
2338 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2339 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2341 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2344 /* RegSetValueW [ADVAPI32.171] */
2345 DWORD WINAPI RegSetValue32W(
2346 HKEY hkey,
2347 LPCWSTR lpszSubKey,
2348 DWORD dwType,
2349 LPCWSTR lpszData,
2350 DWORD cbData
2352 HKEY xhkey;
2353 DWORD ret;
2355 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2356 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2358 if (lpszSubKey && *lpszSubKey) {
2359 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2360 if (ret!=ERROR_SUCCESS)
2361 return ret;
2362 } else
2363 xhkey=hkey;
2364 if (dwType!=REG_SZ) {
2365 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2366 dwType=REG_SZ;
2368 if (cbData!=2*lstrlen32W(lpszData)+2) {
2369 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2370 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2372 cbData=2*lstrlen32W(lpszData)+2;
2374 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2375 if (hkey!=xhkey)
2376 RegCloseKey(xhkey);
2377 return ret;
2380 /* RegSetValueA [ADVAPI32.168] */
2381 DWORD WINAPI RegSetValue32A(
2382 HKEY hkey,
2383 LPCSTR lpszSubKey,
2384 DWORD dwType,
2385 LPCSTR lpszData,
2386 DWORD cbData
2388 DWORD ret;
2389 HKEY xhkey;
2391 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2392 hkey,lpszSubKey,dwType,lpszData,cbData
2394 if (lpszSubKey && *lpszSubKey) {
2395 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2396 if (ret!=ERROR_SUCCESS)
2397 return ret;
2398 } else
2399 xhkey=hkey;
2401 if (dwType!=REG_SZ) {
2402 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2403 dwType=REG_SZ;
2405 if (cbData!=strlen(lpszData)+1)
2406 cbData=strlen(lpszData)+1;
2407 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2408 if (xhkey!=hkey)
2409 RegCloseKey(xhkey);
2410 return ret;
2413 /* RegSetValue [KERNEL.221] [SHELL.5] */
2414 DWORD WINAPI RegSetValue16(
2415 HKEY hkey,
2416 LPCSTR lpszSubKey,
2417 DWORD dwType,
2418 LPCSTR lpszData,
2419 DWORD cbData
2421 DWORD ret;
2422 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2423 hkey,lpszSubKey,dwType,lpszData,cbData
2425 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2426 return ret;
2430 * Key Enumeration
2432 * Callpath:
2433 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2434 * RegEnumKey32W -> RegEnumKeyEx32W
2437 /* RegEnumKeyExW [ADVAPI32.139] */
2438 DWORD WINAPI RegEnumKeyEx32W(
2439 HKEY hkey,
2440 DWORD iSubkey,
2441 LPWSTR lpszName,
2442 LPDWORD lpcchName,
2443 LPDWORD lpdwReserved,
2444 LPWSTR lpszClass,
2445 LPDWORD lpcchClass,
2446 FILETIME *ft
2448 LPKEYSTRUCT lpkey,lpxkey;
2450 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2451 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2453 lpkey=lookup_hkey(hkey);
2454 if (!lpkey)
2455 return SHELL_ERROR_BADKEY;
2456 if (!lpkey->nextsub)
2457 return ERROR_NO_MORE_ITEMS;
2458 lpxkey=lpkey->nextsub;
2459 while (iSubkey && lpxkey) {
2460 iSubkey--;
2461 lpxkey=lpxkey->next;
2463 if (iSubkey || !lpxkey)
2464 return ERROR_NO_MORE_ITEMS;
2465 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2466 return ERROR_MORE_DATA;
2467 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2468 if (lpszClass) {
2469 /* what should we write into it? */
2470 *lpszClass = 0;
2471 *lpcchClass = 2;
2473 return ERROR_SUCCESS;
2477 /* RegEnumKeyW [ADVAPI32.140] */
2478 DWORD WINAPI RegEnumKey32W(
2479 HKEY hkey,
2480 DWORD iSubkey,
2481 LPWSTR lpszName,
2482 DWORD lpcchName
2484 FILETIME ft;
2486 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2487 hkey,iSubkey,lpszName,lpcchName
2489 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2491 /* RegEnumKeyExA [ADVAPI32.138] */
2492 DWORD WINAPI RegEnumKeyEx32A(
2493 HKEY hkey,
2494 DWORD iSubkey,
2495 LPSTR lpszName,
2496 LPDWORD lpcchName,
2497 LPDWORD lpdwReserved,
2498 LPSTR lpszClass,
2499 LPDWORD lpcchClass,
2500 FILETIME *ft
2502 DWORD ret,lpcchNameW,lpcchClassW;
2503 LPWSTR lpszNameW,lpszClassW;
2506 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2507 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2509 if (lpszName) {
2510 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2511 lpcchNameW = *lpcchName*2;
2512 } else {
2513 lpszNameW = NULL;
2514 lpcchNameW = 0;
2516 if (lpszClass) {
2517 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2518 lpcchClassW = *lpcchClass*2;
2519 } else {
2520 lpszClassW =0;
2521 lpcchClassW=0;
2523 ret=RegEnumKeyEx32W(
2524 hkey,
2525 iSubkey,
2526 lpszNameW,
2527 &lpcchNameW,
2528 lpdwReserved,
2529 lpszClassW,
2530 &lpcchClassW,
2533 if (ret==ERROR_SUCCESS) {
2534 lstrcpyWtoA(lpszName,lpszNameW);
2535 *lpcchName=strlen(lpszName);
2536 if (lpszClassW) {
2537 lstrcpyWtoA(lpszClass,lpszClassW);
2538 *lpcchClass=strlen(lpszClass);
2541 if (lpszNameW)
2542 free(lpszNameW);
2543 if (lpszClassW)
2544 free(lpszClassW);
2545 return ret;
2548 /* RegEnumKeyA [ADVAPI32.137] */
2549 DWORD WINAPI RegEnumKey32A(
2550 HKEY hkey,
2551 DWORD iSubkey,
2552 LPSTR lpszName,
2553 DWORD lpcchName
2555 FILETIME ft;
2557 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2558 hkey,iSubkey,lpszName,lpcchName
2560 return RegEnumKeyEx32A(
2561 hkey,
2562 iSubkey,
2563 lpszName,
2564 &lpcchName,
2565 NULL,
2566 NULL,
2567 NULL,
2572 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2573 DWORD WINAPI RegEnumKey16(
2574 HKEY hkey,
2575 DWORD iSubkey,
2576 LPSTR lpszName,
2577 DWORD lpcchName
2579 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2580 hkey,iSubkey,lpszName,lpcchName
2582 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2586 * Enumerate Registry Values
2588 * Callpath:
2589 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2592 /* RegEnumValueW [ADVAPI32.142] */
2593 DWORD WINAPI RegEnumValue32W(
2594 HKEY hkey,
2595 DWORD iValue,
2596 LPWSTR lpszValue,
2597 LPDWORD lpcchValue,
2598 LPDWORD lpdReserved,
2599 LPDWORD lpdwType,
2600 LPBYTE lpbData,
2601 LPDWORD lpcbData
2603 LPKEYSTRUCT lpkey;
2604 LPKEYVALUE val;
2606 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2607 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2609 lpkey = lookup_hkey(hkey);
2610 if (!lpkey)
2611 return SHELL_ERROR_BADKEY;
2612 if (lpkey->nrofvalues<=iValue)
2613 return ERROR_NO_MORE_ITEMS;
2614 val = lpkey->values+iValue;
2616 if (val->name) {
2617 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2618 *lpcchValue = lstrlen32W(val->name)*2+2;
2619 return ERROR_MORE_DATA;
2621 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2622 *lpcchValue=lstrlen32W(val->name)*2+2;
2623 } else {
2624 /* how to handle NULL value? */
2625 *lpszValue = 0;
2626 *lpcchValue = 2;
2628 *lpdwType=val->type;
2629 if (lpbData) {
2630 if (val->len>*lpcbData)
2631 return ERROR_MORE_DATA;
2632 memcpy(lpbData,val->data,val->len);
2633 *lpcbData = val->len;
2635 return SHELL_ERROR_SUCCESS;
2638 /* RegEnumValueA [ADVAPI32.141] */
2639 DWORD WINAPI RegEnumValue32A(
2640 HKEY hkey,
2641 DWORD iValue,
2642 LPSTR lpszValue,
2643 LPDWORD lpcchValue,
2644 LPDWORD lpdReserved,
2645 LPDWORD lpdwType,
2646 LPBYTE lpbData,
2647 LPDWORD lpcbData
2649 LPWSTR lpszValueW;
2650 LPBYTE lpbDataW;
2651 DWORD ret,lpcbDataW;
2653 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2654 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2657 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2658 if (lpbData) {
2659 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2660 lpcbDataW = *lpcbData*2;
2661 } else
2662 lpbDataW = NULL;
2663 ret=RegEnumValue32W(
2664 hkey,
2665 iValue,
2666 lpszValueW,
2667 lpcchValue,
2668 lpdReserved,
2669 lpdwType,
2670 lpbDataW,
2671 &lpcbDataW
2674 if (ret==ERROR_SUCCESS) {
2675 lstrcpyWtoA(lpszValue,lpszValueW);
2676 if (lpbData) {
2677 if ((1<<*lpdwType) & UNICONVMASK) {
2678 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2679 } else {
2680 if (lpcbDataW > *lpcbData)
2681 ret = ERROR_MORE_DATA;
2682 else
2683 memcpy(lpbData,lpbDataW,lpcbDataW);
2685 *lpcbData = lpcbDataW;
2688 if (lpbDataW)
2689 free(lpbDataW);
2690 if (lpszValueW)
2691 free(lpszValueW);
2692 return ret;
2695 /* RegEnumValue [KERNEL.223] */
2696 DWORD WINAPI RegEnumValue16(
2697 HKEY hkey,
2698 DWORD iValue,
2699 LPSTR lpszValue,
2700 LPDWORD lpcchValue,
2701 LPDWORD lpdReserved,
2702 LPDWORD lpdwType,
2703 LPBYTE lpbData,
2704 LPDWORD lpcbData
2706 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2707 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2709 return RegEnumValue32A(
2710 hkey,
2711 iValue,
2712 lpszValue,
2713 lpcchValue,
2714 lpdReserved,
2715 lpdwType,
2716 lpbData,
2717 lpcbData
2722 * Close registry key
2724 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2725 DWORD WINAPI RegCloseKey(HKEY hkey) {
2726 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2727 remove_handle(hkey);
2728 return ERROR_SUCCESS;
2731 * Delete registry key
2733 * Callpath:
2734 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2736 /* RegDeleteKeyW [ADVAPI32.134] */
2737 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2738 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2739 LPWSTR *wps;
2740 int wpc,i;
2742 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2743 hkey,W2C(lpszSubKey,0)
2745 lpNextKey = lookup_hkey(hkey);
2746 if (!lpNextKey)
2747 return SHELL_ERROR_BADKEY;
2748 /* we need to know the previous key in the hier. */
2749 if (!lpszSubKey || !*lpszSubKey)
2750 return SHELL_ERROR_BADKEY;
2751 split_keypath(lpszSubKey,&wps,&wpc);
2752 i = 0;
2753 lpxkey = lpNextKey;
2754 while (i<wpc-1) {
2755 lpxkey=lpNextKey->nextsub;
2756 while (lpxkey) {
2757 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2758 break;
2759 lpxkey=lpxkey->next;
2761 if (!lpxkey) {
2762 FREE_KEY_PATH;
2763 /* not found is success */
2764 return SHELL_ERROR_SUCCESS;
2766 i++;
2767 lpNextKey = lpxkey;
2769 lpxkey = lpNextKey->nextsub;
2770 lplpPrevKey = &(lpNextKey->nextsub);
2771 while (lpxkey) {
2772 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2773 break;
2774 lplpPrevKey = &(lpxkey->next);
2775 lpxkey = lpxkey->next;
2777 if (!lpxkey)
2778 return SHELL_ERROR_SUCCESS;
2779 if (lpxkey->nextsub)
2780 return SHELL_ERROR_CANTWRITE;
2781 *lplpPrevKey = lpxkey->next;
2782 free(lpxkey->keyname);
2783 if (lpxkey->class)
2784 free(lpxkey->class);
2785 if (lpxkey->values)
2786 free(lpxkey->values);
2787 free(lpxkey);
2788 FREE_KEY_PATH;
2789 return SHELL_ERROR_SUCCESS;
2792 /* RegDeleteKeyA [ADVAPI32.133] */
2793 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2794 LPWSTR lpszSubKeyW;
2795 DWORD ret;
2797 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2798 hkey,lpszSubKey
2800 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2801 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2802 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2803 return ret;
2806 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2807 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2808 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2809 hkey,lpszSubKey
2811 return RegDeleteKey32A(hkey,lpszSubKey);
2815 * Delete registry value
2817 * Callpath:
2818 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2820 /* RegDeleteValueW [ADVAPI32.136] */
2821 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2823 DWORD i;
2824 LPKEYSTRUCT lpkey;
2825 LPKEYVALUE val;
2827 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2828 hkey,W2C(lpszValue,0)
2830 lpkey=lookup_hkey(hkey);
2831 if (!lpkey)
2832 return SHELL_ERROR_BADKEY;
2833 if (lpszValue) {
2834 for (i=0;i<lpkey->nrofvalues;i++)
2835 if ( lpkey->values[i].name &&
2836 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2838 break;
2839 } else {
2840 for (i=0;i<lpkey->nrofvalues;i++)
2841 if (lpkey->values[i].name==NULL)
2842 break;
2844 if (i==lpkey->nrofvalues)
2845 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2846 val = lpkey->values+i;
2847 if (val->name) free(val->name);
2848 if (val->data) free(val->data);
2849 memcpy(
2850 lpkey->values+i,
2851 lpkey->values+i+1,
2852 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2854 lpkey->values = (LPKEYVALUE)xrealloc(
2855 lpkey->values,
2856 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2858 lpkey->nrofvalues--;
2859 return SHELL_ERROR_SUCCESS;
2862 /* RegDeleteValueA [ADVAPI32.135] */
2863 DWORD WINAPI 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 WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2878 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2879 return RegDeleteValue32A(hkey,lpszValue);
2882 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2883 DWORD WINAPI RegFlushKey(HKEY hkey)
2885 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2886 return SHELL_ERROR_SUCCESS;
2889 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2891 /* RegQueryInfoKeyW [ADVAPI32.153] */
2892 DWORD WINAPI RegQueryInfoKey32W(
2893 HKEY hkey,
2894 LPWSTR lpszClass,
2895 LPDWORD lpcchClass,
2896 LPDWORD lpdwReserved,
2897 LPDWORD lpcSubKeys,
2898 LPDWORD lpcchMaxSubkey,
2899 LPDWORD lpcchMaxClass,
2900 LPDWORD lpcValues,
2901 LPDWORD lpcchMaxValueName,
2902 LPDWORD lpccbMaxValueData,
2903 LPDWORD lpcbSecurityDescriptor,
2904 FILETIME *ft
2906 LPKEYSTRUCT lpkey,lpxkey;
2907 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2908 int i;
2910 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2911 lpkey=lookup_hkey(hkey);
2912 if (!lpkey)
2913 return SHELL_ERROR_BADKEY;
2914 if (lpszClass) {
2915 if (lpkey->class) {
2916 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2917 *lpcchClass=lstrlen32W(lpkey->class)*2;
2918 return ERROR_MORE_DATA;
2920 *lpcchClass=lstrlen32W(lpkey->class)*2;
2921 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2922 } else {
2923 *lpszClass = 0;
2924 *lpcchClass = 0;
2926 } else {
2927 if (lpcchClass)
2928 *lpcchClass = lstrlen32W(lpkey->class)*2;
2930 lpxkey=lpkey->nextsub;
2931 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2932 while (lpxkey) {
2933 nrofkeys++;
2934 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2935 maxsubkey=lstrlen32W(lpxkey->keyname);
2936 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2937 maxclass=lstrlen32W(lpxkey->class);
2938 if (lpxkey->nrofvalues>maxvalues)
2939 maxvalues=lpxkey->nrofvalues;
2940 for (i=0;i<lpxkey->nrofvalues;i++) {
2941 LPKEYVALUE val=lpxkey->values+i;
2943 if (val->name && lstrlen32W(val->name)>maxvname)
2944 maxvname=lstrlen32W(val->name);
2945 if (val->len>maxvdata)
2946 maxvdata=val->len;
2948 lpxkey=lpxkey->next;
2950 if (!maxclass) maxclass = 1;
2951 if (!maxvname) maxvname = 1;
2952 if (lpcSubKeys)
2953 *lpcSubKeys = nrofkeys;
2954 if (lpcchMaxSubkey)
2955 *lpcchMaxSubkey = maxsubkey*2;
2956 if (lpcchMaxClass)
2957 *lpcchMaxClass = maxclass*2;
2958 if (lpcValues)
2959 *lpcValues = maxvalues;
2960 if (lpcchMaxValueName)
2961 *lpcchMaxValueName= maxvname;
2962 if (lpccbMaxValueData)
2963 *lpccbMaxValueData= maxvdata;
2964 return SHELL_ERROR_SUCCESS;
2967 /* RegQueryInfoKeyA [ADVAPI32.152] */
2968 DWORD WINAPI RegQueryInfoKey32A(
2969 HKEY hkey,
2970 LPSTR lpszClass,
2971 LPDWORD lpcchClass,
2972 LPDWORD lpdwReserved,
2973 LPDWORD lpcSubKeys,
2974 LPDWORD lpcchMaxSubkey,
2975 LPDWORD lpcchMaxClass,
2976 LPDWORD lpcValues,
2977 LPDWORD lpcchMaxValueName,
2978 LPDWORD lpccbMaxValueData,
2979 LPDWORD lpcbSecurityDescriptor,
2980 FILETIME *ft
2982 LPWSTR lpszClassW;
2983 DWORD ret;
2985 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2986 if (lpszClass) {
2987 *lpcchClass*= 2;
2988 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2990 } else
2991 lpszClassW = NULL;
2992 ret=RegQueryInfoKey32W(
2993 hkey,
2994 lpszClassW,
2995 lpcchClass,
2996 lpdwReserved,
2997 lpcSubKeys,
2998 lpcchMaxSubkey,
2999 lpcchMaxClass,
3000 lpcValues,
3001 lpcchMaxValueName,
3002 lpccbMaxValueData,
3003 lpcbSecurityDescriptor,
3006 if (ret==ERROR_SUCCESS && lpszClass)
3007 lstrcpyWtoA(lpszClass,lpszClassW);
3008 if (lpcchClass)
3009 *lpcchClass/=2;
3010 if (lpcchMaxSubkey)
3011 *lpcchMaxSubkey/=2;
3012 if (lpcchMaxClass)
3013 *lpcchMaxClass/=2;
3014 if (lpcchMaxValueName)
3015 *lpcchMaxValueName/=2;
3016 if (lpszClassW)
3017 free(lpszClassW);
3018 return ret;
3020 /* RegConnectRegistryA [ADVAPI32.127] */
3021 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
3023 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
3024 machine,hkey,reskey
3026 return ERROR_FILE_NOT_FOUND; /* FIXME */