Release 980329
[wine/multimedia.git] / misc / registry.c
blob3f7ac03b5bcd6138e37a5e76c3ed474e39d34ae3
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
6 * December 21, 1997 - Kevin Cozens
7 * Fixed bugs in the _w95_loadreg() function. Added extra information
8 * regarding the format of the Windows '95 registry files.
9 */
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
19 #include <sys/stat.h>
20 #include <pwd.h>
21 #include <assert.h>
22 #include <time.h>
23 #include "windows.h"
24 #include "win.h"
25 #include "winerror.h"
26 #include "file.h"
27 #include "heap.h"
28 #include "debug.h"
29 #include "xmalloc.h"
30 #include "winreg.h"
32 #define DEBUG_W95_LOADREG 0
34 /* FIXME: following defines should be configured global ... */
36 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
37 #define WINE_PREFIX "/.wine"
38 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
39 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
41 /* relative in ~user/.wine/ : */
42 #define SAVE_CURRENT_USER "user.reg"
43 #define SAVE_LOCAL_MACHINE "system.reg"
45 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
46 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
48 /* one value of a key */
49 typedef struct tagKEYVALUE
51 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
52 DWORD type; /* type of value */
53 DWORD len; /* length of data in BYTEs */
54 DWORD lastmodified; /* time of seconds since 1.1.1970 */
55 LPBYTE data; /* content, may be strings, binaries, etc. */
56 } KEYVALUE,*LPKEYVALUE;
58 /* a registry key */
59 typedef struct tagKEYSTRUCT
61 LPWSTR keyname; /* name of THIS key (UNICODE) */
62 DWORD flags; /* flags. */
63 LPWSTR class;
64 /* values */
65 DWORD nrofvalues; /* nr of values in THIS key */
66 LPKEYVALUE values; /* values in THIS key */
67 /* key management pointers */
68 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
69 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
70 } KEYSTRUCT, *LPKEYSTRUCT;
73 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
74 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
75 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
76 static KEYSTRUCT *key_users=NULL; /* all users? */
78 /* dynamic, not saved */
79 static KEYSTRUCT *key_performance_data=NULL;
80 static KEYSTRUCT *key_current_config=NULL;
81 static KEYSTRUCT *key_dyn_data=NULL;
83 /* what valuetypes do we need to convert? */
84 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
86 extern LPWSTR __cdecl CRTDLL_wcschr(LPWSTR a,WCHAR c);
88 static LPWSTR strdupA2W(LPCSTR src)
90 LPWSTR dest=xmalloc(2*strlen(src)+2);
91 lstrcpyAtoW(dest,src);
92 return dest;
95 static LPWSTR strdupW(LPCWSTR a) {
96 LPWSTR b;
97 int len;
99 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
100 b=(LPWSTR)xmalloc(len);
101 memcpy(b,a,len);
102 return b;
106 static struct openhandle {
107 LPKEYSTRUCT lpkey;
108 HKEY hkey;
109 REGSAM accessmask;
110 } *openhandles=NULL;
111 static int nrofopenhandles=0;
112 static int currenthandle=1;
114 static void
115 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
116 int i;
118 for (i=0;i<nrofopenhandles;i++) {
119 if (openhandles[i].lpkey==lpkey) {
120 WARN(reg, "Tried to add %p twice!\n",lpkey);
122 if (openhandles[i].hkey==hkey) {
123 WARN(reg, "Tried to add %lx twice!\n",(LONG)hkey);
126 openhandles=xrealloc( openhandles,
127 sizeof(struct openhandle)*(nrofopenhandles+1)
129 openhandles[i].lpkey = lpkey;
130 openhandles[i].hkey = hkey;
131 openhandles[i].accessmask= accessmask;
132 nrofopenhandles++;
135 static LPKEYSTRUCT
136 get_handle(HKEY hkey) {
137 int i;
139 for (i=0;i<nrofopenhandles;i++)
140 if (openhandles[i].hkey==hkey)
141 return openhandles[i].lpkey;
142 WARN(reg, "Didn't find handle %lx?\n",(LONG)hkey);
143 return NULL;
146 static void
147 remove_handle(HKEY hkey) {
148 int i;
150 for (i=0;i<nrofopenhandles;i++)
151 if (openhandles[i].hkey==hkey)
152 break;
153 if (i==nrofopenhandles) {
154 WARN(reg, "Didn't find handle %08x?\n",hkey);
155 return;
157 memcpy( openhandles+i,
158 openhandles+i+1,
159 sizeof(struct openhandle)*(nrofopenhandles-i-1)
161 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
162 nrofopenhandles--;
163 return;
167 /* debug function, converts a unicode into a static memory area
168 * (sub for using two static strings, in case we need them in a single call)
170 LPSTR
171 W2C(LPCWSTR x,int sub) {
172 static LPSTR unicodedebug[2]={NULL,NULL};
173 if (x==NULL)
174 return "<NULL>";
175 if (sub!=0 && sub!=1)
176 return "<W2C:bad sub>";
177 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
178 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
179 return unicodedebug[sub];
182 static LPKEYSTRUCT
183 lookup_hkey(HKEY hkey) {
184 switch (hkey) {
185 case 0x00000000:
186 case 0x00000001:
187 case HKEY_CLASSES_ROOT:
188 return key_classes_root;
189 case HKEY_CURRENT_USER:
190 return key_current_user;
191 case HKEY_LOCAL_MACHINE:
192 return key_local_machine;
193 case HKEY_USERS:
194 return key_users;
195 case HKEY_PERFORMANCE_DATA:
196 return key_performance_data;
197 case HKEY_DYN_DATA:
198 return key_dyn_data;
199 case HKEY_CURRENT_CONFIG:
200 return key_current_config;
201 default:
202 WARN(reg, "(%lx), special key!\n",
203 (LONG)hkey
205 return get_handle(hkey);
207 /*NOTREACHED*/
211 * splits the unicode string 'wp' into an array of strings.
212 * the array is allocated by this function.
213 * the number of components will be stored in 'wpc'
214 * Free the array using FREE_KEY_PATH
216 static void
217 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
218 int i,j,len;
219 LPWSTR ws;
221 ws = HEAP_strdupW( SystemHeap, 0, wp );
222 *wpc = 1;
223 for (i=0;ws[i];i++) {
224 if (ws[i]=='\\') {
225 ws[i]=0;
226 (*wpc)++;
229 len = i;
230 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
231 (*wpv)[0]= ws;
232 j = 1;
233 for (i=1;i<len;i++)
234 if (ws[i-1]==0)
235 (*wpv)[j++]=ws+i;
236 (*wpv)[j]=NULL;
238 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
241 * Shell initialisation, allocates keys.
243 void SHELL_StartupRegistry();
244 void
245 SHELL_Init() {
246 struct passwd *pwd;
248 HKEY cl_r_hkey,c_u_hkey;
249 #define ADD_ROOT_KEY(xx) \
250 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
251 memset(xx,'\0',sizeof(KEYSTRUCT));\
252 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
254 ADD_ROOT_KEY(key_local_machine);
255 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
256 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
257 exit(1);
259 key_classes_root = lookup_hkey(cl_r_hkey);
261 ADD_ROOT_KEY(key_users);
263 #if 0
264 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
265 * (later, when a win32 registry editing tool becomes avail.)
267 while (pwd=getpwent()) {
268 if (pwd->pw_name == NULL)
269 continue;
270 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
271 RegCloseKey(c_u_hkey);
273 #endif
274 pwd=getpwuid(getuid());
275 if (pwd && pwd->pw_name) {
276 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
277 key_current_user = lookup_hkey(c_u_hkey);
278 } else {
279 ADD_ROOT_KEY(key_current_user);
281 ADD_ROOT_KEY(key_performance_data);
282 ADD_ROOT_KEY(key_current_config);
283 ADD_ROOT_KEY(key_dyn_data);
284 #undef ADD_ROOT_KEY
285 SHELL_StartupRegistry();
289 void
290 SHELL_StartupRegistry() {
291 HKEY hkey;
292 char buf[200];
294 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&hkey);
295 RegCloseKey(hkey);
297 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
298 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
299 RegCloseKey(hkey);
300 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
301 * CurrentVersion
302 * CurrentBuildNumber
303 * CurrentType
304 * string RegisteredOwner
305 * string RegisteredOrganization
308 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
309 * string SysContact
310 * string SysLocation
311 * SysServices
313 if (-1!=gethostname(buf,200)) {
314 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
315 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
316 RegCloseKey(hkey);
319 /************************ SAVE Registry Function ****************************/
321 #define REGISTRY_SAVE_VERSION 0x00000001
323 /* Registry saveformat:
324 * If you change it, increase above number by 1, which will flush
325 * old registry database files.
327 * Global:
328 * "WINE REGISTRY Version %d"
329 * subkeys....
330 * Subkeys:
331 * keyname
332 * valuename=lastmodified,type,data
333 * ...
334 * subkeys
335 * ...
336 * keyname,valuename,stringdata:
337 * the usual ascii characters from 0x00-0xff (well, not 0x00)
338 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
339 * ( "=\\\t" escaped in \uXXXX form.)
340 * type,lastmodified:
341 * int
343 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
345 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
346 * SaveOnlyUpdatedKeys=yes
348 static int
349 _save_check_tainted(LPKEYSTRUCT lpkey) {
350 int tainted;
352 if (!lpkey)
353 return 0;
354 if (lpkey->flags & REG_OPTION_TAINTED)
355 tainted = 1;
356 else
357 tainted = 0;
358 while (lpkey) {
359 if (_save_check_tainted(lpkey->nextsub)) {
360 lpkey->flags |= REG_OPTION_TAINTED;
361 tainted = 1;
363 lpkey = lpkey->next;
365 return tainted;
368 static void
369 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
370 LPWSTR s;
371 int doescape;
373 if (wstr==NULL)
374 return;
375 s=wstr;
376 while (*s) {
377 doescape=0;
378 if (*s>0xff)
379 doescape = 1;
380 if (*s=='\n')
381 doescape = 1;
382 if (escapeeq && *s=='=')
383 doescape = 1;
384 if (*s=='\\')
385 fputc(*s,F); /* if \\ then put it twice. */
386 if (doescape)
387 fprintf(F,"\\u%04x",*((unsigned short*)s));
388 else
389 fputc(*s,F);
390 s++;
394 static int
395 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
396 LPKEYSTRUCT lpxkey;
397 int i,tabs,j;
399 lpxkey = lpkey;
400 while (lpxkey) {
401 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
402 (all || (lpxkey->flags & REG_OPTION_TAINTED))
404 for (tabs=level;tabs--;)
405 fputc('\t',F);
406 _save_USTRING(F,lpxkey->keyname,1);
407 fputs("\n",F);
408 for (i=0;i<lpxkey->nrofvalues;i++) {
409 LPKEYVALUE val=lpxkey->values+i;
411 for (tabs=level+1;tabs--;)
412 fputc('\t',F);
413 _save_USTRING(F,val->name,0);
414 fputc('=',F);
415 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
416 if ((1<<val->type) & UNICONVMASK)
417 _save_USTRING(F,(LPWSTR)val->data,0);
418 else
419 for (j=0;j<val->len;j++)
420 fprintf(F,"%02x",*((unsigned char*)val->data+j));
421 fputs("\n",F);
423 /* descend recursively */
424 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
425 return 0;
427 lpxkey=lpxkey->next;
429 return 1;
432 static int
433 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
434 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
435 _save_check_tainted(lpkey->nextsub);
436 return _savesubkey(F,lpkey->nextsub,0,all);
439 static BOOL32
440 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
441 FILE *F;
443 F=fopen(fn,"w");
444 if (F==NULL) {
445 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
446 fn,strerror(errno)
448 return FALSE;
450 if (!_savesubreg(F,lpkey,all)) {
451 fclose(F);
452 unlink(fn);
453 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
454 return FALSE;
456 fclose(F);
457 return TRUE;
460 void
461 SHELL_SaveRegistry() {
462 char *fn;
463 struct passwd *pwd;
464 char buf[4];
465 HKEY hkey;
466 int all;
468 all=0;
469 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
470 strcpy(buf,"yes");
471 } else {
472 DWORD len,junk,type;
474 len=4;
475 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
476 hkey,
477 VAL_SAVEUPDATED,
478 &junk,
479 &type,
480 buf,
481 &len
482 ))|| (type!=REG_SZ)
484 strcpy(buf,"yes");
485 RegCloseKey(hkey);
487 if (lstrcmpi32A(buf,"yes"))
488 all=1;
489 pwd=getpwuid(getuid());
490 if (pwd!=NULL && pwd->pw_dir!=NULL)
492 char *tmp;
494 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
495 strlen(SAVE_CURRENT_USER) + 2 );
496 strcpy(fn,pwd->pw_dir);
497 strcat(fn,WINE_PREFIX);
498 /* create the directory. don't care about errorcodes. */
499 mkdir(fn,0755); /* drwxr-xr-x */
500 strcat(fn,"/"SAVE_CURRENT_USER);
501 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
502 strcpy(tmp,fn);strcat(tmp,".tmp");
503 if (_savereg(key_current_user,tmp,all)) {
504 if (-1==rename(tmp,fn)) {
505 perror("rename tmp registry");
506 unlink(tmp);
509 free(tmp);
510 free(fn);
511 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
512 strcpy(fn,pwd->pw_dir);
513 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
514 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
515 strcpy(tmp,fn);strcat(tmp,".tmp");
516 if (_savereg(key_local_machine,tmp,all)) {
517 if (-1==rename(tmp,fn)) {
518 perror("rename tmp registry");
519 unlink(tmp);
522 free(tmp);
523 free(fn);
524 } else
525 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
528 /************************ LOAD Registry Function ****************************/
530 static LPKEYSTRUCT
531 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
532 LPKEYSTRUCT lpxkey,*lplpkey;
534 if (keyname[0]==0) {
535 free(keyname);
536 return lpkey;
538 lplpkey= &(lpkey->nextsub);
539 lpxkey = *lplpkey;
540 while (lpxkey) {
541 if (!lstrcmpi32W(lpxkey->keyname,keyname))
542 break;
543 lplpkey = &(lpxkey->next);
544 lpxkey = *lplpkey;
546 if (lpxkey==NULL) {
547 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
548 lpxkey = *lplpkey;
549 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
550 lpxkey->keyname = keyname;
551 } else
552 free(keyname);
553 return lpxkey;
556 static void
557 _find_or_add_value(
558 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
559 DWORD lastmodified
561 LPKEYVALUE val=NULL;
562 int i;
564 if (name && !*name) {/* empty string equals default (NULL) value */
565 free(name);
566 name = NULL;
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 if (*ws)
694 *str = strdupW(*str);
695 else
696 *str = NULL;
697 free(ws);
698 return s;
701 static int
702 _wine_loadsubkey(
703 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
705 LPKEYSTRUCT lpxkey;
706 int i;
707 char *s;
708 LPWSTR name;
710 lpkey->flags |= optflag;
712 /* good. we already got a line here ... so parse it */
713 lpxkey = NULL;
714 while (1) {
715 i=0;s=*buf;
716 while (*s=='\t') {
717 s++;
718 i++;
720 if (i>level) {
721 if (lpxkey==NULL) {
722 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
723 return 0;
725 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
726 continue;
728 /* let the caller handle this line */
729 if (i<level || **buf=='\0')
730 return 1;
732 /* it can be: a value or a keyname. Parse the name first */
733 s=_wine_read_USTRING(s,&name);
735 /* switch() default: hack to avoid gotos */
736 switch (0) {
737 default:
738 if (*s=='\0') {
739 lpxkey=_find_or_add_key(lpkey,name);
740 } else {
741 LPBYTE data;
742 int len,lastmodified,type;
744 if (*s!='=') {
745 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
746 break;
748 s++;
749 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
750 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
751 break;
753 /* skip the 2 , */
754 s=strchr(s,',');s++;
755 s=strchr(s,',');s++;
756 if ((1<<type) & UNICONVMASK) {
757 s=_wine_read_USTRING(s,(LPWSTR*)&data);
758 if (data)
759 len = lstrlen32W((LPWSTR)data)*2+2;
760 else
761 len = 0;
762 } else {
763 len=strlen(s)/2;
764 data = (LPBYTE)xmalloc(len+1);
765 for (i=0;i<len;i++) {
766 data[i]=0;
767 if (*s>='0' && *s<='9')
768 data[i]=(*s-'0')<<4;
769 if (*s>='a' && *s<='f')
770 data[i]=(*s-'a')<<4;
771 if (*s>='A' && *s<='F')
772 data[i]=(*s-'A')<<4;
773 s++;
774 if (*s>='0' && *s<='9')
775 data[i]|=*s-'0';
776 if (*s>='a' && *s<='f')
777 data[i]|=*s-'a';
778 if (*s>='A' && *s<='F')
779 data[i]|=*s-'A';
780 s++;
783 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
786 /* read the next line */
787 if (!_wine_read_line(F,buf,buflen))
788 return 1;
790 return 1;
793 static int
794 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
795 int ver;
796 char *buf;
797 int buflen;
799 buf=xmalloc(10);buflen=10;
800 if (!_wine_read_line(F,&buf,&buflen)) {
801 free(buf);
802 return 0;
804 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
805 free(buf);
806 return 0;
808 if (ver!=REGISTRY_SAVE_VERSION) {
809 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
810 free(buf);
811 return 0;
813 if (!_wine_read_line(F,&buf,&buflen)) {
814 free(buf);
815 return 0;
817 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
818 free(buf);
819 return 0;
821 free(buf);
822 return 1;
825 static void
826 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
827 FILE *F;
829 F=fopen(fn,"rb");
830 if (F==NULL) {
831 WARN(reg,"Couldn't open %s for reading: %s\n",
832 fn,strerror(errno)
834 return;
836 if (!_wine_loadsubreg(F,lpkey,optflag)) {
837 fclose(F);
838 unlink(fn);
839 return;
841 fclose(F);
844 static void
845 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
846 LPKEYSTRUCT lpxkey;
847 int j;
848 LPKEYVALUE valfrom;
850 from=from->nextsub;
851 while (from) {
852 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
854 for (j=0;j<from->nrofvalues;j++) {
855 LPWSTR name;
856 LPBYTE data;
858 valfrom = from->values+j;
859 name=valfrom->name;
860 if (name) name=strdupW(name);
861 data=(LPBYTE)xmalloc(valfrom->len);
862 memcpy(data,valfrom->data,valfrom->len);
864 _find_or_add_value(
865 lpxkey,
866 name,
867 valfrom->type,
868 data,
869 valfrom->len,
870 valfrom->lastmodified
873 _copy_registry(from,lpxkey);
874 from = from->next;
878 /* WINDOWS 95 REGISTRY LOADER */
880 * Structure of a win95 registry database.
881 * main header:
882 * 0 : "CREG" - magic
883 * 4 : DWORD version
884 * 8 : DWORD offset_of_RGDB_part
885 * 0C..0F: ? (someone fill in please)
886 * 10: WORD number of RGDB blocks
887 * 12: WORD ?
888 * 14: WORD always 0000?
889 * 16: WORD always 0001?
890 * 18..1F: ? (someone fill in please)
892 * 20: RGKN_section:
893 * header:
894 * 0 : "RGKN" - magic
895 * 4 : DWORD offset to first RGDB section
896 * 8 : DWORD offset to ?
897 * C..0x1B: ? (fill in)
898 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
900 * Disk Key Entry Structure:
901 * 00: DWORD - Free entry indicator(?)
902 * 04: DWORD - Hash = sum of bytes of keyname
903 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
904 * 0C: DWORD - disk address of PreviousLevel Key.
905 * 10: DWORD - disk address of Next Sublevel Key.
906 * 14: DWORD - disk address of Next Key (on same level).
907 * DKEP>18: WORD - Nr, Low Significant part.
908 * 1A: WORD - Nr, High Significant part.
910 * The disk address always points to the nr part of the previous key entry
911 * of the referenced key. Don't ask me why, or even if I got this correct
912 * from staring at 1kg of hexdumps. (DKEP)
914 * The High significant part of the structure seems to equal the number
915 * of the RGDB section. The low significant part is a unique ID within
916 * that RGDB section
918 * There are two minor corrections to the position of that structure.
919 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
920 * the DKE reread from there.
921 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
922 * CPS - I have not experienced the above phenomenon in my registry files
924 * RGDB_section:
925 * 00: "RGDB" - magic
926 * 04: DWORD offset to next RGDB section
927 * 08: DWORD ?
928 * 0C: WORD always 000d?
929 * 0E: WORD RGDB block number
930 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
931 * 14..1F: ?
932 * 20.....: disk keys
934 * disk key:
935 * 00: DWORD nextkeyoffset - offset to the next disk key structure
936 * 08: WORD nrLS - low significant part of NR
937 * 0A: WORD nrHS - high significant part of NR
938 * 0C: DWORD bytesused - bytes used in this structure.
939 * 10: WORD name_len - length of name in bytes. without \0
940 * 12: WORD nr_of_values - number of values.
941 * 14: char name[name_len] - name string. No \0.
942 * 14+name_len: disk values
943 * nextkeyoffset: ... next disk key
945 * disk value:
946 * 00: DWORD type - value type (hmm, could be WORD too)
947 * 04: DWORD - unknown, usually 0
948 * 08: WORD namelen - length of Name. 0 means name=NULL
949 * 0C: WORD datalen - length of Data.
950 * 10: char name[namelen] - name, no \0
951 * 10+namelen: BYTE data[datalen] - data, without \0 if string
952 * 10+namelen+datalen: next values or disk key
954 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
955 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
956 * structure) and reading another RGDB_section.
957 * repeat until end of file.
959 * An interesting relationship exists in RGDB_section. The value at offset
960 * 10 equals the value at offset 4 minus the value at offset 8. I have no
961 * idea at the moment what this means. (Kevin Cozens)
963 * FIXME: this description needs some serious help, yes.
966 struct _w95keyvalue {
967 unsigned long type;
968 unsigned short datalen;
969 char *name;
970 unsigned char *data;
971 unsigned long x1;
972 int lastmodified;
975 struct _w95key {
976 char *name;
977 int nrofvals;
978 struct _w95keyvalue *values;
979 struct _w95key *prevlvl;
980 struct _w95key *nextsub;
981 struct _w95key *next;
985 struct _w95_info {
986 char *rgknbuffer;
987 int rgknsize;
988 char *rgdbbuffer;
989 int rgdbsize;
990 int depth;
991 int lastmodified;
994 LPWSTR strcvtA2W(LPCSTR src, int nchars)
997 LPWSTR dest = xmalloc (2 * nchars + 2);
999 lstrcpynAtoW(dest,src,nchars+1);
1000 dest[nchars] = 0;
1001 return dest;
1004 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1005 int nrLS, int nrMS, struct _w95_info *info )
1008 /* Disk Key Header structure (RGDB part) */
1009 struct dkh {
1010 unsigned long nextkeyoff;
1011 unsigned short nrLS;
1012 unsigned short nrMS;
1013 unsigned long bytesused;
1014 unsigned short keynamelen;
1015 unsigned short values;
1016 unsigned long xx1;
1017 /* keyname */
1018 /* disk key values or nothing */
1020 /* Disk Key Value structure */
1021 struct dkv {
1022 unsigned long type;
1023 unsigned long x1;
1024 unsigned short valnamelen;
1025 unsigned short valdatalen;
1026 /* valname, valdata */
1030 struct dkh dkh;
1031 int bytesread = 0;
1032 char *rgdbdata = info->rgdbbuffer;
1033 int nbytes = info->rgdbsize;
1034 char *curdata = rgdbdata;
1035 char *end = rgdbdata + nbytes;
1036 int off_next_rgdb;
1037 char *next = rgdbdata;
1038 int nrgdb, i;
1039 LPKEYSTRUCT lpxkey;
1041 do {
1042 curdata = next;
1043 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1045 memcpy(&off_next_rgdb,curdata+4,4);
1046 next = curdata + off_next_rgdb;
1047 nrgdb = (int) *((short *)curdata + 7);
1049 } while (nrgdb != nrMS && (next < end));
1051 /* curdata now points to the start of the right RGDB section */
1052 curdata += 0x20;
1054 #define XREAD(whereto,len) \
1055 if ((curdata + len) <end) {\
1056 memcpy(whereto,curdata,len);\
1057 curdata+=len;\
1058 bytesread+=len;\
1061 do {
1062 XREAD(&dkh, sizeof (dkh));
1063 if (dkh.nrLS == nrLS) break;
1065 curdata += dkh.nextkeyoff - sizeof(dkh);
1066 } while (curdata < next);
1068 if (dkh.nrLS != nrLS) return (NULL);
1070 if (nrgdb != dkh.nrMS) {
1071 return (NULL);
1074 assert((dkh.keynamelen<2) || curdata[0]);
1075 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1076 curdata += dkh.keynamelen;
1078 for (i=0;i< dkh.values; i++) {
1079 struct dkv dkv;
1080 LPBYTE data;
1081 int len;
1082 LPWSTR name;
1084 XREAD(&dkv,sizeof(dkv));
1086 name = strcvtA2W(curdata, dkv.valnamelen);
1087 curdata += dkv.valnamelen;
1089 if ((1 << dkv.type) & UNICONVMASK) {
1090 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1091 len = 2*(dkv.valdatalen + 1);
1092 } else {
1093 /* I don't think we want to NULL terminate all data */
1094 data = xmalloc(dkv.valdatalen);
1095 memcpy (data, curdata, dkv.valdatalen);
1096 len = dkv.valdatalen;
1099 curdata += dkv.valdatalen;
1101 _find_or_add_value(
1102 lpxkey,
1103 name,
1104 dkv.type,
1105 data,
1106 len,
1107 info->lastmodified
1112 return (lpxkey);
1115 static void
1116 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1119 /* Disk Key Entry structure (RGKN part) */
1120 struct dke {
1121 unsigned long x1;
1122 unsigned long x2;
1123 unsigned long x3;/*usually 0xFFFFFFFF */
1124 unsigned long prevlvl;
1125 unsigned long nextsub;
1126 unsigned long next;
1127 unsigned short nrLS;
1128 unsigned short nrMS;
1129 } *dke = (struct dke *)off;
1130 LPKEYSTRUCT lpxkey;
1132 if (dke == NULL) {
1133 dke = (struct dke *) ((char *)info->rgknbuffer);
1136 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1137 /* XXX <-- This is a hack*/
1138 if (!lpxkey) {
1139 lpxkey = prevkey;
1142 if (dke->nextsub != -1 &&
1143 ((dke->nextsub - 0x20) < info->rgknsize)
1144 && (dke->nextsub > 0x20)) {
1146 _w95_walkrgkn(lpxkey,
1147 info->rgknbuffer + dke->nextsub - 0x20,
1148 info);
1151 if (dke->next != -1 &&
1152 ((dke->next - 0x20) < info->rgknsize) &&
1153 (dke->next > 0x20)) {
1154 _w95_walkrgkn(prevkey,
1155 info->rgknbuffer + dke->next - 0x20,
1156 info);
1159 return;
1162 static void
1163 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1164 HFILE32 hfd;
1165 char magic[5];
1166 unsigned long where,version,rgdbsection,end;
1167 struct _w95_info info;
1168 OFSTRUCT ofs;
1169 BY_HANDLE_FILE_INFORMATION hfdinfo;
1171 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1172 hfd=OpenFile32(fn,&ofs,OF_READ);
1173 if (hfd==HFILE_ERROR32)
1174 return;
1175 magic[4]=0;
1176 if (4!=_lread32(hfd,magic,4))
1177 return;
1178 if (strcmp(magic,"CREG")) {
1179 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1180 return;
1182 if (4!=_lread32(hfd,&version,4))
1183 return;
1184 if (4!=_lread32(hfd,&rgdbsection,4))
1185 return;
1186 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1187 return;
1188 if (4!=_lread32(hfd,magic,4))
1189 return;
1190 if (strcmp(magic,"RGKN")) {
1191 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1192 return;
1195 /* STEP 1: Keylink structures */
1196 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1197 return;
1198 where = 0x40;
1199 end = rgdbsection;
1201 info.rgknsize = end - where;
1202 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1203 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1204 return;
1206 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1207 return;
1209 end = hfdinfo.nFileSizeLow;
1210 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1212 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1213 return;
1215 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1216 info.rgdbsize = end - rgdbsection;
1218 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1219 return;
1220 _lclose32(hfd);
1222 _w95_walkrgkn(lpkey, NULL, &info);
1224 free (info.rgdbbuffer);
1225 free (info.rgknbuffer);
1228 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1231 reghack - windows 3.11 registry data format demo program.
1233 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1234 a combined hash table and tree description, and finally a text table.
1236 The header is obvious from the struct header. The taboff1 and taboff2
1237 fields are always 0x20, and their usage is unknown.
1239 The 8-byte entry table has various entry types.
1241 tabent[0] is a root index. The second word has the index of the root of
1242 the directory.
1243 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1244 the index of the key/value that has that hash. Data with the same
1245 hash value are on a circular list. The other three words in the
1246 hash entry are always zero.
1247 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1248 entry: dirent and keyent/valent. They are identified by context.
1249 tabent[freeidx] is the first free entry. The first word in a free entry
1250 is the index of the next free entry. The last has 0 as a link.
1251 The other three words in the free list are probably irrelevant.
1253 Entries in text table are preceeded by a word at offset-2. This word
1254 has the value (2*index)+1, where index is the referring keyent/valent
1255 entry in the table. I have no suggestion for the 2* and the +1.
1256 Following the word, there are N bytes of data, as per the keyent/valent
1257 entry length. The offset of the keyent/valent entry is from the start
1258 of the text table to the first data byte.
1260 This information is not available from Microsoft. The data format is
1261 deduced from the reg.dat file by me. Mistakes may
1262 have been made. I claim no rights and give no guarantees for this program.
1264 Tor Sjøwall, tor@sn.no
1267 /* reg.dat header format */
1268 struct _w31_header {
1269 char cookie[8]; /* 'SHCC3.10' */
1270 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1271 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1272 unsigned long tabcnt; /* number of entries in index table */
1273 unsigned long textoff; /* offset of text part */
1274 unsigned long textsize; /* byte size of text part */
1275 unsigned short hashsize; /* hash size */
1276 unsigned short freeidx; /* free index */
1279 /* generic format of table entries */
1280 struct _w31_tabent {
1281 unsigned short w0, w1, w2, w3;
1284 /* directory tabent: */
1285 struct _w31_dirent {
1286 unsigned short sibling_idx; /* table index of sibling dirent */
1287 unsigned short child_idx; /* table index of child dirent */
1288 unsigned short key_idx; /* table index of key keyent */
1289 unsigned short value_idx; /* table index of value valent */
1292 /* key tabent: */
1293 struct _w31_keyent {
1294 unsigned short hash_idx; /* hash chain index for string */
1295 unsigned short refcnt; /* reference count */
1296 unsigned short length; /* length of string */
1297 unsigned short string_off; /* offset of string in text table */
1300 /* value tabent: */
1301 struct _w31_valent {
1302 unsigned short hash_idx; /* hash chain index for string */
1303 unsigned short refcnt; /* reference count */
1304 unsigned short length; /* length of string */
1305 unsigned short string_off; /* offset of string in text table */
1308 /* recursive helper function to display a directory tree */
1309 void
1310 __w31_dumptree( unsigned short idx,
1311 unsigned char *txt,
1312 struct _w31_tabent *tab,
1313 struct _w31_header *head,
1314 LPKEYSTRUCT lpkey,
1315 time_t lastmodified,
1316 int level
1318 struct _w31_dirent *dir;
1319 struct _w31_keyent *key;
1320 struct _w31_valent *val;
1321 LPKEYSTRUCT xlpkey = NULL;
1322 LPWSTR name,value;
1323 static char tail[400];
1325 while (idx!=0) {
1326 dir=(struct _w31_dirent*)&tab[idx];
1328 if (dir->key_idx) {
1329 key = (struct _w31_keyent*)&tab[dir->key_idx];
1331 memcpy(tail,&txt[key->string_off],key->length);
1332 tail[key->length]='\0';
1333 /* all toplevel entries AND the entries in the
1334 * toplevel subdirectory belong to \SOFTWARE\Classes
1336 if (!level && !lstrcmp32A(tail,".classes")) {
1337 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1338 idx=dir->sibling_idx;
1339 continue;
1341 name=strdupA2W(tail);
1343 xlpkey=_find_or_add_key(lpkey,name);
1345 /* only add if leaf node or valued node */
1346 if (dir->value_idx!=0||dir->child_idx==0) {
1347 if (dir->value_idx) {
1348 val=(struct _w31_valent*)&tab[dir->value_idx];
1349 memcpy(tail,&txt[val->string_off],val->length);
1350 tail[val->length]='\0';
1351 value=strdupA2W(tail);
1352 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1355 } else {
1356 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1358 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1359 idx=dir->sibling_idx;
1363 void
1364 _w31_loadreg() {
1365 HFILE32 hf;
1366 struct _w31_header head;
1367 struct _w31_tabent *tab;
1368 unsigned char *txt;
1369 int len;
1370 OFSTRUCT ofs;
1371 BY_HANDLE_FILE_INFORMATION hfinfo;
1372 time_t lastmodified;
1373 HKEY hkey;
1374 LPKEYSTRUCT lpkey;
1376 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1377 if (hf==HFILE_ERROR32)
1378 return;
1380 /* read & dump header */
1381 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1382 ERR(reg, "reg.dat is too short.\n");
1383 _lclose32(hf);
1384 return;
1386 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1387 ERR(reg, "reg.dat has bad signature.\n");
1388 _lclose32(hf);
1389 return;
1392 len = head.tabcnt * sizeof(struct _w31_tabent);
1393 /* read and dump index table */
1394 tab = xmalloc(len);
1395 if (len!=_lread32(hf,tab,len)) {
1396 ERR(reg,"couldn't read %d bytes.\n",len);
1397 free(tab);
1398 _lclose32(hf);
1399 return;
1402 /* read text */
1403 txt = xmalloc(head.textsize);
1404 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1405 ERR(reg,"couldn't seek to textblock.\n");
1406 free(tab);
1407 free(txt);
1408 _lclose32(hf);
1409 return;
1411 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1412 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1413 free(tab);
1414 free(txt);
1415 _lclose32(hf);
1416 return;
1419 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1420 ERR(reg,"GetFileInformationByHandle failed?.\n");
1421 free(tab);
1422 free(txt);
1423 _lclose32(hf);
1424 return;
1426 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1428 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1429 return;
1430 lpkey = lookup_hkey(hkey);
1431 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1432 free(tab);
1433 free(txt);
1434 _lclose32(hf);
1435 return;
1438 void
1439 SHELL_LoadRegistry() {
1440 char *fn;
1441 struct passwd *pwd;
1442 LPKEYSTRUCT lpkey;
1443 HKEY hkey;
1446 if (key_classes_root==NULL)
1447 SHELL_Init();
1449 /* Load windows 3.1 entries */
1450 _w31_loadreg();
1451 /* Load windows 95 entries */
1452 _w95_loadreg("C:\\system.1st", key_local_machine);
1453 _w95_loadreg("system.dat", key_local_machine);
1454 _w95_loadreg("user.dat", key_users);
1456 /* the global user default is loaded under HKEY_USERS\\.Default */
1457 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1458 lpkey = lookup_hkey(hkey);
1459 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1461 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1462 _copy_registry(lpkey,key_current_user);
1463 RegCloseKey(hkey);
1465 /* the global machine defaults */
1466 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1468 /* load the user saved registries */
1470 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1472 pwd=getpwuid(getuid());
1473 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1474 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1475 strcpy(fn,pwd->pw_dir);
1476 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1477 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1478 free(fn);
1479 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1480 strcpy(fn,pwd->pw_dir);
1481 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1482 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1483 free(fn);
1484 } else
1485 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1486 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1487 DWORD junk,type,len;
1488 char data[5];
1490 len=4;
1491 if (( RegQueryValueEx32A(
1492 hkey,
1493 VAL_SAVEUPDATED,
1494 &junk,
1495 &type,
1496 data,
1497 &len
1498 )!=ERROR_SUCCESS) ||
1499 type != REG_SZ
1501 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1502 RegCloseKey(hkey);
1507 /********************* API FUNCTIONS ***************************************/
1509 * Open Keys.
1511 * All functions are stubs to RegOpenKeyEx32W where all the
1512 * magic happens.
1514 * FIXME: security,options,desiredaccess,...
1516 * Callpath:
1517 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1518 * RegOpenKey32W -> RegOpenKeyEx32W
1521 /* RegOpenKeyExW [ADVAPI32.150] */
1522 DWORD WINAPI RegOpenKeyEx32W(
1523 HKEY hkey,
1524 LPCWSTR lpszSubKey,
1525 DWORD dwReserved,
1526 REGSAM samDesired,
1527 LPHKEY retkey
1529 LPKEYSTRUCT lpNextKey,lpxkey;
1530 LPWSTR *wps;
1531 int wpc,i;
1532 TRACE(reg,"(%lx,%s,%ld,%lx,%p)\n",
1533 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1536 lpNextKey = lookup_hkey(hkey);
1537 if (!lpNextKey)
1538 return SHELL_ERROR_BADKEY;
1539 if (!lpszSubKey || !*lpszSubKey) {
1540 add_handle(++currenthandle,lpNextKey,samDesired);
1541 *retkey=currenthandle;
1542 return SHELL_ERROR_SUCCESS;
1544 split_keypath(lpszSubKey,&wps,&wpc);
1545 i = 0;
1546 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1547 lpxkey = lpNextKey;
1548 while (wps[i]) {
1549 lpxkey=lpNextKey->nextsub;
1550 while (lpxkey) {
1551 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1552 break;
1553 lpxkey=lpxkey->next;
1555 if (!lpxkey) {
1556 FREE_KEY_PATH;
1557 return SHELL_ERROR_BADKEY;
1559 i++;
1560 lpNextKey = lpxkey;
1562 add_handle(++currenthandle,lpxkey,samDesired);
1563 *retkey = currenthandle;
1564 FREE_KEY_PATH;
1565 return SHELL_ERROR_SUCCESS;
1568 /* RegOpenKeyW [ADVAPI32.151] */
1569 DWORD WINAPI RegOpenKey32W(
1570 HKEY hkey,
1571 LPCWSTR lpszSubKey,
1572 LPHKEY retkey
1574 TRACE(reg,"(%lx,%s,%p)\n",
1575 (LONG)hkey,W2C(lpszSubKey,0),retkey
1577 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1581 /* RegOpenKeyExA [ADVAPI32.149] */
1582 DWORD WINAPI RegOpenKeyEx32A(
1583 HKEY hkey,
1584 LPCSTR lpszSubKey,
1585 DWORD dwReserved,
1586 REGSAM samDesired,
1587 LPHKEY retkey
1589 LPWSTR lpszSubKeyW;
1590 DWORD ret;
1592 TRACE(reg,"(%lx,%s,%ld,%lx,%p)\n",
1593 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1595 if (lpszSubKey)
1596 lpszSubKeyW=strdupA2W(lpszSubKey);
1597 else
1598 lpszSubKeyW=NULL;
1599 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1600 if (lpszSubKeyW)
1601 free(lpszSubKeyW);
1602 return ret;
1605 /* RegOpenKeyA [ADVAPI32.148] */
1606 DWORD WINAPI RegOpenKey32A(
1607 HKEY hkey,
1608 LPCSTR lpszSubKey,
1609 LPHKEY retkey
1611 TRACE(reg,"(%lx,%s,%p)\n",
1612 (LONG)hkey,lpszSubKey,retkey
1614 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1617 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1618 DWORD WINAPI RegOpenKey16(
1619 HKEY hkey,
1620 LPCSTR lpszSubKey,
1621 LPHKEY retkey
1623 TRACE(reg,"(%lx,%s,%p)\n",
1624 (LONG)hkey,lpszSubKey,retkey
1626 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1630 * Create keys
1632 * All those functions convert their respective
1633 * arguments and call RegCreateKeyExW at the end.
1635 * FIXME: no security,no access attrib,no optionhandling yet.
1637 * Callpath:
1638 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1639 * RegCreateKey32W -> RegCreateKeyEx32W
1642 /* RegCreateKeyExW [ADVAPI32.131] */
1643 DWORD WINAPI RegCreateKeyEx32W(
1644 HKEY hkey,
1645 LPCWSTR lpszSubKey,
1646 DWORD dwReserved,
1647 LPWSTR lpszClass,
1648 DWORD fdwOptions,
1649 REGSAM samDesired,
1650 LPSECURITY_ATTRIBUTES lpSecAttribs,
1651 LPHKEY retkey,
1652 LPDWORD lpDispos
1654 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1655 LPWSTR *wps;
1656 int wpc,i;
1658 /*FIXME: handle security/access/whatever */
1659 TRACE(reg,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1660 (LONG)hkey,
1661 W2C(lpszSubKey,0),
1662 dwReserved,
1663 W2C(lpszClass,1),
1664 fdwOptions,
1665 samDesired,
1666 lpSecAttribs,
1667 retkey,
1668 lpDispos
1671 lpNextKey = lookup_hkey(hkey);
1672 if (!lpNextKey)
1673 return SHELL_ERROR_BADKEY;
1674 if (!lpszSubKey || !*lpszSubKey) {
1675 add_handle(++currenthandle,lpNextKey,samDesired);
1676 *retkey=currenthandle;
1677 lpNextKey->flags|=REG_OPTION_TAINTED;
1678 return SHELL_ERROR_SUCCESS;
1680 split_keypath(lpszSubKey,&wps,&wpc);
1681 i = 0;
1682 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1683 lpxkey = lpNextKey;
1684 while (wps[i]) {
1685 lpxkey=lpNextKey->nextsub;
1686 while (lpxkey) {
1687 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1688 break;
1689 lpxkey=lpxkey->next;
1691 if (!lpxkey)
1692 break;
1693 i++;
1694 lpNextKey = lpxkey;
1696 if (lpxkey) {
1697 add_handle(++currenthandle,lpxkey,samDesired);
1698 lpxkey->flags |= REG_OPTION_TAINTED;
1699 *retkey = currenthandle;
1700 if (lpDispos)
1701 *lpDispos = REG_OPENED_EXISTING_KEY;
1702 FREE_KEY_PATH;
1703 return SHELL_ERROR_SUCCESS;
1705 /* good. now the hard part */
1706 while (wps[i]) {
1707 lplpPrevKey = &(lpNextKey->nextsub);
1708 lpxkey = *lplpPrevKey;
1709 while (lpxkey) {
1710 lplpPrevKey = &(lpxkey->next);
1711 lpxkey = *lplpPrevKey;
1713 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1714 if (!*lplpPrevKey) {
1715 FREE_KEY_PATH;
1716 return SHELL_ERROR_OUTOFMEMORY;
1718 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1719 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1720 (*lplpPrevKey)->next = NULL;
1721 (*lplpPrevKey)->nextsub = NULL;
1722 (*lplpPrevKey)->values = NULL;
1723 (*lplpPrevKey)->nrofvalues = 0;
1724 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1725 if (lpszClass)
1726 (*lplpPrevKey)->class = strdupW(lpszClass);
1727 else
1728 (*lplpPrevKey)->class = NULL;
1729 lpNextKey = *lplpPrevKey;
1730 i++;
1732 add_handle(++currenthandle,lpNextKey,samDesired);
1734 /*FIXME: flag handling correct? */
1735 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1736 if (lpszClass)
1737 lpNextKey->class = strdupW(lpszClass);
1738 else
1739 lpNextKey->class = NULL;
1740 *retkey = currenthandle;
1741 if (lpDispos)
1742 *lpDispos = REG_CREATED_NEW_KEY;
1743 FREE_KEY_PATH;
1744 return SHELL_ERROR_SUCCESS;
1747 /* RegCreateKeyW [ADVAPI32.132] */
1748 DWORD WINAPI RegCreateKey32W(
1749 HKEY hkey,
1750 LPCWSTR lpszSubKey,
1751 LPHKEY retkey
1753 DWORD junk,ret;
1755 TRACE(reg,"(%lx,%s,%p)\n",
1756 (LONG)hkey,W2C(lpszSubKey,0),retkey
1758 ret=RegCreateKeyEx32W(
1759 hkey, /* key handle */
1760 lpszSubKey, /* subkey name */
1761 0, /* reserved = 0 */
1762 NULL, /* lpszClass? FIXME: ? */
1763 REG_OPTION_NON_VOLATILE, /* options */
1764 KEY_ALL_ACCESS, /* desired access attribs */
1765 NULL, /* lpsecurity attributes */
1766 retkey, /* lpretkey */
1767 &junk /* disposition value */
1769 return ret;
1772 /* RegCreateKeyExA [ADVAPI32.130] */
1773 DWORD WINAPI RegCreateKeyEx32A(
1774 HKEY hkey,
1775 LPCSTR lpszSubKey,
1776 DWORD dwReserved,
1777 LPSTR lpszClass,
1778 DWORD fdwOptions,
1779 REGSAM samDesired,
1780 LPSECURITY_ATTRIBUTES lpSecAttribs,
1781 LPHKEY retkey,
1782 LPDWORD lpDispos
1784 LPWSTR lpszSubKeyW,lpszClassW;
1785 DWORD ret;
1787 TRACE(reg,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1788 (LONG)hkey,
1789 lpszSubKey,
1790 dwReserved,
1791 lpszClass,
1792 fdwOptions,
1793 samDesired,
1794 lpSecAttribs,
1795 retkey,
1796 lpDispos
1798 if (lpszSubKey)
1799 lpszSubKeyW=strdupA2W(lpszSubKey);
1800 else
1801 lpszSubKeyW=NULL;
1802 if (lpszClass)
1803 lpszClassW=strdupA2W(lpszClass);
1804 else
1805 lpszClassW=NULL;
1806 ret=RegCreateKeyEx32W(
1807 hkey,
1808 lpszSubKeyW,
1809 dwReserved,
1810 lpszClassW,
1811 fdwOptions,
1812 samDesired,
1813 lpSecAttribs,
1814 retkey,
1815 lpDispos
1817 if (lpszSubKeyW)
1818 free(lpszSubKeyW);
1819 if (lpszClassW)
1820 free(lpszClassW);
1821 return ret;
1824 /* RegCreateKeyA [ADVAPI32.129] */
1825 DWORD WINAPI RegCreateKey32A(
1826 HKEY hkey,
1827 LPCSTR lpszSubKey,
1828 LPHKEY retkey
1830 DWORD junk;
1832 TRACE(reg,"(%lx,%s,%p)\n",
1833 (LONG)hkey,lpszSubKey,retkey
1835 return RegCreateKeyEx32A(
1836 hkey, /* key handle */
1837 lpszSubKey, /* subkey name */
1838 0, /* reserved = 0 */
1839 NULL, /* lpszClass? FIXME: ? */
1840 REG_OPTION_NON_VOLATILE,/* options */
1841 KEY_ALL_ACCESS, /* desired access attribs */
1842 NULL, /* lpsecurity attributes */
1843 retkey, /* lpretkey */
1844 &junk /* disposition value */
1848 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1849 DWORD WINAPI RegCreateKey16(
1850 HKEY hkey,
1851 LPCSTR lpszSubKey,
1852 LPHKEY retkey
1854 TRACE(reg,"(%lx,%s,%p)\n",
1855 (LONG)hkey,lpszSubKey,retkey
1857 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1861 * Query Value Functions
1862 * Win32 differs between keynames and valuenames.
1863 * multiple values may belong to one key, the special value
1864 * with name NULL is the default value used by the win31
1865 * compat functions.
1867 * Callpath:
1868 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1869 * RegQueryValue32W -> RegQueryValueEx32W
1872 /* RegQueryValueExW [ADVAPI32.158] */
1873 DWORD WINAPI RegQueryValueEx32W(
1874 HKEY hkey,
1875 LPWSTR lpszValueName,
1876 LPDWORD lpdwReserved,
1877 LPDWORD lpdwType,
1878 LPBYTE lpbData,
1879 LPDWORD lpcbData
1881 LPKEYSTRUCT lpkey;
1882 int i;
1884 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
1885 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1886 lpcbData?*lpcbData:0);
1888 lpkey = lookup_hkey(hkey);
1889 if (!lpkey)
1890 return SHELL_ERROR_BADKEY;
1891 if (lpszValueName && !*lpszValueName)
1892 lpszValueName = NULL;
1893 if (lpszValueName==NULL) {
1894 for (i=0;i<lpkey->nrofvalues;i++)
1895 if (lpkey->values[i].name==NULL)
1896 break;
1897 } else {
1898 for (i=0;i<lpkey->nrofvalues;i++)
1899 if ( lpkey->values[i].name &&
1900 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
1902 break;
1904 if (i==lpkey->nrofvalues) {
1905 if (lpszValueName==NULL) {
1906 if (lpbData) {
1907 *(WCHAR*)lpbData = 0;
1908 *lpcbData = 2;
1910 if (lpdwType)
1911 *lpdwType = REG_SZ;
1912 return SHELL_ERROR_SUCCESS;
1914 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1916 if (lpdwType)
1917 *lpdwType = lpkey->values[i].type;
1918 if (lpbData==NULL) {
1919 if (lpcbData==NULL)
1920 return SHELL_ERROR_SUCCESS;
1921 *lpcbData = lpkey->values[i].len;
1922 return SHELL_ERROR_SUCCESS;
1924 if (*lpcbData<lpkey->values[i].len) {
1925 *(WCHAR*)lpbData= 0;
1926 *lpcbData = lpkey->values[i].len;
1927 return ERROR_MORE_DATA;
1929 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1930 *lpcbData = lpkey->values[i].len;
1931 return SHELL_ERROR_SUCCESS;
1934 /* RegQueryValueW [ADVAPI32.159] */
1935 DWORD WINAPI RegQueryValue32W(
1936 HKEY hkey,
1937 LPWSTR lpszSubKey,
1938 LPWSTR lpszData,
1939 LPDWORD lpcbData
1941 HKEY xhkey;
1942 DWORD ret,lpdwType;
1944 TRACE(reg,"(%x,%s,%p,%ld)\n",
1945 hkey,W2C(lpszSubKey,0),lpszData,
1946 lpcbData?*lpcbData:0);
1948 /* only open subkey, if we really do descend */
1949 if (lpszSubKey && *lpszSubKey) {
1950 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1951 if (ret!=ERROR_SUCCESS)
1952 return ret;
1953 } else
1954 xhkey = hkey;
1956 lpdwType = REG_SZ;
1957 ret = RegQueryValueEx32W(
1958 xhkey,
1959 NULL, /* varname NULL -> compat */
1960 NULL, /* lpdwReserved, must be NULL */
1961 &lpdwType,
1962 (LPBYTE)lpszData,
1963 lpcbData
1965 if (xhkey!=hkey)
1966 RegCloseKey(xhkey);
1967 return ret;
1970 /* RegQueryValueExA [ADVAPI32.157] */
1971 DWORD WINAPI RegQueryValueEx32A(
1972 HKEY hkey,
1973 LPSTR lpszValueName,
1974 LPDWORD lpdwReserved,
1975 LPDWORD lpdwType,
1976 LPBYTE lpbData,
1977 LPDWORD lpcbData
1979 LPWSTR lpszValueNameW;
1980 LPBYTE buf;
1981 DWORD ret,myxlen;
1982 DWORD *mylen;
1983 DWORD type;
1985 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
1986 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1987 lpcbData?*lpcbData:0);
1989 if (lpszValueName)
1990 lpszValueNameW=strdupA2W(lpszValueName);
1991 else
1992 lpszValueNameW=NULL;
1994 if (lpdwType)
1995 type=*lpdwType;
1997 if (lpbData) {
1998 myxlen = 0;
1999 mylen = &myxlen;
2000 buf = xmalloc(4);
2001 ret=RegQueryValueEx32W(
2002 hkey,
2003 lpszValueNameW,
2004 lpdwReserved,
2005 &type,
2006 buf,
2007 mylen
2009 free(buf);
2010 if (ret==ERROR_MORE_DATA) {
2011 buf = (LPBYTE)xmalloc(*mylen);
2012 } else {
2013 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2014 myxlen = 2*(*lpcbData);
2016 } else {
2017 buf=NULL;
2018 if (lpcbData) {
2019 myxlen = *lpcbData*2;
2020 mylen = &myxlen;
2021 } else
2022 mylen = NULL;
2024 ret=RegQueryValueEx32W(
2025 hkey,
2026 lpszValueNameW,
2027 lpdwReserved,
2028 &type,
2029 buf,
2030 mylen
2032 if (lpdwType)
2033 *lpdwType=type;
2034 if (ret==ERROR_SUCCESS) {
2035 if (buf) {
2036 if (UNICONVMASK & (1<<(type))) {
2037 /* convert UNICODE to ASCII */
2038 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2039 *lpcbData = myxlen/2;
2040 } else {
2041 if (myxlen>*lpcbData)
2042 ret = ERROR_MORE_DATA;
2043 else
2044 memcpy(lpbData,buf,myxlen);
2046 *lpcbData = myxlen;
2048 } else {
2049 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2050 *lpcbData = myxlen/2;
2052 } else {
2053 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2054 *lpcbData = myxlen/2;
2056 if (buf)
2057 free(buf);
2058 return ret;
2061 /* RegQueryValueEx [KERNEL.225] */
2062 DWORD WINAPI RegQueryValueEx16(
2063 HKEY hkey,
2064 LPSTR lpszValueName,
2065 LPDWORD lpdwReserved,
2066 LPDWORD lpdwType,
2067 LPBYTE lpbData,
2068 LPDWORD lpcbData
2070 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
2071 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2072 lpcbData?*lpcbData:0);
2074 return RegQueryValueEx32A(
2075 hkey,
2076 lpszValueName,
2077 lpdwReserved,
2078 lpdwType,
2079 lpbData,
2080 lpcbData
2084 /* RegQueryValueA [ADVAPI32.156] */
2085 DWORD WINAPI RegQueryValue32A(
2086 HKEY hkey,
2087 LPSTR lpszSubKey,
2088 LPSTR lpszData,
2089 LPDWORD lpcbData
2091 HKEY xhkey;
2092 DWORD ret,lpdwType;
2094 TRACE(reg,"(%x,%s,%p,%ld)\n",
2095 hkey,lpszSubKey,lpszData,
2096 lpcbData?*lpcbData:0);
2098 /* only open subkey, if we really do descend */
2099 if (lpszSubKey && *lpszSubKey) {
2100 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2101 if (ret!=ERROR_SUCCESS)
2102 return ret;
2103 } else
2104 xhkey = hkey;
2106 lpdwType = REG_SZ;
2107 ret = RegQueryValueEx32A(
2108 xhkey,
2109 NULL, /* lpszValueName NULL -> compat */
2110 NULL, /* lpdwReserved, must be NULL */
2111 &lpdwType,
2112 (LPBYTE)lpszData,
2113 lpcbData
2115 if (xhkey!=hkey)
2116 RegCloseKey(xhkey);
2117 return ret;
2120 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2121 DWORD WINAPI RegQueryValue16(
2122 HKEY hkey,
2123 LPSTR lpszSubKey,
2124 LPSTR lpszData,
2125 LPDWORD lpcbData
2127 TRACE(reg,"(%x,%s,%p,%ld)\n",
2128 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0);
2130 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2131 * anyway, so we just mask out the high 16 bit.
2132 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2134 if (lpcbData)
2135 *lpcbData &= 0xFFFF;
2136 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2140 * Setting values of Registry keys
2142 * Callpath:
2143 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2144 * RegSetValue32W -> RegSetValueEx32W
2147 /* RegSetValueExW [ADVAPI32.170] */
2148 DWORD WINAPI RegSetValueEx32W(
2149 HKEY hkey,
2150 LPWSTR lpszValueName,
2151 DWORD dwReserved,
2152 DWORD dwType,
2153 LPBYTE lpbData,
2154 DWORD cbData
2156 LPKEYSTRUCT lpkey;
2157 int i;
2159 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2160 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2162 /* we no longer care about the lpbData type here... */
2163 lpkey = lookup_hkey(hkey);
2164 if (!lpkey)
2165 return SHELL_ERROR_BADKEY;
2167 lpkey->flags |= REG_OPTION_TAINTED;
2169 if (lpszValueName==NULL) {
2170 for (i=0;i<lpkey->nrofvalues;i++)
2171 if (lpkey->values[i].name==NULL)
2172 break;
2173 } else {
2174 for (i=0;i<lpkey->nrofvalues;i++)
2175 if ( lpkey->values[i].name &&
2176 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2178 break;
2180 if (i==lpkey->nrofvalues) {
2181 lpkey->values = (LPKEYVALUE)xrealloc(
2182 lpkey->values,
2183 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2185 lpkey->nrofvalues++;
2186 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2188 if (lpkey->values[i].name==NULL)
2189 if (lpszValueName)
2190 lpkey->values[i].name = strdupW(lpszValueName);
2191 else
2192 lpkey->values[i].name = NULL;
2193 lpkey->values[i].len = cbData;
2194 lpkey->values[i].type = dwType;
2195 if (lpkey->values[i].data !=NULL)
2196 free(lpkey->values[i].data);
2197 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2198 lpkey->values[i].lastmodified = time(NULL);
2199 memcpy(lpkey->values[i].data,lpbData,cbData);
2200 return SHELL_ERROR_SUCCESS;
2203 /* RegSetValueExA [ADVAPI32.169] */
2204 DWORD WINAPI RegSetValueEx32A(
2205 HKEY hkey,
2206 LPSTR lpszValueName,
2207 DWORD dwReserved,
2208 DWORD dwType,
2209 LPBYTE lpbData,
2210 DWORD cbData
2212 LPBYTE buf;
2213 LPWSTR lpszValueNameW;
2214 DWORD ret;
2216 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2217 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2219 if ((1<<dwType) & UNICONVMASK) {
2220 buf=(LPBYTE)strdupA2W(lpbData);
2221 cbData=2*strlen(lpbData)+2;
2222 } else
2223 buf=lpbData;
2224 if (lpszValueName)
2225 lpszValueNameW = strdupA2W(lpszValueName);
2226 else
2227 lpszValueNameW = NULL;
2228 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2229 if (lpszValueNameW)
2230 free(lpszValueNameW);
2231 if (buf!=lpbData)
2232 free(buf);
2233 return ret;
2236 /* RegSetValueEx [KERNEL.226] */
2237 DWORD WINAPI RegSetValueEx16(
2238 HKEY hkey,
2239 LPSTR lpszValueName,
2240 DWORD dwReserved,
2241 DWORD dwType,
2242 LPBYTE lpbData,
2243 DWORD cbData
2245 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2246 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2248 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2251 /* RegSetValueW [ADVAPI32.171] */
2252 DWORD WINAPI RegSetValue32W(
2253 HKEY hkey,
2254 LPCWSTR lpszSubKey,
2255 DWORD dwType,
2256 LPCWSTR lpszData,
2257 DWORD cbData
2259 HKEY xhkey;
2260 DWORD ret;
2262 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2263 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2265 if (lpszSubKey && *lpszSubKey) {
2266 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2267 if (ret!=ERROR_SUCCESS)
2268 return ret;
2269 } else
2270 xhkey=hkey;
2271 if (dwType!=REG_SZ) {
2272 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2273 dwType=REG_SZ;
2275 if (cbData!=2*lstrlen32W(lpszData)+2) {
2276 TRACE(reg,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2277 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2279 cbData=2*lstrlen32W(lpszData)+2;
2281 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2282 if (hkey!=xhkey)
2283 RegCloseKey(xhkey);
2284 return ret;
2287 /* RegSetValueA [ADVAPI32.168] */
2288 DWORD WINAPI RegSetValue32A(
2289 HKEY hkey,
2290 LPCSTR lpszSubKey,
2291 DWORD dwType,
2292 LPCSTR lpszData,
2293 DWORD cbData
2295 DWORD ret;
2296 HKEY xhkey;
2298 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2299 hkey,lpszSubKey,dwType,lpszData,cbData
2301 if (lpszSubKey && *lpszSubKey) {
2302 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2303 if (ret!=ERROR_SUCCESS)
2304 return ret;
2305 } else
2306 xhkey=hkey;
2308 if (dwType!=REG_SZ) {
2309 TRACE(reg,"RegSetValueA called with dwType=%ld!\n",dwType);
2310 dwType=REG_SZ;
2312 if (cbData!=strlen(lpszData)+1)
2313 cbData=strlen(lpszData)+1;
2314 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2315 if (xhkey!=hkey)
2316 RegCloseKey(xhkey);
2317 return ret;
2320 /* RegSetValue [KERNEL.221] [SHELL.5] */
2321 DWORD WINAPI RegSetValue16(
2322 HKEY hkey,
2323 LPCSTR lpszSubKey,
2324 DWORD dwType,
2325 LPCSTR lpszData,
2326 DWORD cbData
2328 DWORD ret;
2329 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2330 hkey,lpszSubKey,dwType,lpszData,cbData
2332 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2333 return ret;
2337 * Key Enumeration
2339 * Callpath:
2340 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2341 * RegEnumKey32W -> RegEnumKeyEx32W
2344 /* RegEnumKeyExW [ADVAPI32.139] */
2345 DWORD WINAPI RegEnumKeyEx32W(
2346 HKEY hkey,
2347 DWORD iSubkey,
2348 LPWSTR lpszName,
2349 LPDWORD lpcchName,
2350 LPDWORD lpdwReserved,
2351 LPWSTR lpszClass,
2352 LPDWORD lpcchClass,
2353 FILETIME *ft
2355 LPKEYSTRUCT lpkey,lpxkey;
2357 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2358 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2360 lpkey=lookup_hkey(hkey);
2361 if (!lpkey)
2362 return SHELL_ERROR_BADKEY;
2363 if (!lpkey->nextsub)
2364 return ERROR_NO_MORE_ITEMS;
2365 lpxkey=lpkey->nextsub;
2366 while (iSubkey && lpxkey) {
2367 iSubkey--;
2368 lpxkey=lpxkey->next;
2370 if (iSubkey || !lpxkey)
2371 return ERROR_NO_MORE_ITEMS;
2372 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2373 return ERROR_MORE_DATA;
2374 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2375 if (lpszClass) {
2376 /* what should we write into it? */
2377 *lpszClass = 0;
2378 *lpcchClass = 2;
2380 return ERROR_SUCCESS;
2384 /* RegEnumKeyW [ADVAPI32.140] */
2385 DWORD WINAPI RegEnumKey32W(
2386 HKEY hkey,
2387 DWORD iSubkey,
2388 LPWSTR lpszName,
2389 DWORD lpcchName
2391 FILETIME ft;
2393 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2394 hkey,iSubkey,lpszName,lpcchName
2396 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2398 /* RegEnumKeyExA [ADVAPI32.138] */
2399 DWORD WINAPI RegEnumKeyEx32A(
2400 HKEY hkey,
2401 DWORD iSubkey,
2402 LPSTR lpszName,
2403 LPDWORD lpcchName,
2404 LPDWORD lpdwReserved,
2405 LPSTR lpszClass,
2406 LPDWORD lpcchClass,
2407 FILETIME *ft
2409 DWORD ret,lpcchNameW,lpcchClassW;
2410 LPWSTR lpszNameW,lpszClassW;
2413 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2414 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2416 if (lpszName) {
2417 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2418 lpcchNameW = *lpcchName*2;
2419 } else {
2420 lpszNameW = NULL;
2421 lpcchNameW = 0;
2423 if (lpszClass) {
2424 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2425 lpcchClassW = *lpcchClass*2;
2426 } else {
2427 lpszClassW =0;
2428 lpcchClassW=0;
2430 ret=RegEnumKeyEx32W(
2431 hkey,
2432 iSubkey,
2433 lpszNameW,
2434 &lpcchNameW,
2435 lpdwReserved,
2436 lpszClassW,
2437 &lpcchClassW,
2440 if (ret==ERROR_SUCCESS) {
2441 lstrcpyWtoA(lpszName,lpszNameW);
2442 *lpcchName=strlen(lpszName);
2443 if (lpszClassW) {
2444 lstrcpyWtoA(lpszClass,lpszClassW);
2445 *lpcchClass=strlen(lpszClass);
2448 if (lpszNameW)
2449 free(lpszNameW);
2450 if (lpszClassW)
2451 free(lpszClassW);
2452 return ret;
2455 /* RegEnumKeyA [ADVAPI32.137] */
2456 DWORD WINAPI RegEnumKey32A(
2457 HKEY hkey,
2458 DWORD iSubkey,
2459 LPSTR lpszName,
2460 DWORD lpcchName
2462 FILETIME ft;
2464 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2465 hkey,iSubkey,lpszName,lpcchName
2467 return RegEnumKeyEx32A(
2468 hkey,
2469 iSubkey,
2470 lpszName,
2471 &lpcchName,
2472 NULL,
2473 NULL,
2474 NULL,
2479 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2480 DWORD WINAPI RegEnumKey16(
2481 HKEY hkey,
2482 DWORD iSubkey,
2483 LPSTR lpszName,
2484 DWORD lpcchName
2486 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2487 hkey,iSubkey,lpszName,lpcchName
2489 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2493 * Enumerate Registry Values
2495 * Callpath:
2496 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2499 /* RegEnumValueW [ADVAPI32.142] */
2500 DWORD WINAPI RegEnumValue32W(
2501 HKEY hkey,
2502 DWORD iValue,
2503 LPWSTR lpszValue,
2504 LPDWORD lpcchValue,
2505 LPDWORD lpdReserved,
2506 LPDWORD lpdwType,
2507 LPBYTE lpbData,
2508 LPDWORD lpcbData
2510 LPKEYSTRUCT lpkey;
2511 LPKEYVALUE val;
2513 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2514 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2516 lpkey = lookup_hkey(hkey);
2517 if (!lpkey)
2518 return SHELL_ERROR_BADKEY;
2519 if (lpkey->nrofvalues<=iValue)
2520 return ERROR_NO_MORE_ITEMS;
2521 val = lpkey->values+iValue;
2523 if (val->name) {
2524 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2525 *lpcchValue = lstrlen32W(val->name)*2+2;
2526 return ERROR_MORE_DATA;
2528 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2529 *lpcchValue=lstrlen32W(val->name)*2+2;
2530 } else {
2531 *lpszValue = 0;
2532 *lpcchValue = 0;
2534 if (lpdwType)
2535 *lpdwType=val->type;
2536 if (lpbData) {
2537 if (val->len>*lpcbData)
2538 return ERROR_MORE_DATA;
2539 memcpy(lpbData,val->data,val->len);
2540 *lpcbData = val->len;
2542 return SHELL_ERROR_SUCCESS;
2545 /* RegEnumValueA [ADVAPI32.141] */
2546 DWORD WINAPI RegEnumValue32A(
2547 HKEY hkey,
2548 DWORD iValue,
2549 LPSTR lpszValue,
2550 LPDWORD lpcchValue,
2551 LPDWORD lpdReserved,
2552 LPDWORD lpdwType,
2553 LPBYTE lpbData,
2554 LPDWORD lpcbData
2556 LPWSTR lpszValueW;
2557 LPBYTE lpbDataW;
2558 DWORD ret,lpcbDataW;
2560 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2561 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2564 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2565 if (lpbData) {
2566 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2567 lpcbDataW = *lpcbData*2;
2568 } else
2569 lpbDataW = NULL;
2570 ret=RegEnumValue32W(
2571 hkey,
2572 iValue,
2573 lpszValueW,
2574 lpcchValue,
2575 lpdReserved,
2576 lpdwType,
2577 lpbDataW,
2578 &lpcbDataW
2581 if (ret==ERROR_SUCCESS) {
2582 lstrcpyWtoA(lpszValue,lpszValueW);
2583 if (lpbData) {
2584 if ((1<<*lpdwType) & UNICONVMASK) {
2585 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2586 } else {
2587 if (lpcbDataW > *lpcbData)
2588 ret = ERROR_MORE_DATA;
2589 else
2590 memcpy(lpbData,lpbDataW,lpcbDataW);
2592 *lpcbData = lpcbDataW;
2595 if (lpbDataW)
2596 free(lpbDataW);
2597 if (lpszValueW)
2598 free(lpszValueW);
2599 return ret;
2602 /* RegEnumValue [KERNEL.223] */
2603 DWORD WINAPI RegEnumValue16(
2604 HKEY hkey,
2605 DWORD iValue,
2606 LPSTR lpszValue,
2607 LPDWORD lpcchValue,
2608 LPDWORD lpdReserved,
2609 LPDWORD lpdwType,
2610 LPBYTE lpbData,
2611 LPDWORD lpcbData
2613 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2614 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2616 return RegEnumValue32A(
2617 hkey,
2618 iValue,
2619 lpszValue,
2620 lpcchValue,
2621 lpdReserved,
2622 lpdwType,
2623 lpbData,
2624 lpcbData
2629 * Close registry key
2631 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2632 DWORD WINAPI RegCloseKey(HKEY hkey) {
2633 TRACE(reg,"(%x)\n",hkey);
2634 remove_handle(hkey);
2635 return ERROR_SUCCESS;
2638 * Delete registry key
2640 * Callpath:
2641 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2643 /* RegDeleteKeyW [ADVAPI32.134] */
2644 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2645 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2646 LPWSTR *wps;
2647 int wpc,i;
2649 TRACE(reg,"(%x,%s)\n",
2650 hkey,W2C(lpszSubKey,0)
2652 lpNextKey = lookup_hkey(hkey);
2653 if (!lpNextKey) {
2654 TRACE(reg, " Badkey[1].\n");
2655 return SHELL_ERROR_BADKEY;
2657 /* we need to know the previous key in the hier. */
2658 if (!lpszSubKey || !*lpszSubKey) {
2659 TRACE(reg, " Badkey[2].\n");
2660 return SHELL_ERROR_BADKEY;
2662 split_keypath(lpszSubKey,&wps,&wpc);
2663 i = 0;
2664 lpxkey = lpNextKey;
2665 while (i<wpc-1) {
2666 lpxkey=lpNextKey->nextsub;
2667 while (lpxkey) {
2668 TRACE(reg, " Scanning [%s]\n",
2669 W2C (lpxkey->keyname, 0));
2670 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2671 break;
2672 lpxkey=lpxkey->next;
2674 if (!lpxkey) {
2675 FREE_KEY_PATH;
2676 TRACE(reg, " Not found.\n");
2677 /* not found is success */
2678 return SHELL_ERROR_SUCCESS;
2680 i++;
2681 lpNextKey = lpxkey;
2683 lpxkey = lpNextKey->nextsub;
2684 lplpPrevKey = &(lpNextKey->nextsub);
2685 while (lpxkey) {
2686 TRACE(reg, " Scanning [%s]\n",
2687 W2C (lpxkey->keyname, 0));
2688 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2689 break;
2690 lplpPrevKey = &(lpxkey->next);
2691 lpxkey = lpxkey->next;
2693 if (!lpxkey) {
2694 FREE_KEY_PATH;
2695 WARN(reg , " Not found.\n");
2696 return SHELL_ERROR_BADKEY;
2698 if (lpxkey->nextsub) {
2699 FREE_KEY_PATH;
2700 WARN(reg , " Not empty.\n");
2701 return SHELL_ERROR_CANTWRITE;
2703 *lplpPrevKey = lpxkey->next;
2704 free(lpxkey->keyname);
2705 if (lpxkey->class)
2706 free(lpxkey->class);
2707 if (lpxkey->values)
2708 free(lpxkey->values);
2709 free(lpxkey);
2710 FREE_KEY_PATH;
2711 TRACE(reg, " Done.\n");
2712 return SHELL_ERROR_SUCCESS;
2715 /* RegDeleteKeyA [ADVAPI32.133] */
2716 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2717 LPWSTR lpszSubKeyW;
2718 DWORD ret;
2720 TRACE(reg,"(%x,%s)\n",
2721 hkey,lpszSubKey
2723 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2724 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2725 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2726 return ret;
2729 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2730 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2731 TRACE(reg,"(%x,%s)\n",
2732 hkey,lpszSubKey
2734 return RegDeleteKey32A(hkey,lpszSubKey);
2738 * Delete registry value
2740 * Callpath:
2741 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2743 /* RegDeleteValueW [ADVAPI32.136] */
2744 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2746 DWORD i;
2747 LPKEYSTRUCT lpkey;
2748 LPKEYVALUE val;
2750 TRACE(reg,"(%x,%s)\n",
2751 hkey,W2C(lpszValue,0)
2753 lpkey=lookup_hkey(hkey);
2754 if (!lpkey)
2755 return SHELL_ERROR_BADKEY;
2756 if (lpszValue) {
2757 for (i=0;i<lpkey->nrofvalues;i++)
2758 if ( lpkey->values[i].name &&
2759 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2761 break;
2762 } else {
2763 for (i=0;i<lpkey->nrofvalues;i++)
2764 if (lpkey->values[i].name==NULL)
2765 break;
2767 if (i==lpkey->nrofvalues)
2768 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2769 val = lpkey->values+i;
2770 if (val->name) free(val->name);
2771 if (val->data) free(val->data);
2772 memcpy(
2773 lpkey->values+i,
2774 lpkey->values+i+1,
2775 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2777 lpkey->values = (LPKEYVALUE)xrealloc(
2778 lpkey->values,
2779 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2781 lpkey->nrofvalues--;
2782 return SHELL_ERROR_SUCCESS;
2785 /* RegDeleteValueA [ADVAPI32.135] */
2786 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2788 LPWSTR lpszValueW;
2789 DWORD ret;
2791 TRACE(reg, "(%x,%s)\n", hkey,lpszValue );
2792 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2793 ret=RegDeleteValue32W(hkey,lpszValueW);
2794 HeapFree(GetProcessHeap(),0,lpszValueW);
2795 return ret;
2798 /* RegDeleteValue [KERNEL.222] */
2799 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2801 TRACE(reg,"(%x,%s)\n", hkey,lpszValue );
2802 return RegDeleteValue32A(hkey,lpszValue);
2805 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2806 DWORD WINAPI RegFlushKey(HKEY hkey)
2808 FIXME(reg, "(%x), STUB.\n", hkey);
2809 return SHELL_ERROR_SUCCESS;
2812 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2814 /* RegQueryInfoKeyW [ADVAPI32.153] */
2815 DWORD WINAPI RegQueryInfoKey32W(
2816 HKEY hkey,
2817 LPWSTR lpszClass,
2818 LPDWORD lpcchClass,
2819 LPDWORD lpdwReserved,
2820 LPDWORD lpcSubKeys,
2821 LPDWORD lpcchMaxSubkey,
2822 LPDWORD lpcchMaxClass,
2823 LPDWORD lpcValues,
2824 LPDWORD lpcchMaxValueName,
2825 LPDWORD lpccbMaxValueData,
2826 LPDWORD lpcbSecurityDescriptor,
2827 FILETIME *ft
2829 LPKEYSTRUCT lpkey,lpxkey;
2830 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2831 int i;
2833 TRACE(reg,"(%x,......)\n",hkey);
2834 lpkey=lookup_hkey(hkey);
2835 if (!lpkey)
2836 return SHELL_ERROR_BADKEY;
2837 if (lpszClass) {
2838 if (lpkey->class) {
2839 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2840 *lpcchClass=lstrlen32W(lpkey->class)*2;
2841 return ERROR_MORE_DATA;
2843 *lpcchClass=lstrlen32W(lpkey->class)*2;
2844 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2845 } else {
2846 *lpszClass = 0;
2847 *lpcchClass = 0;
2849 } else {
2850 if (lpcchClass)
2851 *lpcchClass = lstrlen32W(lpkey->class)*2;
2853 lpxkey=lpkey->nextsub;
2854 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2855 while (lpxkey) {
2856 nrofkeys++;
2857 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2858 maxsubkey=lstrlen32W(lpxkey->keyname);
2859 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2860 maxclass=lstrlen32W(lpxkey->class);
2861 if (lpxkey->nrofvalues>maxvalues)
2862 maxvalues=lpxkey->nrofvalues;
2863 for (i=0;i<lpxkey->nrofvalues;i++) {
2864 LPKEYVALUE val=lpxkey->values+i;
2866 if (val->name && lstrlen32W(val->name)>maxvname)
2867 maxvname=lstrlen32W(val->name);
2868 if (val->len>maxvdata)
2869 maxvdata=val->len;
2871 lpxkey=lpxkey->next;
2873 if (!maxclass) maxclass = 1;
2874 if (!maxvname) maxvname = 1;
2875 if (lpcSubKeys)
2876 *lpcSubKeys = nrofkeys;
2877 if (lpcchMaxSubkey)
2878 *lpcchMaxSubkey = maxsubkey*2;
2879 if (lpcchMaxClass)
2880 *lpcchMaxClass = maxclass*2;
2881 if (lpcValues)
2882 *lpcValues = maxvalues;
2883 if (lpcchMaxValueName)
2884 *lpcchMaxValueName= maxvname;
2885 if (lpccbMaxValueData)
2886 *lpccbMaxValueData= maxvdata;
2887 return SHELL_ERROR_SUCCESS;
2890 /* RegQueryInfoKeyA [ADVAPI32.152] */
2891 DWORD WINAPI RegQueryInfoKey32A(
2892 HKEY hkey,
2893 LPSTR lpszClass,
2894 LPDWORD lpcchClass,
2895 LPDWORD lpdwReserved,
2896 LPDWORD lpcSubKeys,
2897 LPDWORD lpcchMaxSubkey,
2898 LPDWORD lpcchMaxClass,
2899 LPDWORD lpcValues,
2900 LPDWORD lpcchMaxValueName,
2901 LPDWORD lpccbMaxValueData,
2902 LPDWORD lpcbSecurityDescriptor,
2903 FILETIME *ft
2905 LPWSTR lpszClassW;
2906 DWORD ret;
2908 TRACE(reg,"(%x,......)\n",hkey);
2909 if (lpszClass) {
2910 *lpcchClass*= 2;
2911 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2913 } else
2914 lpszClassW = NULL;
2915 ret=RegQueryInfoKey32W(
2916 hkey,
2917 lpszClassW,
2918 lpcchClass,
2919 lpdwReserved,
2920 lpcSubKeys,
2921 lpcchMaxSubkey,
2922 lpcchMaxClass,
2923 lpcValues,
2924 lpcchMaxValueName,
2925 lpccbMaxValueData,
2926 lpcbSecurityDescriptor,
2929 if (ret==ERROR_SUCCESS && lpszClass)
2930 lstrcpyWtoA(lpszClass,lpszClassW);
2931 if (lpcchClass)
2932 *lpcchClass/=2;
2933 if (lpcchMaxSubkey)
2934 *lpcchMaxSubkey/=2;
2935 if (lpcchMaxClass)
2936 *lpcchMaxClass/=2;
2937 if (lpcchMaxValueName)
2938 *lpcchMaxValueName/=2;
2939 if (lpszClassW)
2940 free(lpszClassW);
2941 return ret;
2943 /* RegConnectRegistryA [ADVAPI32.127] */
2944 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
2946 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
2947 machine,hkey,reskey
2949 return ERROR_FILE_NOT_FOUND; /* FIXME */