Release 980503
[wine.git] / misc / registry.c
blob537c4edce98c0747c48f5fa428f3fd53f773d993
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 return get_handle(hkey);
204 /*NOTREACHED*/
208 * splits the unicode string 'wp' into an array of strings.
209 * the array is allocated by this function.
210 * the number of components will be stored in 'wpc'
211 * Free the array using FREE_KEY_PATH
213 static void
214 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
215 int i,j,len;
216 LPWSTR ws;
218 ws = HEAP_strdupW( SystemHeap, 0, wp );
219 *wpc = 1;
220 for (i=0;ws[i];i++) {
221 if (ws[i]=='\\') {
222 ws[i]=0;
223 (*wpc)++;
226 len = i;
227 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
228 (*wpv)[0]= ws;
229 j = 1;
230 for (i=1;i<len;i++)
231 if (ws[i-1]==0)
232 (*wpv)[j++]=ws+i;
233 (*wpv)[j]=NULL;
235 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
238 * Shell initialisation, allocates keys.
240 void SHELL_StartupRegistry();
241 void
242 SHELL_Init() {
243 struct passwd *pwd;
245 HKEY cl_r_hkey,c_u_hkey;
246 #define ADD_ROOT_KEY(xx) \
247 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
248 memset(xx,'\0',sizeof(KEYSTRUCT));\
249 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
251 ADD_ROOT_KEY(key_local_machine);
252 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
253 ERR(reg,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
254 exit(1);
256 key_classes_root = lookup_hkey(cl_r_hkey);
258 ADD_ROOT_KEY(key_users);
260 #if 0
261 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
262 * (later, when a win32 registry editing tool becomes avail.)
264 while (pwd=getpwent()) {
265 if (pwd->pw_name == NULL)
266 continue;
267 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
268 RegCloseKey(c_u_hkey);
270 #endif
271 pwd=getpwuid(getuid());
272 if (pwd && pwd->pw_name) {
273 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
274 key_current_user = lookup_hkey(c_u_hkey);
275 } else {
276 ADD_ROOT_KEY(key_current_user);
278 ADD_ROOT_KEY(key_performance_data);
279 ADD_ROOT_KEY(key_current_config);
280 ADD_ROOT_KEY(key_dyn_data);
281 #undef ADD_ROOT_KEY
282 SHELL_StartupRegistry();
286 void
287 SHELL_StartupRegistry() {
288 HKEY hkey;
289 char buf[200];
291 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&hkey);
292 RegCloseKey(hkey);
294 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
295 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
296 RegCloseKey(hkey);
297 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
298 * CurrentVersion
299 * CurrentBuildNumber
300 * CurrentType
301 * string RegisteredOwner
302 * string RegisteredOrganization
305 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
306 * string SysContact
307 * string SysLocation
308 * SysServices
310 if (-1!=gethostname(buf,200)) {
311 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
312 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
313 RegCloseKey(hkey);
316 /************************ SAVE Registry Function ****************************/
318 #define REGISTRY_SAVE_VERSION 0x00000001
320 /* Registry saveformat:
321 * If you change it, increase above number by 1, which will flush
322 * old registry database files.
324 * Global:
325 * "WINE REGISTRY Version %d"
326 * subkeys....
327 * Subkeys:
328 * keyname
329 * valuename=lastmodified,type,data
330 * ...
331 * subkeys
332 * ...
333 * keyname,valuename,stringdata:
334 * the usual ascii characters from 0x00-0xff (well, not 0x00)
335 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
336 * ( "=\\\t" escaped in \uXXXX form.)
337 * type,lastmodified:
338 * int
340 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
342 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
343 * SaveOnlyUpdatedKeys=yes
345 static int
346 _save_check_tainted(LPKEYSTRUCT lpkey) {
347 int tainted;
349 if (!lpkey)
350 return 0;
351 if (lpkey->flags & REG_OPTION_TAINTED)
352 tainted = 1;
353 else
354 tainted = 0;
355 while (lpkey) {
356 if (_save_check_tainted(lpkey->nextsub)) {
357 lpkey->flags |= REG_OPTION_TAINTED;
358 tainted = 1;
360 lpkey = lpkey->next;
362 return tainted;
365 static void
366 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
367 LPWSTR s;
368 int doescape;
370 if (wstr==NULL)
371 return;
372 s=wstr;
373 while (*s) {
374 doescape=0;
375 if (*s>0xff)
376 doescape = 1;
377 if (*s=='\n')
378 doescape = 1;
379 if (escapeeq && *s=='=')
380 doescape = 1;
381 if (*s=='\\')
382 fputc(*s,F); /* if \\ then put it twice. */
383 if (doescape)
384 fprintf(F,"\\u%04x",*((unsigned short*)s));
385 else
386 fputc(*s,F);
387 s++;
391 static int
392 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
393 LPKEYSTRUCT lpxkey;
394 int i,tabs,j;
396 lpxkey = lpkey;
397 while (lpxkey) {
398 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
399 (all || (lpxkey->flags & REG_OPTION_TAINTED))
401 for (tabs=level;tabs--;)
402 fputc('\t',F);
403 _save_USTRING(F,lpxkey->keyname,1);
404 fputs("\n",F);
405 for (i=0;i<lpxkey->nrofvalues;i++) {
406 LPKEYVALUE val=lpxkey->values+i;
408 for (tabs=level+1;tabs--;)
409 fputc('\t',F);
410 _save_USTRING(F,val->name,0);
411 fputc('=',F);
412 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
413 if ((1<<val->type) & UNICONVMASK)
414 _save_USTRING(F,(LPWSTR)val->data,0);
415 else
416 for (j=0;j<val->len;j++)
417 fprintf(F,"%02x",*((unsigned char*)val->data+j));
418 fputs("\n",F);
420 /* descend recursively */
421 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
422 return 0;
424 lpxkey=lpxkey->next;
426 return 1;
429 static int
430 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
431 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
432 _save_check_tainted(lpkey->nextsub);
433 return _savesubkey(F,lpkey->nextsub,0,all);
436 static BOOL32
437 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
438 FILE *F;
440 F=fopen(fn,"w");
441 if (F==NULL) {
442 WARN(reg,"Couldn't open %s for writing: %s\n",
443 fn,strerror(errno)
445 return FALSE;
447 if (!_savesubreg(F,lpkey,all)) {
448 fclose(F);
449 unlink(fn);
450 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
451 return FALSE;
453 fclose(F);
454 return TRUE;
457 void
458 SHELL_SaveRegistry() {
459 char *fn;
460 struct passwd *pwd;
461 char buf[4];
462 HKEY hkey;
463 int all;
465 all=0;
466 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
467 strcpy(buf,"yes");
468 } else {
469 DWORD len,junk,type;
471 len=4;
472 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
473 hkey,
474 VAL_SAVEUPDATED,
475 &junk,
476 &type,
477 buf,
478 &len
479 ))|| (type!=REG_SZ)
481 strcpy(buf,"yes");
482 RegCloseKey(hkey);
484 if (lstrcmpi32A(buf,"yes"))
485 all=1;
486 pwd=getpwuid(getuid());
487 if (pwd!=NULL && pwd->pw_dir!=NULL)
489 char *tmp;
491 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
492 strlen(SAVE_CURRENT_USER) + 2 );
493 strcpy(fn,pwd->pw_dir);
494 strcat(fn,WINE_PREFIX);
495 /* create the directory. don't care about errorcodes. */
496 mkdir(fn,0755); /* drwxr-xr-x */
497 strcat(fn,"/"SAVE_CURRENT_USER);
498 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
499 strcpy(tmp,fn);strcat(tmp,".tmp");
500 if (_savereg(key_current_user,tmp,all)) {
501 if (-1==rename(tmp,fn)) {
502 perror("rename tmp registry");
503 unlink(tmp);
506 free(tmp);
507 free(fn);
508 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
509 strcpy(fn,pwd->pw_dir);
510 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
511 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
512 strcpy(tmp,fn);strcat(tmp,".tmp");
513 if (_savereg(key_local_machine,tmp,all)) {
514 if (-1==rename(tmp,fn)) {
515 perror("rename tmp registry");
516 unlink(tmp);
519 free(tmp);
520 free(fn);
521 } else
522 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
525 /************************ LOAD Registry Function ****************************/
527 static LPKEYSTRUCT
528 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
529 LPKEYSTRUCT lpxkey,*lplpkey;
531 if (keyname[0]==0) {
532 free(keyname);
533 return lpkey;
535 lplpkey= &(lpkey->nextsub);
536 lpxkey = *lplpkey;
537 while (lpxkey) {
538 if (!lstrcmpi32W(lpxkey->keyname,keyname))
539 break;
540 lplpkey = &(lpxkey->next);
541 lpxkey = *lplpkey;
543 if (lpxkey==NULL) {
544 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
545 lpxkey = *lplpkey;
546 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
547 lpxkey->keyname = keyname;
548 } else
549 free(keyname);
550 return lpxkey;
553 static void
554 _find_or_add_value(
555 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
556 DWORD lastmodified
558 LPKEYVALUE val=NULL;
559 int i;
561 if (name && !*name) {/* empty string equals default (NULL) value */
562 free(name);
563 name = NULL;
566 for (i=0;i<lpkey->nrofvalues;i++) {
567 val=lpkey->values+i;
568 if (name==NULL) {
569 if (val->name==NULL)
570 break;
571 } else {
572 if ( val->name!=NULL &&
573 !lstrcmpi32W(val->name,name)
575 break;
578 if (i==lpkey->nrofvalues) {
579 lpkey->values = xrealloc(
580 lpkey->values,
581 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
583 val=lpkey->values+i;
584 memset(val,'\0',sizeof(KEYVALUE));
585 val->name = name;
586 } else {
587 if (name)
588 free(name);
590 if (val->lastmodified<lastmodified) {
591 val->lastmodified=lastmodified;
592 val->type = type;
593 val->len = len;
594 if (val->data)
595 free(val->data);
596 val->data = data;
597 } else
598 free(data);
602 /* reads a line including dynamically enlarging the readbuffer and throwing
603 * away comments
605 static int
606 _wine_read_line(FILE *F,char **buf,int *len) {
607 char *s,*curread;
608 int mylen,curoff;
610 curread = *buf;
611 mylen = *len;
612 **buf = '\0';
613 while (1) {
614 while (1) {
615 s=fgets(curread,mylen,F);
616 if (s==NULL)
617 return 0; /* EOF */
618 if (NULL==(s=strchr(curread,'\n'))) {
619 /* buffer wasn't large enough */
620 curoff = strlen(*buf);
621 *buf = xrealloc(*buf,*len*2);
622 curread = *buf + curoff;
623 mylen = *len; /* we filled up the buffer and
624 * got new '*len' bytes to fill
626 *len = *len * 2;
627 } else {
628 *s='\0';
629 break;
632 /* throw away comments */
633 if (**buf=='#' || **buf==';') {
634 curread = *buf;
635 mylen = *len;
636 continue;
638 if (s) /* got end of line */
639 break;
641 return 1;
644 /* converts a char* into a UNICODE string (up to a special char)
645 * and returns the position exactly after that string
647 static char*
648 _wine_read_USTRING(char *buf,LPWSTR *str) {
649 char *s;
650 LPWSTR ws;
652 /* read up to "=" or "\0" or "\n" */
653 s = buf;
654 if (*s == '=') {
655 /* empty string is the win3.1 default value(NULL)*/
656 *str = NULL;
657 return s;
659 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
660 ws = *str;
661 while (*s && (*s!='\n') && (*s!='=')) {
662 if (*s!='\\')
663 *ws++=*((unsigned char*)s++);
664 else {
665 s++;
666 if (*s=='\\') {
667 *ws++='\\';
668 s++;
669 continue;
671 if (*s!='u') {
672 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
673 *ws++='\\';
674 *ws++=*s++;
675 } else {
676 char xbuf[5];
677 int wc;
679 s++;
680 memcpy(xbuf,s,4);xbuf[4]='\0';
681 if (!sscanf(xbuf,"%x",&wc))
682 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
683 s+=4;
684 *ws++ =(unsigned short)wc;
688 *ws = 0;
689 ws = *str;
690 if (*ws)
691 *str = strdupW(*str);
692 else
693 *str = NULL;
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 WARN(reg,"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 WARN(reg,"Unexpected character: %c\n",*s);
743 break;
745 s++;
746 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
747 WARN(reg,"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'+'\xa')<<4;
768 if (*s>='A' && *s<='F')
769 data[i]=(*s-'A'+'\xa')<<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'+'\xa';
775 if (*s>='A' && *s<='F')
776 data[i]|=*s-'A'+'\xa';
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 TRACE(reg,"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 WARN(reg,"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)xmalloc(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..0F: ? (someone fill in please)
883 * 10: WORD number of RGDB blocks
884 * 12: WORD ?
885 * 14: WORD always 0000?
886 * 16: WORD always 0001?
887 * 18..1F: ? (someone fill in please)
889 * 20: RGKN_section:
890 * header:
891 * 0 : "RGKN" - magic
892 * 4 : DWORD offset to first RGDB section
893 * 8 : DWORD offset to ?
894 * C..0x1B: ? (fill in)
895 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
897 * Disk Key Entry Structure:
898 * 00: DWORD - Free entry indicator(?)
899 * 04: DWORD - Hash = sum of bytes of keyname
900 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
901 * 0C: DWORD - disk address of PreviousLevel Key.
902 * 10: DWORD - disk address of Next Sublevel Key.
903 * 14: DWORD - disk address of Next Key (on same level).
904 * DKEP>18: WORD - Nr, Low Significant part.
905 * 1A: WORD - Nr, High Significant part.
907 * The disk address always points to the nr part of the previous key entry
908 * of the referenced key. Don't ask me why, or even if I got this correct
909 * from staring at 1kg of hexdumps. (DKEP)
911 * The High significant part of the structure seems to equal the number
912 * of the RGDB section. The low significant part is a unique ID within
913 * that RGDB section
915 * There are two minor corrections to the position of that structure.
916 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
917 * the DKE reread from there.
918 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
919 * CPS - I have not experienced the above phenomenon in my registry files
921 * RGDB_section:
922 * 00: "RGDB" - magic
923 * 04: DWORD offset to next RGDB section
924 * 08: DWORD ?
925 * 0C: WORD always 000d?
926 * 0E: WORD RGDB block number
927 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
928 * 14..1F: ?
929 * 20.....: disk keys
931 * disk key:
932 * 00: DWORD nextkeyoffset - offset to the next disk key structure
933 * 08: WORD nrLS - low significant part of NR
934 * 0A: WORD nrHS - high significant part of NR
935 * 0C: DWORD bytesused - bytes used in this structure.
936 * 10: WORD name_len - length of name in bytes. without \0
937 * 12: WORD nr_of_values - number of values.
938 * 14: char name[name_len] - name string. No \0.
939 * 14+name_len: disk values
940 * nextkeyoffset: ... next disk key
942 * disk value:
943 * 00: DWORD type - value type (hmm, could be WORD too)
944 * 04: DWORD - unknown, usually 0
945 * 08: WORD namelen - length of Name. 0 means name=NULL
946 * 0C: WORD datalen - length of Data.
947 * 10: char name[namelen] - name, no \0
948 * 10+namelen: BYTE data[datalen] - data, without \0 if string
949 * 10+namelen+datalen: next values or disk key
951 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
952 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
953 * structure) and reading another RGDB_section.
954 * repeat until end of file.
956 * An interesting relationship exists in RGDB_section. The value at offset
957 * 10 equals the value at offset 4 minus the value at offset 8. I have no
958 * idea at the moment what this means. (Kevin Cozens)
960 * FIXME: this description needs some serious help, yes.
963 struct _w95keyvalue {
964 unsigned long type;
965 unsigned short datalen;
966 char *name;
967 unsigned char *data;
968 unsigned long x1;
969 int lastmodified;
972 struct _w95key {
973 char *name;
974 int nrofvals;
975 struct _w95keyvalue *values;
976 struct _w95key *prevlvl;
977 struct _w95key *nextsub;
978 struct _w95key *next;
982 struct _w95_info {
983 char *rgknbuffer;
984 int rgknsize;
985 char *rgdbbuffer;
986 int rgdbsize;
987 int depth;
988 int lastmodified;
991 LPWSTR strcvtA2W(LPCSTR src, int nchars)
994 LPWSTR dest = xmalloc (2 * nchars + 2);
996 lstrcpynAtoW(dest,src,nchars+1);
997 dest[nchars] = 0;
998 return dest;
1001 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1002 int nrLS, int nrMS, struct _w95_info *info )
1005 /* Disk Key Header structure (RGDB part) */
1006 struct dkh {
1007 unsigned long nextkeyoff;
1008 unsigned short nrLS;
1009 unsigned short nrMS;
1010 unsigned long bytesused;
1011 unsigned short keynamelen;
1012 unsigned short values;
1013 unsigned long xx1;
1014 /* keyname */
1015 /* disk key values or nothing */
1017 /* Disk Key Value structure */
1018 struct dkv {
1019 unsigned long type;
1020 unsigned long x1;
1021 unsigned short valnamelen;
1022 unsigned short valdatalen;
1023 /* valname, valdata */
1027 struct dkh dkh;
1028 int bytesread = 0;
1029 char *rgdbdata = info->rgdbbuffer;
1030 int nbytes = info->rgdbsize;
1031 char *curdata = rgdbdata;
1032 char *end = rgdbdata + nbytes;
1033 int off_next_rgdb;
1034 char *next = rgdbdata;
1035 int nrgdb, i;
1036 LPKEYSTRUCT lpxkey;
1038 do {
1039 curdata = next;
1040 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1042 memcpy(&off_next_rgdb,curdata+4,4);
1043 next = curdata + off_next_rgdb;
1044 nrgdb = (int) *((short *)curdata + 7);
1046 } while (nrgdb != nrMS && (next < end));
1048 /* curdata now points to the start of the right RGDB section */
1049 curdata += 0x20;
1051 #define XREAD(whereto,len) \
1052 if ((curdata + len) <end) {\
1053 memcpy(whereto,curdata,len);\
1054 curdata+=len;\
1055 bytesread+=len;\
1058 do {
1059 XREAD(&dkh, sizeof (dkh));
1060 if (dkh.nrLS == nrLS) break;
1062 curdata += dkh.nextkeyoff - sizeof(dkh);
1063 } while (curdata < next);
1065 if (dkh.nrLS != nrLS) return (NULL);
1067 if (nrgdb != dkh.nrMS) {
1068 return (NULL);
1071 assert((dkh.keynamelen<2) || curdata[0]);
1072 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1073 curdata += dkh.keynamelen;
1075 for (i=0;i< dkh.values; i++) {
1076 struct dkv dkv;
1077 LPBYTE data;
1078 int len;
1079 LPWSTR name;
1081 XREAD(&dkv,sizeof(dkv));
1083 name = strcvtA2W(curdata, dkv.valnamelen);
1084 curdata += dkv.valnamelen;
1086 if ((1 << dkv.type) & UNICONVMASK) {
1087 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1088 len = 2*(dkv.valdatalen + 1);
1089 } else {
1090 /* I don't think we want to NULL terminate all data */
1091 data = xmalloc(dkv.valdatalen);
1092 memcpy (data, curdata, dkv.valdatalen);
1093 len = dkv.valdatalen;
1096 curdata += dkv.valdatalen;
1098 _find_or_add_value(
1099 lpxkey,
1100 name,
1101 dkv.type,
1102 data,
1103 len,
1104 info->lastmodified
1109 return (lpxkey);
1112 static void
1113 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1116 /* Disk Key Entry structure (RGKN part) */
1117 struct dke {
1118 unsigned long x1;
1119 unsigned long x2;
1120 unsigned long x3;/*usually 0xFFFFFFFF */
1121 unsigned long prevlvl;
1122 unsigned long nextsub;
1123 unsigned long next;
1124 unsigned short nrLS;
1125 unsigned short nrMS;
1126 } *dke = (struct dke *)off;
1127 LPKEYSTRUCT lpxkey;
1129 if (dke == NULL) {
1130 dke = (struct dke *) ((char *)info->rgknbuffer);
1133 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1134 /* XXX <-- This is a hack*/
1135 if (!lpxkey) {
1136 lpxkey = prevkey;
1139 if (dke->nextsub != -1 &&
1140 ((dke->nextsub - 0x20) < info->rgknsize)
1141 && (dke->nextsub > 0x20)) {
1143 _w95_walkrgkn(lpxkey,
1144 info->rgknbuffer + dke->nextsub - 0x20,
1145 info);
1148 if (dke->next != -1 &&
1149 ((dke->next - 0x20) < info->rgknsize) &&
1150 (dke->next > 0x20)) {
1151 _w95_walkrgkn(prevkey,
1152 info->rgknbuffer + dke->next - 0x20,
1153 info);
1156 return;
1159 static void
1160 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1161 HFILE32 hfd;
1162 char magic[5];
1163 unsigned long where,version,rgdbsection,end;
1164 struct _w95_info info;
1165 OFSTRUCT ofs;
1166 BY_HANDLE_FILE_INFORMATION hfdinfo;
1168 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1169 hfd=OpenFile32(fn,&ofs,OF_READ);
1170 if (hfd==HFILE_ERROR32)
1171 return;
1172 magic[4]=0;
1173 if (4!=_lread32(hfd,magic,4))
1174 return;
1175 if (strcmp(magic,"CREG")) {
1176 WARN(reg,"%s is not a w95 registry.\n",fn);
1177 return;
1179 if (4!=_lread32(hfd,&version,4))
1180 return;
1181 if (4!=_lread32(hfd,&rgdbsection,4))
1182 return;
1183 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1184 return;
1185 if (4!=_lread32(hfd,magic,4))
1186 return;
1187 if (strcmp(magic,"RGKN")) {
1188 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1189 return;
1192 /* STEP 1: Keylink structures */
1193 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1194 return;
1195 where = 0x40;
1196 end = rgdbsection;
1198 info.rgknsize = end - where;
1199 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1200 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1201 return;
1203 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1204 return;
1206 end = hfdinfo.nFileSizeLow;
1207 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1209 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1210 return;
1212 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1213 info.rgdbsize = end - rgdbsection;
1215 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1216 return;
1217 _lclose32(hfd);
1219 _w95_walkrgkn(lpkey, NULL, &info);
1221 free (info.rgdbbuffer);
1222 free (info.rgknbuffer);
1225 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1228 reghack - windows 3.11 registry data format demo program.
1230 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1231 a combined hash table and tree description, and finally a text table.
1233 The header is obvious from the struct header. The taboff1 and taboff2
1234 fields are always 0x20, and their usage is unknown.
1236 The 8-byte entry table has various entry types.
1238 tabent[0] is a root index. The second word has the index of the root of
1239 the directory.
1240 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1241 the index of the key/value that has that hash. Data with the same
1242 hash value are on a circular list. The other three words in the
1243 hash entry are always zero.
1244 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1245 entry: dirent and keyent/valent. They are identified by context.
1246 tabent[freeidx] is the first free entry. The first word in a free entry
1247 is the index of the next free entry. The last has 0 as a link.
1248 The other three words in the free list are probably irrelevant.
1250 Entries in text table are preceeded by a word at offset-2. This word
1251 has the value (2*index)+1, where index is the referring keyent/valent
1252 entry in the table. I have no suggestion for the 2* and the +1.
1253 Following the word, there are N bytes of data, as per the keyent/valent
1254 entry length. The offset of the keyent/valent entry is from the start
1255 of the text table to the first data byte.
1257 This information is not available from Microsoft. The data format is
1258 deduced from the reg.dat file by me. Mistakes may
1259 have been made. I claim no rights and give no guarantees for this program.
1261 Tor Sjøwall, tor@sn.no
1264 /* reg.dat header format */
1265 struct _w31_header {
1266 char cookie[8]; /* 'SHCC3.10' */
1267 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1268 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1269 unsigned long tabcnt; /* number of entries in index table */
1270 unsigned long textoff; /* offset of text part */
1271 unsigned long textsize; /* byte size of text part */
1272 unsigned short hashsize; /* hash size */
1273 unsigned short freeidx; /* free index */
1276 /* generic format of table entries */
1277 struct _w31_tabent {
1278 unsigned short w0, w1, w2, w3;
1281 /* directory tabent: */
1282 struct _w31_dirent {
1283 unsigned short sibling_idx; /* table index of sibling dirent */
1284 unsigned short child_idx; /* table index of child dirent */
1285 unsigned short key_idx; /* table index of key keyent */
1286 unsigned short value_idx; /* table index of value valent */
1289 /* key tabent: */
1290 struct _w31_keyent {
1291 unsigned short hash_idx; /* hash chain index for string */
1292 unsigned short refcnt; /* reference count */
1293 unsigned short length; /* length of string */
1294 unsigned short string_off; /* offset of string in text table */
1297 /* value tabent: */
1298 struct _w31_valent {
1299 unsigned short hash_idx; /* hash chain index for string */
1300 unsigned short refcnt; /* reference count */
1301 unsigned short length; /* length of string */
1302 unsigned short string_off; /* offset of string in text table */
1305 /* recursive helper function to display a directory tree */
1306 void
1307 __w31_dumptree( unsigned short idx,
1308 unsigned char *txt,
1309 struct _w31_tabent *tab,
1310 struct _w31_header *head,
1311 LPKEYSTRUCT lpkey,
1312 time_t lastmodified,
1313 int level
1315 struct _w31_dirent *dir;
1316 struct _w31_keyent *key;
1317 struct _w31_valent *val;
1318 LPKEYSTRUCT xlpkey = NULL;
1319 LPWSTR name,value;
1320 static char tail[400];
1322 while (idx!=0) {
1323 dir=(struct _w31_dirent*)&tab[idx];
1325 if (dir->key_idx) {
1326 key = (struct _w31_keyent*)&tab[dir->key_idx];
1328 memcpy(tail,&txt[key->string_off],key->length);
1329 tail[key->length]='\0';
1330 /* all toplevel entries AND the entries in the
1331 * toplevel subdirectory belong to \SOFTWARE\Classes
1333 if (!level && !lstrcmp32A(tail,".classes")) {
1334 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1335 idx=dir->sibling_idx;
1336 continue;
1338 name=strdupA2W(tail);
1340 xlpkey=_find_or_add_key(lpkey,name);
1342 /* only add if leaf node or valued node */
1343 if (dir->value_idx!=0||dir->child_idx==0) {
1344 if (dir->value_idx) {
1345 val=(struct _w31_valent*)&tab[dir->value_idx];
1346 memcpy(tail,&txt[val->string_off],val->length);
1347 tail[val->length]='\0';
1348 value=strdupA2W(tail);
1349 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1352 } else {
1353 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1355 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1356 idx=dir->sibling_idx;
1360 void
1361 _w31_loadreg() {
1362 HFILE32 hf;
1363 struct _w31_header head;
1364 struct _w31_tabent *tab;
1365 unsigned char *txt;
1366 int len;
1367 OFSTRUCT ofs;
1368 BY_HANDLE_FILE_INFORMATION hfinfo;
1369 time_t lastmodified;
1370 HKEY hkey;
1371 LPKEYSTRUCT lpkey;
1373 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1374 if (hf==HFILE_ERROR32)
1375 return;
1377 /* read & dump header */
1378 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1379 ERR(reg, "reg.dat is too short.\n");
1380 _lclose32(hf);
1381 return;
1383 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1384 ERR(reg, "reg.dat has bad signature.\n");
1385 _lclose32(hf);
1386 return;
1389 len = head.tabcnt * sizeof(struct _w31_tabent);
1390 /* read and dump index table */
1391 tab = xmalloc(len);
1392 if (len!=_lread32(hf,tab,len)) {
1393 ERR(reg,"couldn't read %d bytes.\n",len);
1394 free(tab);
1395 _lclose32(hf);
1396 return;
1399 /* read text */
1400 txt = xmalloc(head.textsize);
1401 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1402 ERR(reg,"couldn't seek to textblock.\n");
1403 free(tab);
1404 free(txt);
1405 _lclose32(hf);
1406 return;
1408 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1409 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1410 free(tab);
1411 free(txt);
1412 _lclose32(hf);
1413 return;
1416 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1417 ERR(reg,"GetFileInformationByHandle failed?.\n");
1418 free(tab);
1419 free(txt);
1420 _lclose32(hf);
1421 return;
1423 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1425 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1426 return;
1427 lpkey = lookup_hkey(hkey);
1428 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1429 free(tab);
1430 free(txt);
1431 _lclose32(hf);
1432 return;
1435 void
1436 SHELL_LoadRegistry() {
1437 char *fn;
1438 struct passwd *pwd;
1439 LPKEYSTRUCT lpkey;
1440 HKEY hkey;
1443 if (key_classes_root==NULL)
1444 SHELL_Init();
1446 /* Load windows 3.1 entries */
1447 _w31_loadreg();
1448 /* Load windows 95 entries */
1449 _w95_loadreg("C:\\system.1st", key_local_machine);
1450 _w95_loadreg("system.dat", key_local_machine);
1451 _w95_loadreg("user.dat", key_users);
1453 /* the global user default is loaded under HKEY_USERS\\.Default */
1454 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1455 lpkey = lookup_hkey(hkey);
1456 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1458 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1459 _copy_registry(lpkey,key_current_user);
1460 RegCloseKey(hkey);
1462 /* the global machine defaults */
1463 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1465 /* load the user saved registries */
1467 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1469 pwd=getpwuid(getuid());
1470 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1471 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1472 strcpy(fn,pwd->pw_dir);
1473 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1474 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1475 free(fn);
1476 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1477 strcpy(fn,pwd->pw_dir);
1478 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1479 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1480 free(fn);
1481 } else
1482 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1483 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1484 DWORD junk,type,len;
1485 char data[5];
1487 len=4;
1488 if (( RegQueryValueEx32A(
1489 hkey,
1490 VAL_SAVEUPDATED,
1491 &junk,
1492 &type,
1493 data,
1494 &len
1495 )!=ERROR_SUCCESS) ||
1496 type != REG_SZ
1498 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1499 RegCloseKey(hkey);
1504 /********************* API FUNCTIONS ***************************************/
1506 * Open Keys.
1508 * All functions are stubs to RegOpenKeyEx32W where all the
1509 * magic happens.
1511 * FIXME: security,options,desiredaccess,...
1513 * Callpath:
1514 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1515 * RegOpenKey32W -> RegOpenKeyEx32W
1518 /* RegOpenKeyExW [ADVAPI32.150] */
1519 DWORD WINAPI RegOpenKeyEx32W(
1520 HKEY hkey,
1521 LPCWSTR lpszSubKey,
1522 DWORD dwReserved,
1523 REGSAM samDesired,
1524 LPHKEY retkey
1526 LPKEYSTRUCT lpNextKey,lpxkey;
1527 LPWSTR *wps;
1528 int wpc,i;
1529 TRACE(reg,"(%lx,%s,%ld,%lx,%p)\n",
1530 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1533 lpNextKey = lookup_hkey(hkey);
1534 if (!lpNextKey)
1535 return SHELL_ERROR_BADKEY;
1536 if (!lpszSubKey || !*lpszSubKey) {
1537 add_handle(++currenthandle,lpNextKey,samDesired);
1538 *retkey=currenthandle;
1539 return SHELL_ERROR_SUCCESS;
1541 split_keypath(lpszSubKey,&wps,&wpc);
1542 i = 0;
1543 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1544 lpxkey = lpNextKey;
1545 while (wps[i]) {
1546 lpxkey=lpNextKey->nextsub;
1547 while (lpxkey) {
1548 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1549 break;
1550 lpxkey=lpxkey->next;
1552 if (!lpxkey) {
1553 FREE_KEY_PATH;
1554 return SHELL_ERROR_BADKEY;
1556 i++;
1557 lpNextKey = lpxkey;
1559 add_handle(++currenthandle,lpxkey,samDesired);
1560 *retkey = currenthandle;
1561 FREE_KEY_PATH;
1562 return SHELL_ERROR_SUCCESS;
1565 /* RegOpenKeyW [ADVAPI32.151] */
1566 DWORD WINAPI RegOpenKey32W(
1567 HKEY hkey,
1568 LPCWSTR lpszSubKey,
1569 LPHKEY retkey
1571 TRACE(reg,"(%lx,%s,%p)\n",
1572 (LONG)hkey,W2C(lpszSubKey,0),retkey
1574 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1578 /* RegOpenKeyExA [ADVAPI32.149] */
1579 DWORD WINAPI RegOpenKeyEx32A(
1580 HKEY hkey,
1581 LPCSTR lpszSubKey,
1582 DWORD dwReserved,
1583 REGSAM samDesired,
1584 LPHKEY retkey
1586 LPWSTR lpszSubKeyW;
1587 DWORD ret;
1589 TRACE(reg,"(%lx,%s,%ld,%lx,%p)\n",
1590 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1592 if (lpszSubKey)
1593 lpszSubKeyW=strdupA2W(lpszSubKey);
1594 else
1595 lpszSubKeyW=NULL;
1596 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1597 if (lpszSubKeyW)
1598 free(lpszSubKeyW);
1599 return ret;
1602 /* RegOpenKeyA [ADVAPI32.148] */
1603 DWORD WINAPI RegOpenKey32A(
1604 HKEY hkey,
1605 LPCSTR lpszSubKey,
1606 LPHKEY retkey
1608 TRACE(reg,"(%lx,%s,%p)\n",
1609 (LONG)hkey,lpszSubKey,retkey
1611 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1614 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1615 DWORD WINAPI RegOpenKey16(
1616 HKEY hkey,
1617 LPCSTR lpszSubKey,
1618 LPHKEY retkey
1620 TRACE(reg,"(%lx,%s,%p)\n",
1621 (LONG)hkey,lpszSubKey,retkey
1623 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1627 * Create keys
1629 * All those functions convert their respective
1630 * arguments and call RegCreateKeyExW at the end.
1632 * FIXME: no security,no access attrib,no optionhandling yet.
1634 * Callpath:
1635 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1636 * RegCreateKey32W -> RegCreateKeyEx32W
1639 /* RegCreateKeyExW [ADVAPI32.131] */
1640 DWORD WINAPI RegCreateKeyEx32W(
1641 HKEY hkey,
1642 LPCWSTR lpszSubKey,
1643 DWORD dwReserved,
1644 LPWSTR lpszClass,
1645 DWORD fdwOptions,
1646 REGSAM samDesired,
1647 LPSECURITY_ATTRIBUTES lpSecAttribs,
1648 LPHKEY retkey,
1649 LPDWORD lpDispos
1651 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1652 LPWSTR *wps;
1653 int wpc,i;
1655 /*FIXME: handle security/access/whatever */
1656 TRACE(reg,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1657 (LONG)hkey,
1658 W2C(lpszSubKey,0),
1659 dwReserved,
1660 W2C(lpszClass,1),
1661 fdwOptions,
1662 samDesired,
1663 lpSecAttribs,
1664 retkey,
1665 lpDispos
1668 lpNextKey = lookup_hkey(hkey);
1669 if (!lpNextKey)
1670 return SHELL_ERROR_BADKEY;
1671 if (!lpszSubKey || !*lpszSubKey) {
1672 add_handle(++currenthandle,lpNextKey,samDesired);
1673 *retkey=currenthandle;
1674 lpNextKey->flags|=REG_OPTION_TAINTED;
1675 return SHELL_ERROR_SUCCESS;
1677 split_keypath(lpszSubKey,&wps,&wpc);
1678 i = 0;
1679 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1680 lpxkey = lpNextKey;
1681 while (wps[i]) {
1682 lpxkey=lpNextKey->nextsub;
1683 while (lpxkey) {
1684 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1685 break;
1686 lpxkey=lpxkey->next;
1688 if (!lpxkey)
1689 break;
1690 i++;
1691 lpNextKey = lpxkey;
1693 if (lpxkey) {
1694 add_handle(++currenthandle,lpxkey,samDesired);
1695 lpxkey->flags |= REG_OPTION_TAINTED;
1696 *retkey = currenthandle;
1697 if (lpDispos)
1698 *lpDispos = REG_OPENED_EXISTING_KEY;
1699 FREE_KEY_PATH;
1700 return SHELL_ERROR_SUCCESS;
1702 /* good. now the hard part */
1703 while (wps[i]) {
1704 lplpPrevKey = &(lpNextKey->nextsub);
1705 lpxkey = *lplpPrevKey;
1706 while (lpxkey) {
1707 lplpPrevKey = &(lpxkey->next);
1708 lpxkey = *lplpPrevKey;
1710 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1711 if (!*lplpPrevKey) {
1712 FREE_KEY_PATH;
1713 return SHELL_ERROR_OUTOFMEMORY;
1715 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1716 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1717 (*lplpPrevKey)->next = NULL;
1718 (*lplpPrevKey)->nextsub = NULL;
1719 (*lplpPrevKey)->values = NULL;
1720 (*lplpPrevKey)->nrofvalues = 0;
1721 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1722 if (lpszClass)
1723 (*lplpPrevKey)->class = strdupW(lpszClass);
1724 else
1725 (*lplpPrevKey)->class = NULL;
1726 lpNextKey = *lplpPrevKey;
1727 i++;
1729 add_handle(++currenthandle,lpNextKey,samDesired);
1731 /*FIXME: flag handling correct? */
1732 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1733 if (lpszClass)
1734 lpNextKey->class = strdupW(lpszClass);
1735 else
1736 lpNextKey->class = NULL;
1737 *retkey = currenthandle;
1738 if (lpDispos)
1739 *lpDispos = REG_CREATED_NEW_KEY;
1740 FREE_KEY_PATH;
1741 return SHELL_ERROR_SUCCESS;
1744 /* RegCreateKeyW [ADVAPI32.132] */
1745 DWORD WINAPI RegCreateKey32W(
1746 HKEY hkey,
1747 LPCWSTR lpszSubKey,
1748 LPHKEY retkey
1750 DWORD junk,ret;
1752 TRACE(reg,"(%lx,%s,%p)\n",
1753 (LONG)hkey,W2C(lpszSubKey,0),retkey
1755 ret=RegCreateKeyEx32W(
1756 hkey, /* key handle */
1757 lpszSubKey, /* subkey name */
1758 0, /* reserved = 0 */
1759 NULL, /* lpszClass? FIXME: ? */
1760 REG_OPTION_NON_VOLATILE, /* options */
1761 KEY_ALL_ACCESS, /* desired access attribs */
1762 NULL, /* lpsecurity attributes */
1763 retkey, /* lpretkey */
1764 &junk /* disposition value */
1766 return ret;
1769 /* RegCreateKeyExA [ADVAPI32.130] */
1770 DWORD WINAPI RegCreateKeyEx32A(
1771 HKEY hkey,
1772 LPCSTR lpszSubKey,
1773 DWORD dwReserved,
1774 LPSTR lpszClass,
1775 DWORD fdwOptions,
1776 REGSAM samDesired,
1777 LPSECURITY_ATTRIBUTES lpSecAttribs,
1778 LPHKEY retkey,
1779 LPDWORD lpDispos
1781 LPWSTR lpszSubKeyW,lpszClassW;
1782 DWORD ret;
1784 TRACE(reg,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1785 (LONG)hkey,
1786 lpszSubKey,
1787 dwReserved,
1788 lpszClass,
1789 fdwOptions,
1790 samDesired,
1791 lpSecAttribs,
1792 retkey,
1793 lpDispos
1795 if (lpszSubKey)
1796 lpszSubKeyW=strdupA2W(lpszSubKey);
1797 else
1798 lpszSubKeyW=NULL;
1799 if (lpszClass)
1800 lpszClassW=strdupA2W(lpszClass);
1801 else
1802 lpszClassW=NULL;
1803 ret=RegCreateKeyEx32W(
1804 hkey,
1805 lpszSubKeyW,
1806 dwReserved,
1807 lpszClassW,
1808 fdwOptions,
1809 samDesired,
1810 lpSecAttribs,
1811 retkey,
1812 lpDispos
1814 if (lpszSubKeyW)
1815 free(lpszSubKeyW);
1816 if (lpszClassW)
1817 free(lpszClassW);
1818 return ret;
1821 /* RegCreateKeyA [ADVAPI32.129] */
1822 DWORD WINAPI RegCreateKey32A(
1823 HKEY hkey,
1824 LPCSTR lpszSubKey,
1825 LPHKEY retkey
1827 DWORD junk;
1829 TRACE(reg,"(%lx,%s,%p)\n",
1830 (LONG)hkey,lpszSubKey,retkey
1832 return RegCreateKeyEx32A(
1833 hkey, /* key handle */
1834 lpszSubKey, /* subkey name */
1835 0, /* reserved = 0 */
1836 NULL, /* lpszClass? FIXME: ? */
1837 REG_OPTION_NON_VOLATILE,/* options */
1838 KEY_ALL_ACCESS, /* desired access attribs */
1839 NULL, /* lpsecurity attributes */
1840 retkey, /* lpretkey */
1841 &junk /* disposition value */
1845 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1846 DWORD WINAPI RegCreateKey16(
1847 HKEY hkey,
1848 LPCSTR lpszSubKey,
1849 LPHKEY retkey
1851 TRACE(reg,"(%lx,%s,%p)\n",
1852 (LONG)hkey,lpszSubKey,retkey
1854 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1858 * Query Value Functions
1859 * Win32 differs between keynames and valuenames.
1860 * multiple values may belong to one key, the special value
1861 * with name NULL is the default value used by the win31
1862 * compat functions.
1864 * Callpath:
1865 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1866 * RegQueryValue32W -> RegQueryValueEx32W
1869 /* RegQueryValueExW [ADVAPI32.158] */
1870 DWORD WINAPI RegQueryValueEx32W(
1871 HKEY hkey,
1872 LPWSTR lpszValueName,
1873 LPDWORD lpdwReserved,
1874 LPDWORD lpdwType,
1875 LPBYTE lpbData,
1876 LPDWORD lpcbData
1878 LPKEYSTRUCT lpkey;
1879 int i;
1881 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
1882 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1883 lpcbData?*lpcbData:0);
1885 lpkey = lookup_hkey(hkey);
1886 if (!lpkey)
1887 return SHELL_ERROR_BADKEY;
1888 if (lpszValueName && !*lpszValueName)
1889 lpszValueName = NULL;
1890 if (lpszValueName==NULL) {
1891 for (i=0;i<lpkey->nrofvalues;i++)
1892 if (lpkey->values[i].name==NULL)
1893 break;
1894 } else {
1895 for (i=0;i<lpkey->nrofvalues;i++)
1896 if ( lpkey->values[i].name &&
1897 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
1899 break;
1901 if (i==lpkey->nrofvalues) {
1902 if (lpszValueName==NULL) {
1903 if (lpbData) {
1904 *(WCHAR*)lpbData = 0;
1905 *lpcbData = 2;
1907 if (lpdwType)
1908 *lpdwType = REG_SZ;
1909 return SHELL_ERROR_SUCCESS;
1911 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1913 if (lpdwType)
1914 *lpdwType = lpkey->values[i].type;
1915 if (lpbData==NULL) {
1916 if (lpcbData==NULL)
1917 return SHELL_ERROR_SUCCESS;
1918 *lpcbData = lpkey->values[i].len;
1919 return SHELL_ERROR_SUCCESS;
1921 if (*lpcbData<lpkey->values[i].len) {
1922 *(WCHAR*)lpbData= 0;
1923 *lpcbData = lpkey->values[i].len;
1924 return ERROR_MORE_DATA;
1926 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1927 *lpcbData = lpkey->values[i].len;
1928 return SHELL_ERROR_SUCCESS;
1931 /* RegQueryValueW [ADVAPI32.159] */
1932 DWORD WINAPI RegQueryValue32W(
1933 HKEY hkey,
1934 LPWSTR lpszSubKey,
1935 LPWSTR lpszData,
1936 LPDWORD lpcbData
1938 HKEY xhkey;
1939 DWORD ret,lpdwType;
1941 TRACE(reg,"(%x,%s,%p,%ld)\n",
1942 hkey,W2C(lpszSubKey,0),lpszData,
1943 lpcbData?*lpcbData:0);
1945 /* only open subkey, if we really do descend */
1946 if (lpszSubKey && *lpszSubKey) {
1947 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1948 if (ret!=ERROR_SUCCESS)
1949 return ret;
1950 } else
1951 xhkey = hkey;
1953 lpdwType = REG_SZ;
1954 ret = RegQueryValueEx32W(
1955 xhkey,
1956 NULL, /* varname NULL -> compat */
1957 NULL, /* lpdwReserved, must be NULL */
1958 &lpdwType,
1959 (LPBYTE)lpszData,
1960 lpcbData
1962 if (xhkey!=hkey)
1963 RegCloseKey(xhkey);
1964 return ret;
1967 /* RegQueryValueExA [ADVAPI32.157] */
1968 DWORD WINAPI RegQueryValueEx32A(
1969 HKEY hkey,
1970 LPSTR lpszValueName,
1971 LPDWORD lpdwReserved,
1972 LPDWORD lpdwType,
1973 LPBYTE lpbData,
1974 LPDWORD lpcbData
1976 LPWSTR lpszValueNameW;
1977 LPBYTE buf;
1978 DWORD ret,myxlen;
1979 DWORD *mylen;
1980 DWORD type;
1982 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
1983 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1984 lpcbData?*lpcbData:0);
1986 if (lpszValueName)
1987 lpszValueNameW=strdupA2W(lpszValueName);
1988 else
1989 lpszValueNameW=NULL;
1991 if (lpdwType)
1992 type=*lpdwType;
1994 if (lpbData) {
1995 myxlen = 0;
1996 mylen = &myxlen;
1997 buf = xmalloc(4);
1998 ret=RegQueryValueEx32W(
1999 hkey,
2000 lpszValueNameW,
2001 lpdwReserved,
2002 &type,
2003 buf,
2004 mylen
2006 free(buf);
2007 if (ret==ERROR_MORE_DATA) {
2008 buf = (LPBYTE)xmalloc(*mylen);
2009 } else {
2010 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2011 myxlen = 2*(*lpcbData);
2013 } else {
2014 buf=NULL;
2015 if (lpcbData) {
2016 myxlen = *lpcbData*2;
2017 mylen = &myxlen;
2018 } else
2019 mylen = NULL;
2021 ret=RegQueryValueEx32W(
2022 hkey,
2023 lpszValueNameW,
2024 lpdwReserved,
2025 &type,
2026 buf,
2027 mylen
2029 if (lpdwType)
2030 *lpdwType=type;
2031 if (ret==ERROR_SUCCESS) {
2032 if (buf) {
2033 if (UNICONVMASK & (1<<(type))) {
2034 /* convert UNICODE to ASCII */
2035 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2036 *lpcbData = myxlen/2;
2037 } else {
2038 if (myxlen>*lpcbData)
2039 ret = ERROR_MORE_DATA;
2040 else
2041 memcpy(lpbData,buf,myxlen);
2043 *lpcbData = myxlen;
2045 } else {
2046 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2047 *lpcbData = myxlen/2;
2049 } else {
2050 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2051 *lpcbData = myxlen/2;
2053 if (buf)
2054 free(buf);
2055 return ret;
2058 /* RegQueryValueEx [KERNEL.225] */
2059 DWORD WINAPI RegQueryValueEx16(
2060 HKEY hkey,
2061 LPSTR lpszValueName,
2062 LPDWORD lpdwReserved,
2063 LPDWORD lpdwType,
2064 LPBYTE lpbData,
2065 LPDWORD lpcbData
2067 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",
2068 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2069 lpcbData?*lpcbData:0);
2071 return RegQueryValueEx32A(
2072 hkey,
2073 lpszValueName,
2074 lpdwReserved,
2075 lpdwType,
2076 lpbData,
2077 lpcbData
2081 /* RegQueryValueA [ADVAPI32.156] */
2082 DWORD WINAPI RegQueryValue32A(
2083 HKEY hkey,
2084 LPSTR lpszSubKey,
2085 LPSTR lpszData,
2086 LPDWORD lpcbData
2088 HKEY xhkey;
2089 DWORD ret,lpdwType;
2091 TRACE(reg,"(%x,%s,%p,%ld)\n",
2092 hkey,lpszSubKey,lpszData,
2093 lpcbData?*lpcbData:0);
2095 /* only open subkey, if we really do descend */
2096 if (lpszSubKey && *lpszSubKey) {
2097 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2098 if (ret!=ERROR_SUCCESS)
2099 return ret;
2100 } else
2101 xhkey = hkey;
2103 lpdwType = REG_SZ;
2104 ret = RegQueryValueEx32A(
2105 xhkey,
2106 NULL, /* lpszValueName NULL -> compat */
2107 NULL, /* lpdwReserved, must be NULL */
2108 &lpdwType,
2109 (LPBYTE)lpszData,
2110 lpcbData
2112 if (xhkey!=hkey)
2113 RegCloseKey(xhkey);
2114 return ret;
2117 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2118 DWORD WINAPI RegQueryValue16(
2119 HKEY hkey,
2120 LPSTR lpszSubKey,
2121 LPSTR lpszData,
2122 LPDWORD lpcbData
2124 TRACE(reg,"(%x,%s,%p,%ld)\n",
2125 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0);
2127 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2128 * anyway, so we just mask out the high 16 bit.
2129 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2131 if (lpcbData)
2132 *lpcbData &= 0xFFFF;
2133 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2137 * Setting values of Registry keys
2139 * Callpath:
2140 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2141 * RegSetValue32W -> RegSetValueEx32W
2144 /* RegSetValueExW [ADVAPI32.170] */
2145 DWORD WINAPI RegSetValueEx32W(
2146 HKEY hkey,
2147 LPWSTR lpszValueName,
2148 DWORD dwReserved,
2149 DWORD dwType,
2150 LPBYTE lpbData,
2151 DWORD cbData
2153 LPKEYSTRUCT lpkey;
2154 int i;
2156 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2157 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2159 /* we no longer care about the lpbData type here... */
2160 lpkey = lookup_hkey(hkey);
2161 if (!lpkey)
2162 return SHELL_ERROR_BADKEY;
2164 lpkey->flags |= REG_OPTION_TAINTED;
2166 if (lpszValueName==NULL) {
2167 for (i=0;i<lpkey->nrofvalues;i++)
2168 if (lpkey->values[i].name==NULL)
2169 break;
2170 } else {
2171 for (i=0;i<lpkey->nrofvalues;i++)
2172 if ( lpkey->values[i].name &&
2173 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2175 break;
2177 if (i==lpkey->nrofvalues) {
2178 lpkey->values = (LPKEYVALUE)xrealloc(
2179 lpkey->values,
2180 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2182 lpkey->nrofvalues++;
2183 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2185 if (lpkey->values[i].name==NULL)
2186 if (lpszValueName)
2187 lpkey->values[i].name = strdupW(lpszValueName);
2188 else
2189 lpkey->values[i].name = NULL;
2190 lpkey->values[i].len = cbData;
2191 lpkey->values[i].type = dwType;
2192 if (lpkey->values[i].data !=NULL)
2193 free(lpkey->values[i].data);
2194 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2195 lpkey->values[i].lastmodified = time(NULL);
2196 memcpy(lpkey->values[i].data,lpbData,cbData);
2197 return SHELL_ERROR_SUCCESS;
2200 /* RegSetValueExA [ADVAPI32.169] */
2201 DWORD WINAPI RegSetValueEx32A(
2202 HKEY hkey,
2203 LPSTR lpszValueName,
2204 DWORD dwReserved,
2205 DWORD dwType,
2206 LPBYTE lpbData,
2207 DWORD cbData
2209 LPBYTE buf;
2210 LPWSTR lpszValueNameW;
2211 DWORD ret;
2213 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2214 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2216 if ((1<<dwType) & UNICONVMASK) {
2217 buf=(LPBYTE)strdupA2W(lpbData);
2218 cbData=2*strlen(lpbData)+2;
2219 } else
2220 buf=lpbData;
2221 if (lpszValueName)
2222 lpszValueNameW = strdupA2W(lpszValueName);
2223 else
2224 lpszValueNameW = NULL;
2225 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2226 if (lpszValueNameW)
2227 free(lpszValueNameW);
2228 if (buf!=lpbData)
2229 free(buf);
2230 return ret;
2233 /* RegSetValueEx [KERNEL.226] */
2234 DWORD WINAPI RegSetValueEx16(
2235 HKEY hkey,
2236 LPSTR lpszValueName,
2237 DWORD dwReserved,
2238 DWORD dwType,
2239 LPBYTE lpbData,
2240 DWORD cbData
2242 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",
2243 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2245 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2248 /* RegSetValueW [ADVAPI32.171] */
2249 DWORD WINAPI RegSetValue32W(
2250 HKEY hkey,
2251 LPCWSTR lpszSubKey,
2252 DWORD dwType,
2253 LPCWSTR lpszData,
2254 DWORD cbData
2256 HKEY xhkey;
2257 DWORD ret;
2259 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2260 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2262 if (lpszSubKey && *lpszSubKey) {
2263 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2264 if (ret!=ERROR_SUCCESS)
2265 return ret;
2266 } else
2267 xhkey=hkey;
2268 if (dwType!=REG_SZ) {
2269 TRACE(reg,"RegSetValueX called with dwType=%ld!\n",dwType);
2270 dwType=REG_SZ;
2272 if (cbData!=2*lstrlen32W(lpszData)+2) {
2273 TRACE(reg,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2274 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2276 cbData=2*lstrlen32W(lpszData)+2;
2278 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2279 if (hkey!=xhkey)
2280 RegCloseKey(xhkey);
2281 return ret;
2284 /* RegSetValueA [ADVAPI32.168] */
2285 DWORD WINAPI RegSetValue32A(
2286 HKEY hkey,
2287 LPCSTR lpszSubKey,
2288 DWORD dwType,
2289 LPCSTR lpszData,
2290 DWORD cbData
2292 DWORD ret;
2293 HKEY xhkey;
2295 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2296 hkey,lpszSubKey,dwType,lpszData,cbData
2298 if (lpszSubKey && *lpszSubKey) {
2299 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2300 if (ret!=ERROR_SUCCESS)
2301 return ret;
2302 } else
2303 xhkey=hkey;
2305 if (dwType!=REG_SZ) {
2306 TRACE(reg,"RegSetValueA called with dwType=%ld!\n",dwType);
2307 dwType=REG_SZ;
2309 if (cbData!=strlen(lpszData)+1)
2310 cbData=strlen(lpszData)+1;
2311 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2312 if (xhkey!=hkey)
2313 RegCloseKey(xhkey);
2314 return ret;
2317 /* RegSetValue [KERNEL.221] [SHELL.5] */
2318 DWORD WINAPI RegSetValue16(
2319 HKEY hkey,
2320 LPCSTR lpszSubKey,
2321 DWORD dwType,
2322 LPCSTR lpszData,
2323 DWORD cbData
2325 DWORD ret;
2326 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2327 hkey,lpszSubKey,dwType,lpszData,cbData
2329 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2330 return ret;
2334 * Key Enumeration
2336 * Callpath:
2337 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2338 * RegEnumKey32W -> RegEnumKeyEx32W
2341 /* RegEnumKeyExW [ADVAPI32.139] */
2342 DWORD WINAPI RegEnumKeyEx32W(
2343 HKEY hkey,
2344 DWORD iSubkey,
2345 LPWSTR lpszName,
2346 LPDWORD lpcchName,
2347 LPDWORD lpdwReserved,
2348 LPWSTR lpszClass,
2349 LPDWORD lpcchClass,
2350 FILETIME *ft
2352 LPKEYSTRUCT lpkey,lpxkey;
2354 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2355 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2357 lpkey=lookup_hkey(hkey);
2358 if (!lpkey)
2359 return SHELL_ERROR_BADKEY;
2360 if (!lpkey->nextsub)
2361 return ERROR_NO_MORE_ITEMS;
2362 lpxkey=lpkey->nextsub;
2363 while (iSubkey && lpxkey) {
2364 iSubkey--;
2365 lpxkey=lpxkey->next;
2367 if (iSubkey || !lpxkey)
2368 return ERROR_NO_MORE_ITEMS;
2369 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2370 return ERROR_MORE_DATA;
2371 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2372 if (lpszClass) {
2373 /* what should we write into it? */
2374 *lpszClass = 0;
2375 *lpcchClass = 2;
2377 return ERROR_SUCCESS;
2381 /* RegEnumKeyW [ADVAPI32.140] */
2382 DWORD WINAPI RegEnumKey32W(
2383 HKEY hkey,
2384 DWORD iSubkey,
2385 LPWSTR lpszName,
2386 DWORD lpcchName
2388 FILETIME ft;
2390 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2391 hkey,iSubkey,lpszName,lpcchName
2393 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2395 /* RegEnumKeyExA [ADVAPI32.138] */
2396 DWORD WINAPI RegEnumKeyEx32A(
2397 HKEY hkey,
2398 DWORD iSubkey,
2399 LPSTR lpszName,
2400 LPDWORD lpcchName,
2401 LPDWORD lpdwReserved,
2402 LPSTR lpszClass,
2403 LPDWORD lpcchClass,
2404 FILETIME *ft
2406 DWORD ret,lpcchNameW,lpcchClassW;
2407 LPWSTR lpszNameW,lpszClassW;
2410 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2411 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2413 if (lpszName) {
2414 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2415 lpcchNameW = *lpcchName*2;
2416 } else {
2417 lpszNameW = NULL;
2418 lpcchNameW = 0;
2420 if (lpszClass) {
2421 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2422 lpcchClassW = *lpcchClass*2;
2423 } else {
2424 lpszClassW =0;
2425 lpcchClassW=0;
2427 ret=RegEnumKeyEx32W(
2428 hkey,
2429 iSubkey,
2430 lpszNameW,
2431 &lpcchNameW,
2432 lpdwReserved,
2433 lpszClassW,
2434 &lpcchClassW,
2437 if (ret==ERROR_SUCCESS) {
2438 lstrcpyWtoA(lpszName,lpszNameW);
2439 *lpcchName=strlen(lpszName);
2440 if (lpszClassW) {
2441 lstrcpyWtoA(lpszClass,lpszClassW);
2442 *lpcchClass=strlen(lpszClass);
2445 if (lpszNameW)
2446 free(lpszNameW);
2447 if (lpszClassW)
2448 free(lpszClassW);
2449 return ret;
2452 /* RegEnumKeyA [ADVAPI32.137] */
2453 DWORD WINAPI RegEnumKey32A(
2454 HKEY hkey,
2455 DWORD iSubkey,
2456 LPSTR lpszName,
2457 DWORD lpcchName
2459 FILETIME ft;
2461 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2462 hkey,iSubkey,lpszName,lpcchName
2464 return RegEnumKeyEx32A(
2465 hkey,
2466 iSubkey,
2467 lpszName,
2468 &lpcchName,
2469 NULL,
2470 NULL,
2471 NULL,
2476 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2477 DWORD WINAPI RegEnumKey16(
2478 HKEY hkey,
2479 DWORD iSubkey,
2480 LPSTR lpszName,
2481 DWORD lpcchName
2483 TRACE(reg,"(%x,%ld,%p,%ld)\n",
2484 hkey,iSubkey,lpszName,lpcchName
2486 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2490 * Enumerate Registry Values
2492 * Callpath:
2493 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2496 /* RegEnumValueW [ADVAPI32.142] */
2497 DWORD WINAPI RegEnumValue32W(
2498 HKEY hkey,
2499 DWORD iValue,
2500 LPWSTR lpszValue,
2501 LPDWORD lpcchValue,
2502 LPDWORD lpdReserved,
2503 LPDWORD lpdwType,
2504 LPBYTE lpbData,
2505 LPDWORD lpcbData
2507 LPKEYSTRUCT lpkey;
2508 LPKEYVALUE val;
2510 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2511 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2513 lpkey = lookup_hkey(hkey);
2514 if (!lpkey)
2515 return SHELL_ERROR_BADKEY;
2516 if (lpkey->nrofvalues<=iValue)
2517 return ERROR_NO_MORE_ITEMS;
2518 val = lpkey->values+iValue;
2520 if (val->name) {
2521 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2522 *lpcchValue = lstrlen32W(val->name)*2+2;
2523 return ERROR_MORE_DATA;
2525 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2526 *lpcchValue=lstrlen32W(val->name)*2+2;
2527 } else {
2528 *lpszValue = 0;
2529 *lpcchValue = 0;
2531 if (lpdwType)
2532 *lpdwType=val->type;
2533 if (lpbData) {
2534 if (val->len>*lpcbData)
2535 return ERROR_MORE_DATA;
2536 memcpy(lpbData,val->data,val->len);
2537 *lpcbData = val->len;
2539 return SHELL_ERROR_SUCCESS;
2542 /* RegEnumValueA [ADVAPI32.141] */
2543 DWORD WINAPI RegEnumValue32A(
2544 HKEY hkey,
2545 DWORD iValue,
2546 LPSTR lpszValue,
2547 LPDWORD lpcchValue,
2548 LPDWORD lpdReserved,
2549 LPDWORD lpdwType,
2550 LPBYTE lpbData,
2551 LPDWORD lpcbData
2553 LPWSTR lpszValueW;
2554 LPBYTE lpbDataW;
2555 DWORD ret,lpcbDataW;
2557 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2558 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2561 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2562 if (lpbData) {
2563 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2564 lpcbDataW = *lpcbData*2;
2565 } else
2566 lpbDataW = NULL;
2567 ret=RegEnumValue32W(
2568 hkey,
2569 iValue,
2570 lpszValueW,
2571 lpcchValue,
2572 lpdReserved,
2573 lpdwType,
2574 lpbDataW,
2575 &lpcbDataW
2578 if (ret==ERROR_SUCCESS) {
2579 lstrcpyWtoA(lpszValue,lpszValueW);
2580 if (lpbData) {
2581 if ((1<<*lpdwType) & UNICONVMASK) {
2582 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2583 } else {
2584 if (lpcbDataW > *lpcbData)
2585 ret = ERROR_MORE_DATA;
2586 else
2587 memcpy(lpbData,lpbDataW,lpcbDataW);
2589 *lpcbData = lpcbDataW;
2592 if (lpbDataW)
2593 free(lpbDataW);
2594 if (lpszValueW)
2595 free(lpszValueW);
2596 return ret;
2599 /* RegEnumValue [KERNEL.223] */
2600 DWORD WINAPI RegEnumValue16(
2601 HKEY hkey,
2602 DWORD iValue,
2603 LPSTR lpszValue,
2604 LPDWORD lpcchValue,
2605 LPDWORD lpdReserved,
2606 LPDWORD lpdwType,
2607 LPBYTE lpbData,
2608 LPDWORD lpcbData
2610 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2611 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2613 return RegEnumValue32A(
2614 hkey,
2615 iValue,
2616 lpszValue,
2617 lpcchValue,
2618 lpdReserved,
2619 lpdwType,
2620 lpbData,
2621 lpcbData
2626 * Close registry key
2628 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2629 DWORD WINAPI RegCloseKey(HKEY hkey) {
2630 TRACE(reg,"(%x)\n",hkey);
2631 remove_handle(hkey);
2632 return ERROR_SUCCESS;
2635 * Delete registry key
2637 * Callpath:
2638 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2640 /* RegDeleteKeyW [ADVAPI32.134] */
2641 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2642 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2643 LPWSTR *wps;
2644 int wpc,i;
2646 TRACE(reg,"(%x,%s)\n",
2647 hkey,W2C(lpszSubKey,0)
2649 lpNextKey = lookup_hkey(hkey);
2650 if (!lpNextKey) {
2651 TRACE(reg, " Badkey[1].\n");
2652 return SHELL_ERROR_BADKEY;
2654 /* we need to know the previous key in the hier. */
2655 if (!lpszSubKey || !*lpszSubKey) {
2656 TRACE(reg, " Badkey[2].\n");
2657 return SHELL_ERROR_BADKEY;
2659 split_keypath(lpszSubKey,&wps,&wpc);
2660 i = 0;
2661 lpxkey = lpNextKey;
2662 while (i<wpc-1) {
2663 lpxkey=lpNextKey->nextsub;
2664 while (lpxkey) {
2665 TRACE(reg, " Scanning [%s]\n",
2666 W2C (lpxkey->keyname, 0));
2667 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2668 break;
2669 lpxkey=lpxkey->next;
2671 if (!lpxkey) {
2672 FREE_KEY_PATH;
2673 TRACE(reg, " Not found.\n");
2674 /* not found is success */
2675 return SHELL_ERROR_SUCCESS;
2677 i++;
2678 lpNextKey = lpxkey;
2680 lpxkey = lpNextKey->nextsub;
2681 lplpPrevKey = &(lpNextKey->nextsub);
2682 while (lpxkey) {
2683 TRACE(reg, " Scanning [%s]\n",
2684 W2C (lpxkey->keyname, 0));
2685 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2686 break;
2687 lplpPrevKey = &(lpxkey->next);
2688 lpxkey = lpxkey->next;
2690 if (!lpxkey) {
2691 FREE_KEY_PATH;
2692 WARN(reg , " Not found.\n");
2693 return SHELL_ERROR_BADKEY;
2695 if (lpxkey->nextsub) {
2696 FREE_KEY_PATH;
2697 WARN(reg , " Not empty.\n");
2698 return SHELL_ERROR_CANTWRITE;
2700 *lplpPrevKey = lpxkey->next;
2701 free(lpxkey->keyname);
2702 if (lpxkey->class)
2703 free(lpxkey->class);
2704 if (lpxkey->values)
2705 free(lpxkey->values);
2706 free(lpxkey);
2707 FREE_KEY_PATH;
2708 TRACE(reg, " Done.\n");
2709 return SHELL_ERROR_SUCCESS;
2712 /* RegDeleteKeyA [ADVAPI32.133] */
2713 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2714 LPWSTR lpszSubKeyW;
2715 DWORD ret;
2717 TRACE(reg,"(%x,%s)\n",
2718 hkey,lpszSubKey
2720 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2721 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2722 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2723 return ret;
2726 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2727 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2728 TRACE(reg,"(%x,%s)\n",
2729 hkey,lpszSubKey
2731 return RegDeleteKey32A(hkey,lpszSubKey);
2735 * Delete registry value
2737 * Callpath:
2738 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2740 /* RegDeleteValueW [ADVAPI32.136] */
2741 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2743 DWORD i;
2744 LPKEYSTRUCT lpkey;
2745 LPKEYVALUE val;
2747 TRACE(reg,"(%x,%s)\n",
2748 hkey,W2C(lpszValue,0)
2750 lpkey=lookup_hkey(hkey);
2751 if (!lpkey)
2752 return SHELL_ERROR_BADKEY;
2753 if (lpszValue) {
2754 for (i=0;i<lpkey->nrofvalues;i++)
2755 if ( lpkey->values[i].name &&
2756 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2758 break;
2759 } else {
2760 for (i=0;i<lpkey->nrofvalues;i++)
2761 if (lpkey->values[i].name==NULL)
2762 break;
2764 if (i==lpkey->nrofvalues)
2765 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2766 val = lpkey->values+i;
2767 if (val->name) free(val->name);
2768 if (val->data) free(val->data);
2769 memcpy(
2770 lpkey->values+i,
2771 lpkey->values+i+1,
2772 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2774 lpkey->values = (LPKEYVALUE)xrealloc(
2775 lpkey->values,
2776 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2778 lpkey->nrofvalues--;
2779 return SHELL_ERROR_SUCCESS;
2782 /* RegDeleteValueA [ADVAPI32.135] */
2783 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2785 LPWSTR lpszValueW;
2786 DWORD ret;
2788 TRACE(reg, "(%x,%s)\n", hkey,lpszValue );
2789 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2790 ret=RegDeleteValue32W(hkey,lpszValueW);
2791 HeapFree(GetProcessHeap(),0,lpszValueW);
2792 return ret;
2795 /* RegDeleteValue [KERNEL.222] */
2796 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2798 TRACE(reg,"(%x,%s)\n", hkey,lpszValue );
2799 return RegDeleteValue32A(hkey,lpszValue);
2803 /******************************************************************************
2804 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
2805 * Writes key to registry
2807 * PARAMS
2808 * hkey [I] Handle of key to write
2810 * RETURNS
2811 * Success: ERROR_SUCCESS
2812 * Failure: Error code
2814 DWORD WINAPI RegFlushKey( HKEY hkey )
2816 FIXME(reg, "(%x): stub\n", hkey);
2817 return ERROR_SUCCESS;
2821 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2823 /* RegQueryInfoKeyW [ADVAPI32.153] */
2824 DWORD WINAPI RegQueryInfoKey32W(
2825 HKEY hkey,
2826 LPWSTR lpszClass,
2827 LPDWORD lpcchClass,
2828 LPDWORD lpdwReserved,
2829 LPDWORD lpcSubKeys,
2830 LPDWORD lpcchMaxSubkey,
2831 LPDWORD lpcchMaxClass,
2832 LPDWORD lpcValues,
2833 LPDWORD lpcchMaxValueName,
2834 LPDWORD lpccbMaxValueData,
2835 LPDWORD lpcbSecurityDescriptor,
2836 FILETIME *ft
2838 LPKEYSTRUCT lpkey,lpxkey;
2839 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2840 int i;
2842 TRACE(reg,"(%x,......)\n",hkey);
2843 lpkey=lookup_hkey(hkey);
2844 if (!lpkey)
2845 return SHELL_ERROR_BADKEY;
2846 if (lpszClass) {
2847 if (lpkey->class) {
2848 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2849 *lpcchClass=lstrlen32W(lpkey->class)*2;
2850 return ERROR_MORE_DATA;
2852 *lpcchClass=lstrlen32W(lpkey->class)*2;
2853 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2854 } else {
2855 *lpszClass = 0;
2856 *lpcchClass = 0;
2858 } else {
2859 if (lpcchClass)
2860 *lpcchClass = lstrlen32W(lpkey->class)*2;
2862 lpxkey=lpkey->nextsub;
2863 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2864 while (lpxkey) {
2865 nrofkeys++;
2866 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2867 maxsubkey=lstrlen32W(lpxkey->keyname);
2868 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2869 maxclass=lstrlen32W(lpxkey->class);
2870 if (lpxkey->nrofvalues>maxvalues)
2871 maxvalues=lpxkey->nrofvalues;
2872 for (i=0;i<lpxkey->nrofvalues;i++) {
2873 LPKEYVALUE val=lpxkey->values+i;
2875 if (val->name && lstrlen32W(val->name)>maxvname)
2876 maxvname=lstrlen32W(val->name);
2877 if (val->len>maxvdata)
2878 maxvdata=val->len;
2880 lpxkey=lpxkey->next;
2882 if (!maxclass) maxclass = 1;
2883 if (!maxvname) maxvname = 1;
2884 if (lpcSubKeys)
2885 *lpcSubKeys = nrofkeys;
2886 if (lpcchMaxSubkey)
2887 *lpcchMaxSubkey = maxsubkey*2;
2888 if (lpcchMaxClass)
2889 *lpcchMaxClass = maxclass*2;
2890 if (lpcValues)
2891 *lpcValues = maxvalues;
2892 if (lpcchMaxValueName)
2893 *lpcchMaxValueName= maxvname;
2894 if (lpccbMaxValueData)
2895 *lpccbMaxValueData= maxvdata;
2896 return SHELL_ERROR_SUCCESS;
2899 /* RegQueryInfoKeyA [ADVAPI32.152] */
2900 DWORD WINAPI RegQueryInfoKey32A(
2901 HKEY hkey,
2902 LPSTR lpszClass,
2903 LPDWORD lpcchClass,
2904 LPDWORD lpdwReserved,
2905 LPDWORD lpcSubKeys,
2906 LPDWORD lpcchMaxSubkey,
2907 LPDWORD lpcchMaxClass,
2908 LPDWORD lpcValues,
2909 LPDWORD lpcchMaxValueName,
2910 LPDWORD lpccbMaxValueData,
2911 LPDWORD lpcbSecurityDescriptor,
2912 FILETIME *ft
2914 LPWSTR lpszClassW;
2915 DWORD ret;
2917 TRACE(reg,"(%x,......)\n",hkey);
2918 if (lpszClass) {
2919 *lpcchClass*= 2;
2920 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2922 } else
2923 lpszClassW = NULL;
2924 ret=RegQueryInfoKey32W(
2925 hkey,
2926 lpszClassW,
2927 lpcchClass,
2928 lpdwReserved,
2929 lpcSubKeys,
2930 lpcchMaxSubkey,
2931 lpcchMaxClass,
2932 lpcValues,
2933 lpcchMaxValueName,
2934 lpccbMaxValueData,
2935 lpcbSecurityDescriptor,
2938 if (ret==ERROR_SUCCESS && lpszClass)
2939 lstrcpyWtoA(lpszClass,lpszClassW);
2940 if (lpcchClass)
2941 *lpcchClass/=2;
2942 if (lpcchMaxSubkey)
2943 *lpcchMaxSubkey/=2;
2944 if (lpcchMaxClass)
2945 *lpcchMaxClass/=2;
2946 if (lpcchMaxValueName)
2947 *lpcchMaxValueName/=2;
2948 if (lpszClassW)
2949 free(lpszClassW);
2950 return ret;
2952 /* RegConnectRegistryA [ADVAPI32.127] */
2953 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
2955 FIXME(reg,"(%s,%08x,%p):stub.\n",machine,hkey,reskey);
2956 return ERROR_FILE_NOT_FOUND; /* FIXME */
2960 /******************************************************************************
2961 * RegGetKeySecurity [ADVAPI32.144]
2962 * Retrieves a copy of security descriptor protecting the registry key
2964 * NOTES
2965 * pSecurityDescriptor should be PSECURITY_DESCRIPTOR
2967 * RETURNS
2968 * Success: ERROR_SUCCESS
2969 * Failure: Error code
2971 LONG WINAPI RegGetKeySecurity( HKEY hKey,
2972 SECURITY_INFORMATION SecurityInformation,
2973 LPVOID pSecurityDescriptor,
2974 LPDWORD lpcbSecurityDescriptor )
2976 FIXME(reg, "(%d,%ld,%p,%p): stub\n", hKey, SecurityInformation,
2977 pSecurityDescriptor, lpcbSecurityDescriptor);
2978 return ERROR_SUCCESS;