Release 960428
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/fcntl.h>
15 #include <sys/stat.h>
16 #include <pwd.h>
17 #include <time.h>
18 #include "windows.h"
19 #include "win.h"
20 #include "winerror.h"
21 #include "string32.h"   
22 #include "stddebug.h"
23 #include "debug.h"
24 #include "xmalloc.h"
25 #include "winreg.h"
26
27 /* FIXME: following defines should be configured global ... */
28
29 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
30 #define WINE_PREFIX                     "/.wine"
31 #define SAVE_CURRENT_USER_DEFAULT       "/usr/local/etc/wine.userreg"
32         /* relative in ~user/.wine/ */
33 #define SAVE_CURRENT_USER               "user.reg"
34 #define SAVE_LOCAL_MACHINE_DEFAULT      "/usr/local/etc/wine.systemreg"
35         /* relative in ~user/.wine/ */
36 #define SAVE_LOCAL_MACHINE              "system.reg"
37
38 static KEYSTRUCT        *key_classes_root=NULL; /* windows 3.1 global values */
39 static KEYSTRUCT        *key_current_user=NULL; /* user specific values */
40 static KEYSTRUCT        *key_local_machine=NULL;/* machine specific values */
41 static KEYSTRUCT        *key_users=NULL;        /* all users? */
42
43 /* dynamic, not saved */
44 static KEYSTRUCT        *key_performance_data=NULL;
45 static KEYSTRUCT        *key_current_config=NULL;
46 static KEYSTRUCT        *key_dyn_data=NULL;
47
48 /* what valuetypes do we need to convert? */
49 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
50
51 #define strdupA2W(x)    STRING32_DupAnsiToUni(x)
52 #define strdupW2A(x)    STRING32_DupUniToAnsi(x)
53 #define strdupW(x)      STRING32_strdupW(x)
54 #define strcmpW(a,b)    STRING32_lstrcmpW(a,b)
55 #define strcmpniW(a,b)  STRING32_lstrcmpniW(a,b)
56 #define strchrW(a,c)    STRING32_lstrchrW(a,c)
57 #define strlenW(a)      STRING32_UniLen(a)
58 #define strcpyWA(a,b)   STRING32_UniToAnsi(a,b)
59
60 static struct openhandle {
61         LPKEYSTRUCT     lpkey;
62         HKEY            hkey;
63         REGSAM          accessmask;
64 }  *openhandles=NULL;
65 static int      nrofopenhandles=0;
66 static int      currenthandle=1;
67
68 static void
69 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
70         int     i;
71
72         for (i=0;i<nrofopenhandles;i++) {
73                 if (openhandles[i].lpkey==lpkey) {
74                         dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
75                 }
76                 if (openhandles[i].hkey==hkey) {
77                         dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
78                 }
79         }
80         openhandles=xrealloc(   openhandles,
81                                 sizeof(struct openhandle)*(nrofopenhandles+1)
82                 );
83         openhandles[i].lpkey    = lpkey;
84         openhandles[i].hkey     = hkey;
85         openhandles[i].accessmask= accessmask;
86         nrofopenhandles++;
87 }
88
89 static LPKEYSTRUCT
90 get_handle(HKEY hkey) {
91         int     i;
92
93         for (i=0;i<nrofopenhandles;i++)
94                 if (openhandles[i].hkey==hkey)
95                         return openhandles[i].lpkey;
96         dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
97         return NULL;
98 }
99
100 static void
101 remove_handle(HKEY hkey) {
102         int     i;
103
104         for (i=0;i<nrofopenhandles;i++)
105                 if (openhandles[i].hkey==hkey)
106                         break;
107         if (i==nrofopenhandles) {
108                 dprintf_reg(stddeb,"remove_handle:Didn't find handle %lx?\n",hkey);
109                 return;
110         }
111         memcpy( openhandles+i,
112                 openhandles+i+1,
113                 sizeof(struct openhandle)*(nrofopenhandles-i-1)
114         );
115         openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
116         nrofopenhandles--;
117         return;
118 }
119
120
121 /* debug function, converts a unicode into a static memory area 
122  * (sub for using two static strings, in case we need them in a single call)
123  */
124 LPSTR
125 W2C(LPCWSTR x,int sub) {
126         static  LPSTR   unicodedebug[2]={NULL,NULL};
127         if (x==NULL)
128                 return "<NULL>";
129         if (sub!=0 && sub!=1)
130                 return "<W2C:bad sub>";
131         if (unicodedebug[sub]) free(unicodedebug[sub]);
132         unicodedebug[sub]       = strdupW2A(x);
133         return unicodedebug[sub];
134 }
135
136 static LPKEYSTRUCT
137 lookup_hkey(HKEY hkey) {
138         switch (hkey) {
139         case 0x00000000:
140         case 0x00000001:
141         case HKEY_CLASSES_ROOT:
142                 return key_classes_root;
143         case HKEY_CURRENT_USER:
144                 return key_current_user;
145         case HKEY_LOCAL_MACHINE:
146                 return key_local_machine;
147         case HKEY_USERS:
148                 return key_users;
149         case HKEY_PERFORMANCE_DATA:
150                 return key_performance_data;
151         case HKEY_DYN_DATA:
152                 return key_dyn_data;
153         case HKEY_CURRENT_CONFIG:
154                 return key_current_config;
155         default:
156                 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
157                         (LONG)hkey
158                 );
159                 return get_handle(hkey);
160         }
161         /*NOTREACHED*/
162 }
163
164 /* 
165  * splits the unicode string 'wp' into an array of strings.
166  * the array is allocated by this function. 
167  * the number of components will be stored in 'wpc'
168  * Free the array using FREE_KEY_PATH
169  */
170 static void
171 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
172         int     i,j,len;
173         LPWSTR  ws;
174
175         ws      = strdupW(wp);
176         *wpc    = 1;
177         for (i=0;ws[i];i++) {
178                 if (ws[i]=='\\') {
179                         ws[i]=0;
180                         (*wpc)++;
181                 }
182         }
183         len     = i;
184         *wpv    = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2));
185         (*wpv)[0]= ws;
186         j       = 1;
187         for (i=1;i<len;i++)
188                 if (ws[i-1]==0)
189                         (*wpv)[j++]=ws+i;
190         (*wpv)[j]=NULL;
191 }
192 #define FREE_KEY_PATH   free(wps[0]);free(wps);
193
194 /*
195  * Shell initialisation, allocates keys. 
196  */
197 void
198 SHELL_Init() {
199         struct  passwd  *pwd;
200
201         HKEY    cl_r_hkey,c_u_hkey;
202 #define ADD_ROOT_KEY(xx) \
203         xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
204         memset(xx,'\0',sizeof(KEYSTRUCT));\
205         xx->keyname= strdupA2W("<should_not_appear_anywhere>");
206
207         ADD_ROOT_KEY(key_local_machine);
208         if (RegCreateKey(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
209                 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
210                 exit(1);
211         }
212         key_classes_root = lookup_hkey(cl_r_hkey);
213
214         ADD_ROOT_KEY(key_users);
215
216 #if 0
217         /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg 
218          *        (later, when a win32 registry editing tool becomes avail.)
219          */
220         while (pwd=getpwent()) {
221                 if (pwd->pw_name == NULL)
222                         continue;
223                 RegCreateKey(HKEY_USERS,pwd->pw_name,&c_u_hkey);
224                 RegCloseKey(c_u_hkey);
225         }
226 #endif
227         pwd=getpwuid(getuid());
228         if (pwd && pwd->pw_name) {
229                 RegCreateKey(HKEY_USERS,pwd->pw_name,&c_u_hkey);
230                 key_current_user = lookup_hkey(c_u_hkey);
231         } else {
232                 ADD_ROOT_KEY(key_current_user);
233         }
234         ADD_ROOT_KEY(key_performance_data);
235         ADD_ROOT_KEY(key_current_config);
236         ADD_ROOT_KEY(key_dyn_data);
237 #undef ADD_ROOT_KEY
238 }
239
240 /************************ SAVE Registry Function ****************************/
241
242 #define REGISTRY_SAVE_VERSION   0x00000001
243
244 /* Registry saveformat:
245  * If you change it, increase above number by 1, which will flush
246  * old registry database files.
247  * 
248  * Global:
249  *      "WINE REGISTRY Version %d"
250  *      subkeys....
251  * Subkeys:
252  *      keyname
253  *              valuename=lastmodified,type,data
254  *              ...
255  *              subkeys
256  *      ...
257  * keyname,valuename,stringdata:
258  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
259  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
260  *      ( "=\\\t" escaped in \uXXXX form.)
261  * type,lastmodified: 
262  *      int
263  * 
264  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
265  */
266
267 static void
268 _write_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
269         LPWSTR  s;
270         int     doescape;
271
272         if (wstr==NULL) {
273                 /* FIXME: NULL equals empty string... I hope
274                  * the empty string isn't a valid valuename
275                  */
276                 return;
277         }
278         s=wstr;
279         while (*s) {
280                 doescape=0;
281                 if (*s>0xff)
282                         doescape = 1;
283                 if (*s=='\n')
284                         doescape = 1;
285                 if (escapeeq && *s=='=')
286                         doescape = 1;
287                 if (*s=='\\')
288                         fputc(*s,F); /* if \\ than put it twice. */
289                 if (doescape)
290                         fprintf(F,"\\u%04x",*((unsigned short*)s));
291                 else
292                         fputc(*s,F);
293                 s++;
294         }
295 }
296
297 static int
298 _do_save_subkey(FILE *F,LPKEYSTRUCT lpkey,int level) {
299         LPKEYSTRUCT     lpxkey;
300         int             i,tabs,j;
301
302         lpxkey  = lpkey;
303         while (lpxkey) {
304                 if (!(lpxkey->flags & REG_OPTION_VOLATILE)) {
305                         for (tabs=level;tabs--;)
306                                 fputc('\t',F);
307                         _write_USTRING(F,lpxkey->keyname,1);
308                         fputs("\n",F);
309                         for (i=0;i<lpxkey->nrofvalues;i++) {
310                                 LPKEYVALUE      val=lpxkey->values+i;
311
312                                 for (tabs=level+1;tabs--;)
313                                         fputc('\t',F);
314                                 _write_USTRING(F,val->name,0);
315                                 fputc('=',F);
316                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
317                                 if ((1<<val->type) & UNICONVMASK)
318                                         _write_USTRING(F,(LPWSTR)val->data,0);
319                                 else
320                                         for (j=0;j<val->len;j++)
321                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
322                                 fputs("\n",F);
323                         }
324                         /* descend recursively */
325                         if (!_do_save_subkey(F,lpxkey->nextsub,level+1))
326                                 return 0;
327                 }
328                 lpxkey=lpxkey->next;
329         }
330         return 1;
331 }
332
333 static int
334 _do_savesubreg(FILE *F,LPKEYSTRUCT lpkey) {
335         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
336         return _do_save_subkey(F,lpkey->nextsub,0);
337 }
338
339 static void
340 _SaveSubReg(LPKEYSTRUCT lpkey,char *fn) {
341         FILE    *F;
342
343         F=fopen(fn,"w");
344         if (F==NULL) {
345                 fprintf(stddeb,__FILE__":_SaveSubReg:Couldn't open %s for writing: %s\n",
346                         fn,strerror(errno)
347                 );
348                 return;
349         }
350         if (!_do_savesubreg(F,lpkey)) {
351                 fclose(F);
352                 unlink(fn);
353                 fprintf(stddeb,__FILE__":_SaveSubReg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
354                 return;
355         }
356         fclose(F);
357 }
358
359 void
360 SHELL_SaveRegistry() {
361         char    *fn;
362         struct  passwd  *pwd;
363
364         pwd=getpwuid(getuid());
365         if (pwd!=NULL && pwd->pw_dir!=NULL) {
366                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
367                 strcpy(fn,pwd->pw_dir);
368                 strcat(fn,WINE_PREFIX);
369                 /* create the directory. don't care about errorcodes. */
370                 mkdir(fn,0755); /* drwxr-xr-x */
371                 strcat(fn,"/"SAVE_CURRENT_USER);
372                 _SaveSubReg(key_current_user,fn);
373                 free(fn);
374                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
375                 strcpy(fn,pwd->pw_dir);
376                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
377                 _SaveSubReg(key_local_machine,fn);
378                 free(fn);
379         } else {
380                 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
381         }
382 }
383
384 /************************ LOAD Registry Function ****************************/
385
386 /* reads a line including dynamically enlarging the readbuffer and throwing
387  * away comments
388  */
389 static int 
390 _read_line(FILE *F,char **buf,int *len) {
391         char    *s,*curread;
392         int     mylen,curoff;
393
394         curread = *buf;
395         mylen   = *len;
396         **buf   = '\0';
397         while (1) {
398                 while (1) {
399                         s=fgets(curread,mylen,F);
400                         if (s==NULL)
401                                 return 0; /* EOF */
402                         if (NULL==(s=strchr(curread,'\n'))) {
403                                 /* buffer wasn't large enough */
404                                 curoff  = strlen(*buf);
405                                 *buf    = xrealloc(*buf,*len*2);
406                                 curread = *buf + curoff;
407                                 mylen   = *len; /* we filled up the buffer and 
408                                                  * got new '*len' bytes to fill
409                                                  */
410                                 *len    = *len * 2;
411                         } else {
412                                 *s='\0';
413                                 break;
414                         }
415                 }
416                 /* throw away comments */
417                 if (**buf=='#' || **buf==';') {
418                         curread = *buf;
419                         mylen   = *len;
420                         continue;
421                 }
422                 if (s)  /* got end of line */
423                         break;
424         }
425         return 1;
426 }
427
428 /* converts a char* into a UNICODE string (up to a special char)
429  * and returns the position exactly after that string
430  */
431 static char*
432 _read_USTRING(char *buf,LPWSTR *str) {
433         char    *s;
434         LPWSTR  ws;
435
436         /* read up to "=" or "\0" or "\n" */
437         s       = buf;
438         if (*s == '=') {
439                 /* empty string is the win3.1 default value(NULL)*/
440                 *str    = NULL;
441                 return s;
442         }
443         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
444         ws      = *str;
445         while (*s && (*s!='\n') && (*s!='=')) {
446                 if (*s!='\\')
447                         *ws++=*((unsigned char*)s++);
448                 else {
449                         s++;
450                         if (*s=='\\') {
451                                 *ws+='\\';
452                                 s++;
453                                 continue;
454                         }
455                         if (*s!='u') {
456                                 fprintf(stderr,"_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
457                                 *ws++='\\';
458                                 *ws++=*s++;
459                         } else {
460                                 char    xbuf[5];
461                                 int     wc;
462
463                                 s++;
464                                 memcpy(xbuf,s,4);xbuf[4]='\0';
465                                 if (!sscanf(xbuf,"%x",&wc))
466                                         fprintf(stderr,"_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
467                                 s+=4;
468                                 *ws++   =(unsigned short)wc;
469                         }
470                 }
471         }
472         *ws     = 0;
473         ws      = *str;
474         *str    = strdupW(*str);
475         free(ws);
476         return s;
477 }
478
479 static int
480 _do_load_subkey(FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen) {
481         LPKEYSTRUCT     lpxkey,*lplpkey;
482         int             i;
483         char            *s;
484         LPWSTR          name;
485
486         /* good. we already got a line here ... so parse it */
487         lpxkey  = NULL;
488         while (1) {
489                 i=0;s=*buf;
490                 while (*s=='\t') {
491                         s++;
492                         i++;
493                 }
494                 if (i>level) {
495                         if (lpxkey==NULL) {
496                                 fprintf(stderr,"_do_load_subkey:Got a subhierarchy without resp. key?\n");
497                                 return 0;
498                         }
499                         _do_load_subkey(F,lpxkey,level+1,buf,buflen);
500                         continue;
501                 }
502                 /* let the caller handle this line */
503                 if (i<level || **buf=='\0')
504                         return 1;
505                 /* good. this is one line for us.
506                  * it can be: a value or a keyname. Parse the name first
507                  */
508                 s=_read_USTRING(s,&name);
509
510                 /* switch() default: hack to avoid gotos */
511                 switch (0) {
512                 default:
513                         if (*s=='\0') {
514                                 /* this is a new key 
515                                  * look for the name in the already existing keys
516                                  * on this level.
517                                  */
518                                  lplpkey= &(lpkey->nextsub);
519                                  lpxkey = *lplpkey;
520                                  while (lpxkey) {
521                                         if (!strcmpW(lpxkey->keyname,name))
522                                                 break;
523                                         lplpkey = &(lpxkey->next);
524                                         lpxkey  = *lplpkey;
525                                  }
526                                  if (lpxkey==NULL) {
527                                         /* we have no key with that name yet. allocate
528                                          * it.
529                                          */
530                                         *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
531                                         lpxkey  = *lplpkey;
532                                         memset(lpxkey,'\0',sizeof(KEYSTRUCT));
533                                         lpxkey->keyname = name;
534                                  } else {
535                                         /* already got it. we just remember it in 
536                                          * 'lpxkey'
537                                          */
538                                         free(name);
539                                  }
540                         } else {
541                                 LPKEYVALUE      val=NULL;
542                                 LPBYTE          data;
543                                 int             len,lastmodified,type;
544
545                                 if (*s!='=') {
546                                         fprintf(stderr,"_do_load_subkey:unexpected character: %c\n",*s);
547                                         break;
548                                 }
549                                 /* good. this looks like a value to me */
550                                 s++;
551                                 for (i=0;i<lpkey->nrofvalues;i++) {
552                                         val=lpkey->values+i;
553                                         if (name==NULL) {
554                                                 if (val->name==NULL)
555                                                         break;
556                                         } else {
557                                                 if (    val->name!=NULL && 
558                                                         !strcmpW(val->name,name)
559                                                 )
560                                                         break;
561                                         }
562                                 }
563                                 if (i==lpkey->nrofvalues) {
564                                         lpkey->values = xrealloc(
565                                                 lpkey->values,
566                                                 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
567                                         );
568                                         val=lpkey->values+i;
569                                         memset(val,'\0',sizeof(KEYVALUE));
570                                         val->name = name;
571                                 } else {
572                                         /* value already exists, free name */
573                                         free(name);
574                                 }
575                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
576                                         fprintf(stderr,"_do_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
577                                         break;
578                                 }
579                                 /* skip the 2 , */
580                                 s=strchr(s,',');s++;
581                                 s=strchr(s,',');s++;
582                                 if ((1<<type) & UNICONVMASK) {
583                                         s=_read_USTRING(s,(LPWSTR*)&data);
584                                         if (data)
585                                                 len = strlenW((LPWSTR)data)*2+2;
586                                         else    
587                                                 len = 0;
588                                 } else {
589                                         len=strlen(s)/2;
590                                         data = (LPBYTE)xmalloc(len+1);
591                                         for (i=0;i<len;i++) {
592                                                 data[i]=0;
593                                                 if (*s>='0' && *s<='9')
594                                                         data[i]=(*s-'0')<<4;
595                                                 if (*s>='a' && *s<='f')
596                                                         data[i]=(*s-'a')<<4;
597                                                 if (*s>='A' && *s<='F')
598                                                         data[i]=(*s-'A')<<4;
599                                                 s++;
600                                                 if (*s>='0' && *s<='9')
601                                                         data[i]|=*s-'0';
602                                                 if (*s>='a' && *s<='f')
603                                                         data[i]|=*s-'a';
604                                                 if (*s>='A' && *s<='F')
605                                                         data[i]|=*s-'A';
606                                                 s++;
607                                         }
608                                 }
609                                 if (val->lastmodified<lastmodified) {
610                                         val->lastmodified=lastmodified;
611                                         val->type = type;
612                                         val->len  = len;
613                                         if (val->data) 
614                                                 free(val->data);
615                                         val->data = data;
616                                 } else {
617                                         free(data);
618                                 }
619                         }
620                 }
621                 /* read the next line */
622                 if (!_read_line(F,buf,buflen))
623                         return 1;
624         }
625         return 1;
626 }
627
628 static int
629 _do_loadsubreg(FILE *F,LPKEYSTRUCT lpkey) {
630         int     ver;
631         char    *buf;
632         int     buflen;
633
634         buf=xmalloc(10);buflen=10;
635         if (!_read_line(F,&buf,&buflen)) {
636                 free(buf);
637                 return 0;
638         }
639         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
640                 free(buf);
641                 return 0;
642         }
643         if (ver!=REGISTRY_SAVE_VERSION) {
644                 dprintf_reg(stddeb,__FILE__":_do_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
645                 free(buf);
646                 return 0;
647         }
648         if (!_read_line(F,&buf,&buflen)) {
649                 free(buf);
650                 return 0;
651         }
652         if (!_do_load_subkey(F,lpkey,0,&buf,&buflen)) {
653                 free(buf);
654                 /* FIXME: memory leak on failure to read registry ... 
655                  * But this won't happen very often.
656                  */
657                 lpkey->nextsub=NULL;
658                 return 0;
659         }
660         free(buf);
661         return 1;
662 }
663
664 static void
665 _LoadSubReg(LPKEYSTRUCT lpkey,char *fn) {
666         FILE    *F;
667
668         F=fopen(fn,"rb");
669         if (F==NULL) {
670                 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
671                         fn,strerror(errno)
672                 );
673                 return;
674         }
675         if (!_do_loadsubreg(F,lpkey)) {
676                 fclose(F);
677                 unlink(fn);
678                 return;
679         }
680         fclose(F);
681 }
682
683 void
684 SHELL_LoadRegistry() {
685         char    *fn;
686         struct  passwd  *pwd;
687
688         if (key_classes_root==NULL)
689                 SHELL_Init();
690         /* load the machine-wide defaults first */
691         _LoadSubReg(key_current_user,SAVE_CURRENT_USER_DEFAULT);
692         _LoadSubReg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT);
693
694         /* load the user saved registry. overwriting only newer entries */
695         pwd=getpwuid(getuid());
696         if (pwd!=NULL && pwd->pw_dir!=NULL) {
697                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
698                 strcpy(fn,pwd->pw_dir);
699                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
700                 _LoadSubReg(key_current_user,fn);
701                 free(fn);
702                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
703                 strcpy(fn,pwd->pw_dir);
704                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
705                 _LoadSubReg(key_local_machine,fn);
706                 free(fn);
707         } else {
708                 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
709         }
710         /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg 
711          *        (later, when a win32 registry editing tool becomes avail.)
712          */
713 }
714
715 /********************* API FUNCTIONS ***************************************/
716
717 /*
718  * Open Keys.
719  *
720  * All functions are stubs to RegOpenKeyExW where all the
721  * magic happens. 
722  *
723  * FIXME: security,options,desiredaccess,...
724  *
725  * Callpath:
726  * RegOpenKey -> RegOpenKeyA -> RegOpenKeyExA \
727  *                              RegOpenKeyW   -> RegOpenKeyExW 
728  */
729
730 /* RegOpenKeyExW                [ADVAPI32.150] */
731 WINAPI DWORD
732 RegOpenKeyExW(
733         HKEY    hkey,
734         LPCWSTR lpszSubKey,
735         DWORD   dwReserved,
736         REGSAM  samDesired,
737         LPHKEY  retkey
738 ) {
739         LPKEYSTRUCT     lpNextKey,lpxkey;
740         LPWSTR          *wps;
741         int             wpc,i;
742         dprintf_reg(stddeb,"RegOpenKeyExW(%lx,%s,%ld,%lx,%p)\n",
743                 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
744         );
745
746         lpNextKey       = lookup_hkey(hkey);
747         if (!lpNextKey)
748                 return SHELL_ERROR_BADKEY;
749         if (!lpszSubKey || !*lpszSubKey) {
750                 add_handle(++currenthandle,lpNextKey,samDesired);
751                 *retkey=currenthandle;
752                 return SHELL_ERROR_SUCCESS;
753         }
754         split_keypath(lpszSubKey,&wps,&wpc);
755         i       = 0;
756         while ((i<wpc) && (wps[i][0]=='\0')) i++;
757         lpxkey  = lpNextKey;
758         while (i<wpc) {
759                 lpxkey=lpNextKey->nextsub;
760                 while (lpxkey) {
761                         if (!strcmpW(wps[i],lpxkey->keyname))
762                                 break;
763                         lpxkey=lpxkey->next;
764                 }
765                 if (!lpxkey) {
766                         FREE_KEY_PATH;
767                         return SHELL_ERROR_BADKEY;
768                 }
769                 i++;
770                 lpNextKey       = lpxkey;
771         }
772         add_handle(++currenthandle,lpxkey,samDesired);
773         *retkey = currenthandle;
774         FREE_KEY_PATH;
775         return  SHELL_ERROR_SUCCESS;
776 }
777
778 /* RegOpenKeyW                  [ADVAPI32.151] */
779 WINAPI DWORD
780 RegOpenKeyW(
781         HKEY    hkey,
782         LPCWSTR lpszSubKey,
783         LPHKEY  retkey
784 ) {
785         dprintf_reg(stddeb,"RegOpenKeyW(%lx,%s,%p)\n",
786                 (LONG)hkey,W2C(lpszSubKey,0),retkey
787         );
788         return RegOpenKeyExW(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
789 }
790
791
792 /* RegOpenKeyExA                [ADVAPI32.149] */
793 WINAPI DWORD
794 RegOpenKeyExA(
795         HKEY    hkey,
796         LPCSTR  lpszSubKey,
797         DWORD   dwReserved,
798         REGSAM  samDesired,
799         LPHKEY  retkey
800 ) {
801         LPWSTR  lpszSubKeyW;
802         DWORD   ret;
803
804         dprintf_reg(stddeb,"RegOpenKeyExA(%lx,%s,%ld,%lx,%p)\n",
805                 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
806         );
807         if (lpszSubKey)
808                 lpszSubKeyW=strdupA2W(lpszSubKey);
809         else
810                 lpszSubKeyW=NULL;
811         ret=RegOpenKeyExW(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
812         if (lpszSubKeyW)
813                 free(lpszSubKeyW);
814         return ret;
815 }
816
817 /* RegOpenKeyA                  [ADVAPI32.148] */
818 WINAPI DWORD
819 RegOpenKeyA(
820         HKEY    hkey,
821         LPCSTR  lpszSubKey,
822         LPHKEY  retkey
823 ) {
824         dprintf_reg(stddeb,"RegOpenKeyA(%lx,%s,%p)\n",
825                 (LONG)hkey,lpszSubKey,retkey
826         );
827         return  RegOpenKeyExA(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
828 }
829
830 /* RegOpenKey                   [SHELL.1] [KERNEL.217] */
831 WINAPI DWORD
832 RegOpenKey(
833         HKEY    hkey,
834         LPCSTR  lpszSubKey,
835         LPHKEY  retkey
836 ) {
837         dprintf_reg(stddeb,"RegOpenKey(%lx,%s,%p)\n",
838                 (LONG)hkey,lpszSubKey,retkey
839         );
840         return RegOpenKeyA(hkey,lpszSubKey,retkey);
841 }
842
843 /* 
844  * Create keys
845  * 
846  * All those functions convert their respective 
847  * arguments and call RegCreateKeyExW at the end.
848  *
849  * FIXME: no security,no access attrib,no optionhandling yet.
850  *
851  * Callpath:
852  * RegCreateKey -> RegCreateKeyA -> RegCreateKeyExA \
853  *                                  RegCreateKeyW   -> RegCreateKeyExW
854  */
855
856 /* RegCreateKeyExW              [ADVAPI32.131] */
857 WINAPI DWORD
858 RegCreateKeyExW(
859         HKEY    hkey,
860         LPCWSTR lpszSubKey,
861         DWORD   dwReserved,
862         LPWSTR  lpszClass,
863         DWORD   fdwOptions,
864         REGSAM  samDesired,
865         LPSECURITY_ATTRIBUTES lpSecAttribs,
866         LPHKEY  retkey,
867         LPDWORD lpDispos
868 ) {
869         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
870         LPWSTR          *wps;
871         int             wpc,i;
872
873 /*FIXME: handle security/access/whatever */
874         dprintf_reg(stddeb,"RegCreateKeyExW(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
875                 (LONG)hkey,
876                 W2C(lpszSubKey,0),
877                 dwReserved,
878                 W2C(lpszClass,1),
879                 fdwOptions,
880                 samDesired,
881                 lpSecAttribs,
882                 retkey,
883                 lpDispos
884         );
885
886         lpNextKey       = lookup_hkey(hkey);
887         if (!lpNextKey)
888                 return SHELL_ERROR_BADKEY;
889         if (!lpszSubKey || !*lpszSubKey) {
890                 add_handle(++currenthandle,lpNextKey,samDesired);
891                 *retkey=currenthandle;
892                 return SHELL_ERROR_SUCCESS;
893         }
894         split_keypath(lpszSubKey,&wps,&wpc);
895         i       = 0;
896         while ((i<wpc) && (wps[i][0]=='\0')) i++;
897         lpxkey  = lpNextKey;
898         while (i<wpc) {
899                 lpxkey=lpNextKey->nextsub;
900                 while (lpxkey) {
901                         if (!strcmpW(wps[i],lpxkey->keyname))
902                                 break;
903                         lpxkey=lpxkey->next;
904                 }
905                 if (!lpxkey)
906                         break;
907                 i++;
908                 lpNextKey       = lpxkey;
909         }
910         if (lpxkey) {
911                 add_handle(++currenthandle,lpxkey,samDesired);
912                 *retkey         = currenthandle;
913                 *lpDispos       = REG_OPENED_EXISTING_KEY;
914                 FREE_KEY_PATH;
915                 return  SHELL_ERROR_SUCCESS;
916         }
917         /* good. now the hard part */
918         while (i<wpc) {
919                 lplpPrevKey     = &(lpNextKey->nextsub);
920                 lpxkey          = *lplpPrevKey;
921                 while (lpxkey) {
922                         lplpPrevKey     = &(lpxkey->next);
923                         lpxkey          = *lplpPrevKey;
924                 }
925                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
926                 if (!*lplpPrevKey) {
927                         FREE_KEY_PATH;
928                         return SHELL_ERROR_OUTOFMEMORY;
929                 }
930                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
931                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
932                 (*lplpPrevKey)->next    = NULL;
933                 (*lplpPrevKey)->nextsub = NULL;
934                 (*lplpPrevKey)->values  = NULL;
935                 (*lplpPrevKey)->nrofvalues = 0;
936                 if (lpszClass)
937                         (*lplpPrevKey)->class = strdupW(lpszClass);
938                 else
939                         (*lplpPrevKey)->class = NULL;
940                 lpNextKey       = *lplpPrevKey;
941                 i++;
942         }
943         add_handle(++currenthandle,lpNextKey,samDesired);
944
945         /*FIXME: flag handling correct? */
946         lpNextKey->flags= fdwOptions;
947         if (lpszClass)
948                 lpNextKey->class = strdupW(lpszClass);
949         else
950                 lpNextKey->class = NULL;
951         *retkey         = currenthandle;
952         *lpDispos       = REG_CREATED_NEW_KEY;
953         FREE_KEY_PATH;
954         return SHELL_ERROR_SUCCESS;
955 }
956
957 /* RegCreateKeyW                [ADVAPI32.132] */
958 WINAPI DWORD
959 RegCreateKeyW(
960         HKEY    hkey,
961         LPCWSTR lpszSubKey,
962         LPHKEY  retkey
963 ) {
964         DWORD   junk,ret;
965
966         dprintf_reg(stddeb,"RegCreateKeyW(%lx,%s,%p)\n",
967                 (LONG)hkey,W2C(lpszSubKey,0),retkey
968         );
969         ret=RegCreateKeyExW(
970                 hkey,           /* key handle */
971                 lpszSubKey,     /* subkey name */
972                 0,              /* reserved = 0 */
973                 NULL,           /* lpszClass? FIXME: ? */
974                 REG_OPTION_NON_VOLATILE,        /* options */
975                 KEY_ALL_ACCESS, /* desired access attribs */
976                 NULL,           /* lpsecurity attributes */
977                 retkey,         /* lpretkey */
978                 &junk           /* disposition value */
979         );
980         return  ret;
981 }
982
983 /* RegCreateKeyExA              [ADVAPI32.130] */
984 WINAPI DWORD
985 RegCreateKeyExA(
986         HKEY    hkey,
987         LPCSTR  lpszSubKey,
988         DWORD   dwReserved,
989         LPSTR   lpszClass,
990         DWORD   fdwOptions,
991         REGSAM  samDesired,
992         LPSECURITY_ATTRIBUTES lpSecAttribs,
993         LPHKEY  retkey,
994         LPDWORD lpDispos
995 ) {
996         LPWSTR  lpszSubKeyW,lpszClassW;
997         DWORD   ret;
998
999         dprintf_reg(stddeb,"RegCreateKeyExA(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1000                 (LONG)hkey,
1001                 lpszSubKey,
1002                 dwReserved,
1003                 lpszClass,
1004                 fdwOptions,
1005                 samDesired,
1006                 lpSecAttribs,
1007                 retkey,
1008                 lpDispos
1009         );
1010         if (lpszSubKey)
1011                 lpszSubKeyW=strdupA2W(lpszSubKey);
1012         else
1013                 lpszSubKeyW=NULL;
1014         if (lpszClass)
1015                 lpszClassW=strdupA2W(lpszClass);
1016         else
1017                 lpszClassW=NULL;
1018         ret=RegCreateKeyExW(
1019                 hkey,
1020                 lpszSubKeyW,
1021                 dwReserved,
1022                 lpszClassW,
1023                 fdwOptions,
1024                 samDesired,
1025                 lpSecAttribs,
1026                 retkey,
1027                 lpDispos
1028         );
1029         if (lpszSubKeyW)
1030                 free(lpszSubKeyW);
1031         if (lpszClassW)
1032                 free(lpszClassW);
1033         return ret;
1034 }
1035
1036 /* RegCreateKeyA                [ADVAPI32.129] */
1037 WINAPI DWORD
1038 RegCreateKeyA(
1039         HKEY    hkey,
1040         LPCSTR  lpszSubKey,
1041         LPHKEY  retkey
1042 ) {
1043         DWORD   junk;
1044
1045         dprintf_reg(stddeb,"RegCreateKeyA(%lx,%s,%p)\n",
1046                 (LONG)hkey,lpszSubKey,retkey
1047         );
1048         return  RegCreateKeyExA(
1049                 hkey,           /* key handle */
1050                 lpszSubKey,     /* subkey name */
1051                 0,              /* reserved = 0 */
1052                 NULL,           /* lpszClass? FIXME: ? */
1053                 REG_OPTION_NON_VOLATILE,/* options */
1054                 KEY_ALL_ACCESS, /* desired access attribs */
1055                 NULL,           /* lpsecurity attributes */
1056                 retkey,         /* lpretkey */
1057                 &junk           /* disposition value */
1058         );
1059 }
1060
1061 /* RegCreateKey                 [SHELL.2] [KERNEL.218] */
1062 WINAPI DWORD
1063 RegCreateKey(
1064         HKEY    hkey,
1065         LPCSTR  lpszSubKey,
1066         LPHKEY  retkey
1067 ) {
1068         dprintf_reg(stddeb,"RegCreateKey(%lx,%s,%p)\n",
1069                 (LONG)hkey,lpszSubKey,retkey
1070         );
1071         return RegCreateKeyA(hkey,lpszSubKey,retkey);
1072 }
1073
1074 /* 
1075  * Query Value Functions
1076  * Win32 differs between keynames and valuenames. 
1077  * multiple values may belong to one key, the special value
1078  * with name NULL is the default value used by the win31
1079  * compat functions.
1080  *
1081  * Callpath:
1082  * RegQueryValue -> RegQueryValueA -> RegQueryValueExA \
1083  *                                    RegQueryValueW   -> RegQueryValueExW
1084  */
1085
1086 /* RegQueryValueExW             [ADVAPI32.158] */
1087 WINAPI DWORD
1088 RegQueryValueExW(
1089         HKEY    hkey,
1090         LPWSTR  lpszValueName,
1091         LPDWORD lpdwReserved,
1092         LPDWORD lpdwType,
1093         LPBYTE  lpbData,
1094         LPDWORD lpcbData
1095 ) {
1096         LPKEYSTRUCT     lpkey;
1097         int             i;
1098
1099         dprintf_reg(stddeb,"RegQueryValueExW(%lx,%s,%p,%p,%p,%p)\n",
1100                 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,lpcbData
1101         );
1102
1103         lpkey   = lookup_hkey(hkey);
1104         if (!lpkey)
1105                 return SHELL_ERROR_BADKEY;
1106         if (lpszValueName==NULL) {
1107                 for (i=0;i<lpkey->nrofvalues;i++)
1108                         if (lpkey->values[i].name==NULL)
1109                                 break;
1110         } else {
1111                 for (i=0;i<lpkey->nrofvalues;i++)
1112                         if (!strcmpW(lpszValueName,lpkey->values[i].name))
1113                                 break;
1114         }
1115         if (i==lpkey->nrofvalues) {
1116                 if (lpszValueName==NULL) {
1117                         *(WCHAR*)lpbData = 0;
1118                         *lpcbData       = 2;
1119                         *lpdwType       = REG_SZ;
1120                         return SHELL_ERROR_SUCCESS;
1121                 }
1122                 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1123         }
1124         if (lpdwType)
1125                 *lpdwType       = lpkey->values[i].type;
1126         if (lpbData==NULL) {
1127                 if (lpcbData==NULL)
1128                         return SHELL_ERROR_SUCCESS;
1129                 *lpcbData       = lpkey->values[i].len;
1130                 return SHELL_ERROR_SUCCESS;
1131         }
1132         if (*lpcbData<lpkey->values[i].len) {
1133                 *(WCHAR*)lpbData
1134                         = 0;
1135                 *lpcbData       = lpkey->values[i].len;
1136                 return ERROR_MORE_DATA;
1137         }
1138         memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1139         *lpcbData       = lpkey->values[i].len;
1140         return SHELL_ERROR_SUCCESS;
1141 }
1142
1143 /* RegQueryValueW               [ADVAPI32.159] */
1144 WINAPI DWORD
1145 RegQueryValueW(
1146         HKEY    hkey,
1147         LPWSTR  lpszSubKey,
1148         LPWSTR  lpszData,
1149         LPDWORD lpcbData
1150 ) {
1151         HKEY    xhkey;
1152         DWORD   ret,lpdwType;
1153
1154         dprintf_reg(stddeb,"RegQueryValueW(%lx,%s,%p,%p)\n->",
1155                 hkey,W2C(lpszSubKey,0),lpszData,lpcbData
1156         );
1157
1158         /* only open subkey, if we really do descend */
1159         if (lpszSubKey && *lpszSubKey) {
1160                 ret     = RegOpenKeyW(hkey,lpszSubKey,&xhkey);
1161                 if (ret!=ERROR_SUCCESS)
1162                         return ret;
1163         } else
1164                 xhkey   = hkey;
1165
1166         lpdwType        = REG_SZ;
1167         ret     = RegQueryValueExW(
1168                 xhkey,
1169                 NULL,           /* varname NULL -> compat */
1170                 NULL,           /* lpdwReserved, must be NULL */
1171                 &lpdwType,
1172                 (LPBYTE)lpszData,
1173                 lpcbData
1174         );
1175         if (xhkey!=hkey)
1176                 RegCloseKey(xhkey);
1177         return ret;
1178 }
1179
1180 /* RegQueryValueExA             [ADVAPI32.157] */
1181 WINAPI DWORD
1182 RegQueryValueExA(
1183         HKEY    hkey,
1184         LPSTR   lpszValueName,
1185         LPDWORD lpdwReserved,
1186         LPDWORD lpdwType,
1187         LPBYTE  lpbData,
1188         LPDWORD lpcbData
1189 ) {
1190         LPWSTR  lpszValueNameW;
1191         LPBYTE  buf;
1192         DWORD   ret,myxlen;
1193         DWORD   *mylen;
1194
1195         dprintf_reg(stddeb,"RegQueryValueExA(%lx,%s,%p,%p,%p,%p)\n->",
1196                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData
1197         );
1198         if (lpbData) {
1199                 /* double buffer */
1200                 buf     = (LPBYTE)xmalloc((*lpcbData)*2);
1201                 myxlen  = *lpcbData*2;
1202                 mylen   = &myxlen;
1203         } else {
1204                 buf=NULL;
1205                 if (lpcbData) {
1206                         myxlen  = *lpcbData*2;
1207                         mylen   = &myxlen;
1208                 }
1209                         mylen   = NULL;
1210         }
1211         if (lpszValueName)
1212                 lpszValueNameW=strdupA2W(lpszValueName);
1213         else 
1214                 lpszValueNameW=NULL;
1215
1216         ret=RegQueryValueExW(
1217                 hkey,
1218                 lpszValueNameW,
1219                 lpdwReserved,
1220                 lpdwType,
1221                 buf,
1222                 mylen
1223         );
1224
1225         if (ret==ERROR_SUCCESS) {
1226                 if (buf) {
1227                         if (UNICONVMASK & (1<<(*lpdwType))) {
1228                                 /* convert UNICODE to ASCII */
1229                                 strcpyWA(lpbData,(LPWSTR)buf);
1230                                 *lpcbData       = myxlen/2;
1231                         } else {
1232                                 if (myxlen>*lpcbData)
1233                                         ret     = ERROR_MORE_DATA;
1234                                 else
1235                                         memcpy(lpbData,buf,myxlen);
1236
1237                                 *lpcbData       = myxlen;
1238                         }
1239                 } else {
1240                         if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData)
1241                                 *lpcbData       = myxlen/2;
1242                 }
1243         } else {
1244                 if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData)
1245                         *lpcbData       = myxlen/2;
1246         }
1247         if (buf)
1248                 free(buf);
1249         return ret;
1250 }
1251
1252 /* RegQueryValueEx              [KERNEL.225] */
1253 WINAPI DWORD
1254 RegQueryValueEx(
1255         HKEY    hkey,
1256         LPSTR   lpszValueName,
1257         LPDWORD lpdwReserved,
1258         LPDWORD lpdwType,
1259         LPBYTE  lpbData,
1260         LPDWORD lpcbData
1261 ) {
1262         dprintf_reg(stddeb,"RegQueryValueEx(%lx,%s,%p,%p,%p,%p)\n",
1263                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData
1264         );
1265         return RegQueryValueExA(        
1266                 hkey,
1267                 lpszValueName,
1268                 lpdwReserved,
1269                 lpdwType,
1270                 lpbData,
1271                 lpcbData
1272         );
1273 }
1274
1275 /* RegQueryValueA               [ADVAPI32.156] */
1276 WINAPI DWORD
1277 RegQueryValueA(
1278         HKEY    hkey,
1279         LPSTR   lpszSubKey,
1280         LPSTR   lpszData,
1281         LPDWORD lpcbData
1282 ) {
1283         HKEY    xhkey;
1284         DWORD   ret,lpdwType;
1285
1286         dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n",
1287                 hkey,lpszSubKey,lpszData,lpcbData
1288         );
1289
1290         /* only open subkey, if we really do descend */
1291         if (lpszSubKey && *lpszSubKey) {
1292                 ret     = RegOpenKey(hkey,lpszSubKey,&xhkey);
1293                 if (ret!=ERROR_SUCCESS)
1294                         return ret;
1295         } else
1296                 xhkey   = hkey;
1297
1298         lpdwType        = REG_SZ;
1299         ret     = RegQueryValueExA(
1300                 xhkey,
1301                 NULL,           /* lpszValueName NULL -> compat */
1302                 NULL,           /* lpdwReserved, must be NULL */
1303                 &lpdwType,
1304                 (LPBYTE)lpszData,
1305                 lpcbData
1306         );
1307         if (xhkey!=hkey)
1308                 RegCloseKey(xhkey);
1309         return ret;
1310 }
1311
1312 /* RegQueryValue                [SHELL.6] [KERNEL.224] */
1313 WINAPI DWORD
1314 RegQueryValue(
1315         HKEY    hkey,
1316         LPSTR   lpszSubKey,
1317         LPSTR   lpszData,
1318         LPDWORD lpcbData
1319 ) {
1320         dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n",
1321                 hkey,lpszSubKey,lpszData,lpcbData
1322         );
1323         return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
1324 }
1325
1326 /*
1327  * Setting values of Registry keys
1328  *
1329  * Callpath:
1330  * RegSetValue -> RegSetValueA -> RegSetValueExA \
1331  *                                RegSetValueW   -> RegSetValueExW
1332  */
1333
1334 /* RegSetValueExW               [ADVAPI32.170] */
1335 WINAPI DWORD
1336 RegSetValueExW(
1337         HKEY    hkey,
1338         LPWSTR  lpszValueName,
1339         DWORD   dwReserved,
1340         DWORD   dwType,
1341         LPBYTE  lpbData,
1342         DWORD   cbData
1343 ) {
1344         LPKEYSTRUCT     lpkey;
1345         int             i;
1346
1347         dprintf_reg(stddeb,"RegSetValueExW(%lx,%s,%ld,%ld,%p,%ld)\n",
1348                 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
1349         );
1350         /* we no longer care about the lpbData dwType here... */
1351         lpkey   = lookup_hkey(hkey);
1352         if (!lpkey)
1353                 return SHELL_ERROR_BADKEY;
1354         if (lpszValueName==NULL) {
1355                 for (i=0;i<lpkey->nrofvalues;i++)
1356                         if (lpkey->values[i].name==NULL)
1357                                 break;
1358         } else {
1359                 for (i=0;i<lpkey->nrofvalues;i++)
1360                         if (!strcmpW(lpszValueName,lpkey->values[i].name))
1361                                 break;
1362         }
1363         if (i==lpkey->nrofvalues) {
1364                 lpkey->values = (LPKEYVALUE)xrealloc(
1365                                         lpkey->values,
1366                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
1367                                 );
1368                 lpkey->nrofvalues++;
1369                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
1370         }
1371         if (lpkey->values[i].name==NULL)
1372                 if (lpszValueName)
1373                         lpkey->values[i].name = strdupW(lpszValueName);
1374                 else
1375                         lpkey->values[i].name = NULL;
1376         lpkey->values[i].len    = cbData;
1377         lpkey->values[i].type   = dwType;
1378         if (lpkey->values[i].data !=NULL)
1379                 free(lpkey->values[i].data);
1380         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
1381         lpkey->values[i].lastmodified = time(NULL);
1382         memcpy(lpkey->values[i].data,lpbData,cbData);
1383         return SHELL_ERROR_SUCCESS;
1384 }
1385
1386 /* RegSetValueExA               [ADVAPI32.169] */
1387 WINAPI DWORD
1388 RegSetValueExA(
1389         HKEY    hkey,
1390         LPSTR   lpszValueName,
1391         DWORD   dwReserved,
1392         DWORD   dwType,
1393         LPBYTE  lpbData,
1394         DWORD   cbData
1395 ) {
1396         LPBYTE  buf;
1397         LPWSTR  lpszValueNameW;
1398         DWORD   ret;
1399
1400         dprintf_reg(stddeb,"RegSetValueExA(%lx,%s,%ld,%ld,%p,%ld)\n->",
1401                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
1402         );
1403         if ((1<<dwType) & UNICONVMASK) {
1404                 buf=(LPBYTE)strdupA2W(lpbData);
1405                 cbData=2*strlen(lpbData)+2;
1406         } else
1407                 buf=lpbData;
1408         if (lpszValueName)
1409                 lpszValueNameW = strdupA2W(lpszValueName);
1410         else
1411                 lpszValueNameW = NULL;
1412         ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
1413         if (lpszValueNameW)
1414                 free(lpszValueNameW);
1415         if (buf!=lpbData)
1416                 free(buf);
1417         return ret;
1418 }
1419
1420 /* RegSetValueEx                [KERNEL.226] */
1421 WINAPI DWORD
1422 RegSetValueEx(
1423         HKEY    hkey,
1424         LPSTR   lpszValueName,
1425         DWORD   dwReserved,
1426         DWORD   dwType,
1427         LPBYTE  lpbData,
1428         DWORD   cbData
1429 ) {
1430         dprintf_reg(stddeb,"RegSetValueEx(%lx,%s,%ld,%ld,%p,%ld)\n->",
1431                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
1432         );
1433         return RegSetValueExA(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
1434 }
1435
1436 /* RegSetValueW                 [ADVAPI32.171] */
1437 WINAPI DWORD
1438 RegSetValueW(
1439         HKEY    hkey,
1440         LPCWSTR lpszSubKey,
1441         DWORD   dwType,
1442         LPCWSTR lpszData,
1443         DWORD   cbData
1444 ) {
1445         HKEY    xhkey;
1446         DWORD   ret;
1447
1448         dprintf_reg(stddeb,"RegSetValueW(%lx,%s,%ld,%s,%ld)\n->",
1449                 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
1450         );
1451         if (lpszSubKey && *lpszSubKey) {
1452                 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
1453                 if (ret!=ERROR_SUCCESS)
1454                         return ret;
1455         } else
1456                 xhkey=hkey;
1457         if (dwType!=REG_SZ) {
1458                 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
1459                 dwType=REG_SZ;
1460         }
1461         if (cbData!=2*strlenW(lpszData)+2) {
1462                 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
1463                         cbData,W2C(lpszData,0),2*strlenW(lpszData)+2
1464                 );
1465                 cbData=2*strlenW(lpszData)+2;
1466         }
1467         ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
1468         if (hkey!=xhkey)
1469                 RegCloseKey(xhkey);
1470         return ret;
1471
1472 }
1473 /* RegSetValueA                 [ADVAPI32.168] */
1474 WINAPI DWORD
1475 RegSetValueA(
1476         HKEY    hkey,
1477         LPCSTR  lpszSubKey,
1478         DWORD   dwType,
1479         LPCSTR  lpszData,
1480         DWORD   cbData
1481 ) {
1482         DWORD   ret;
1483         HKEY    xhkey;
1484
1485         dprintf_reg(stddeb,"RegSetValueA(%lx,%s,%ld,%s,%ld)\n->",
1486                 hkey,lpszSubKey,dwType,lpszData,cbData
1487         );
1488         if (lpszSubKey && *lpszSubKey) {
1489                 ret=RegCreateKey(hkey,lpszSubKey,&xhkey);
1490                 if (ret!=ERROR_SUCCESS)
1491                         return ret;
1492         } else
1493                 xhkey=hkey;
1494
1495         if (dwType!=REG_SZ) {
1496                 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
1497                 dwType=REG_SZ;
1498         }
1499         if (cbData!=strlen(lpszData)+1)
1500                 cbData=strlen(lpszData)+1;
1501         ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
1502         if (xhkey!=hkey)
1503                 RegCloseKey(xhkey);
1504         return ret;
1505 }
1506
1507 /* RegSetValue                  [KERNEL.221] [SHELL.5] */
1508 WINAPI DWORD
1509 RegSetValue(
1510         HKEY    hkey,
1511         LPCSTR  lpszSubKey,
1512         DWORD   dwType,
1513         LPCSTR  lpszData,
1514         DWORD   cbData
1515 ) {
1516         DWORD   ret;
1517         dprintf_reg(stddeb,"RegSetValue(%lx,%s,%ld,%s,%ld)\n->",
1518                 hkey,lpszSubKey,dwType,lpszData,cbData
1519         );
1520         ret=RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
1521         return ret;
1522 }
1523
1524 /* 
1525  * Key Enumeration
1526  *
1527  * Callpath:
1528  * RegEnumKey -> RegEnumKeyA -> RegEnumKeyExA \
1529  *                              RegEnumKeyW   -> RegEnumKeyExW
1530  */
1531
1532 /* RegEnumKeyExW                [ADVAPI32.139] */
1533 WINAPI DWORD
1534 RegEnumKeyExW(
1535         HKEY    hkey,
1536         DWORD   iSubkey,
1537         LPWSTR  lpszName,
1538         LPDWORD lpcchName,
1539         LPDWORD lpdwReserved,
1540         LPWSTR  lpszClass,
1541         LPDWORD lpcchClass,
1542         FILETIME        *ft
1543 ) {
1544         LPKEYSTRUCT     lpkey,lpxkey;
1545
1546         dprintf_reg(stddeb,"RegEnumKeyExW(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n",
1547                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
1548         );
1549         lpkey=lookup_hkey(hkey);
1550         if (!lpkey)
1551                 return SHELL_ERROR_BADKEY;
1552         if (!lpkey->nextsub)
1553                 return ERROR_NO_MORE_ITEMS;
1554         lpxkey=lpkey->nextsub;
1555         while (iSubkey && lpxkey) {
1556                 iSubkey--;
1557                 lpxkey=lpxkey->next;
1558         }
1559         if (iSubkey || !lpxkey)
1560                 return ERROR_NO_MORE_ITEMS;
1561         if (2*strlenW(lpxkey->keyname)+2>*lpcchName)
1562                 return ERROR_MORE_DATA;
1563         memcpy(lpszName,lpxkey->keyname,strlenW(lpxkey->keyname)*2+2);
1564         if (lpszClass) {
1565                 /* what should we write into it? */
1566                 *lpszClass              = 0;
1567                 *lpcchClass     = 2;
1568         }
1569         return ERROR_SUCCESS;
1570
1571 }
1572
1573 /* RegEnumKeyW                  [ADVAPI32.140] */
1574 WINAPI DWORD
1575 RegEnumKeyW(
1576         HKEY    hkey,
1577         DWORD   iSubkey,
1578         LPWSTR  lpszName,
1579         DWORD   lpcchName
1580 ) {
1581         FILETIME        ft;
1582
1583         dprintf_reg(stddeb,"RegEnumKeyW(%lx,%ld,%p,%ld)\n->",
1584                 hkey,iSubkey,lpszName,lpcchName
1585         );
1586         return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
1587 }
1588 /* RegEnumKeyExA                [ADVAPI32.138] */
1589 WINAPI DWORD
1590 RegEnumKeyExA(
1591         HKEY    hkey,
1592         DWORD   iSubkey,
1593         LPSTR   lpszName,
1594         LPDWORD lpcchName,
1595         LPDWORD lpdwReserved,
1596         LPSTR   lpszClass,
1597         LPDWORD lpcchClass,
1598         FILETIME        *ft
1599 ) {
1600         DWORD   ret,lpcchNameW,lpcchClassW;
1601         LPWSTR  lpszNameW,lpszClassW;
1602
1603
1604         dprintf_reg(stddeb,"RegEnumKeyExA(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n->",
1605                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
1606         );
1607         if (lpszName) {
1608                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
1609                 lpcchNameW      = *lpcchName*2;
1610         } else {
1611                 lpszNameW       = NULL;
1612                 lpcchNameW      = 0;
1613         }
1614         if (lpszClass) {
1615                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
1616                 lpcchClassW     = *lpcchClass*2;
1617         } else {
1618                 lpszClassW      =0;
1619                 lpcchClassW=0;
1620         }
1621         ret=RegEnumKeyExW(
1622                 hkey,
1623                 iSubkey,
1624                 lpszNameW,
1625                 &lpcchNameW,
1626                 lpdwReserved,
1627                 lpszClassW,
1628                 &lpcchClassW,
1629                 ft
1630         );
1631         if (ret==ERROR_SUCCESS) {
1632                 strcpyWA(lpszName,lpszNameW);
1633                 *lpcchName=strlen(lpszName);
1634                 if (lpszClassW) {
1635                         strcpyWA(lpszClass,lpszClassW);
1636                         *lpcchClass=strlen(lpszClass);
1637                 }
1638         }
1639         if (lpszNameW)
1640                 free(lpszNameW);
1641         if (lpszClassW)
1642                 free(lpszClassW);
1643         return ret;
1644 }
1645
1646 /* RegEnumKeyA                  [ADVAPI32.137] */
1647 WINAPI DWORD
1648 RegEnumKeyA(
1649         HKEY    hkey,
1650         DWORD   iSubkey,
1651         LPSTR   lpszName,
1652         DWORD   lpcchName
1653 ) {
1654         FILETIME        ft;
1655
1656         dprintf_reg(stddeb,"RegEnumKeyA(%lx,%ld,%p,%ld)\n->",
1657                 hkey,iSubkey,lpszName,lpcchName
1658         );
1659         return  RegEnumKeyExA(
1660                 hkey,
1661                 iSubkey,
1662                 lpszName,
1663                 &lpcchName,
1664                 NULL,
1665                 NULL,
1666                 NULL,
1667                 &ft
1668         );
1669 }
1670
1671 /* RegEnumKey                   [SHELL.7] [KERNEL.216] */
1672 WINAPI DWORD
1673 RegEnumKey(
1674         HKEY    hkey,
1675         DWORD   iSubkey,
1676         LPSTR   lpszName,
1677         DWORD   lpcchName
1678 ) {
1679         dprintf_reg(stddeb,"RegEnumKey(%lx,%ld,%p,%ld)\n->",
1680                 hkey,iSubkey,lpszName,lpcchName
1681         );
1682         return RegEnumKeyA(hkey,iSubkey,lpszName,lpcchName);
1683 }
1684
1685 /* 
1686  * Enumerate Registry Values
1687  *
1688  * Callpath:
1689  * RegEnumValue -> RegEnumValueA -> RegEnumValueW
1690  */
1691
1692 /* RegEnumValueW                [ADVAPI32.142] */
1693 WINAPI DWORD
1694 RegEnumValueW(
1695         HKEY    hkey,
1696         DWORD   iValue,
1697         LPWSTR  lpszValue,
1698         LPDWORD lpcchValue,
1699         LPDWORD lpdReserved,
1700         LPDWORD lpdwType,
1701         LPBYTE  lpbData,
1702         LPDWORD lpcbData
1703 ) {
1704         LPKEYSTRUCT     lpkey;
1705         LPKEYVALUE      val;
1706
1707         dprintf_reg(stddeb,"RegEnumValueW(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1708                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1709         );
1710         lpkey = lookup_hkey(hkey);
1711         if (!lpkey)
1712                 return SHELL_ERROR_BADKEY;
1713         if (lpkey->nrofvalues<=iValue)
1714                 return ERROR_NO_MORE_ITEMS;
1715         val     = lpkey->values+iValue;
1716
1717         if (val->name) {
1718                 if (strlenW(val->name)*2+2>*lpcchValue) {
1719                         *lpcchValue = strlenW(val->name)*2+2;
1720                         return ERROR_MORE_DATA;
1721                 }
1722                 memcpy(lpszValue,val->name,2*strlenW(val->name)+2);
1723                 *lpcchValue=strlenW(val->name)*2+2;
1724         } else {
1725                 /* how to handle NULL value? */
1726                 *lpszValue      = 0;
1727                 *lpcchValue     = 2;
1728         }
1729         *lpdwType=val->type;
1730         if (lpbData) {
1731                 if (val->len>*lpcbData)
1732                         return ERROR_MORE_DATA;
1733                 memcpy(lpbData,val->data,val->len);
1734                 *lpcbData = val->len;
1735         }
1736         return SHELL_ERROR_SUCCESS;
1737 }
1738
1739 /* RegEnumValueA                [ADVAPI32.141] */
1740 WINAPI DWORD
1741 RegEnumValueA(
1742         HKEY    hkey,
1743         DWORD   iValue,
1744         LPSTR   lpszValue,
1745         LPDWORD lpcchValue,
1746         LPDWORD lpdReserved,
1747         LPDWORD lpdwType,
1748         LPBYTE  lpbData,
1749         LPDWORD lpcbData
1750 ) {
1751         LPWSTR  lpszValueW;
1752         LPBYTE  lpbDataW;
1753         DWORD   ret,lpcbDataW;
1754
1755         dprintf_reg(stddeb,"RegEnumValueA(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1756                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1757         );
1758
1759         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
1760         if (lpbData) {
1761                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
1762                 lpcbDataW = *lpcbData*2;
1763         } else
1764                 lpbDataW = NULL;
1765         ret=RegEnumValueW(
1766                 hkey,
1767                 iValue,
1768                 lpszValueW,
1769                 lpcchValue,
1770                 lpdReserved,
1771                 lpdwType,
1772                 lpbDataW,
1773                 &lpcbDataW
1774         );
1775
1776         if (ret==ERROR_SUCCESS) {
1777                 strcpyWA(lpszValue,lpszValueW);
1778                 if (lpbData) {
1779                         if ((1<<*lpdwType) & UNICONVMASK) {
1780                                 strcpyWA(lpbData,(LPWSTR)lpbDataW);
1781                         } else {
1782                                 if (lpcbDataW > *lpcbData)
1783                                         ret     = ERROR_MORE_DATA;
1784                                 else
1785                                         memcpy(lpbData,lpbDataW,lpcbDataW);
1786                         }
1787                         *lpcbData = lpcbDataW;
1788                 }
1789         }
1790         if (lpbDataW)
1791                 free(lpbDataW);
1792         if (lpszValueW)
1793                 free(lpszValueW);
1794         return ret;
1795 }
1796
1797 /* RegEnumValue                 [KERNEL.223] */
1798 WINAPI DWORD
1799 RegEnumValue(
1800         HKEY    hkey,
1801         DWORD   iValue,
1802         LPSTR   lpszValue,
1803         LPDWORD lpcchValue,
1804         LPDWORD lpdReserved,
1805         LPDWORD lpdwType,
1806         LPBYTE  lpbData,
1807         LPDWORD lpcbData
1808 ) {
1809         dprintf_reg(stddeb,"RegEnumValue(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1810                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1811         );
1812         return RegEnumValueA(
1813                 hkey,
1814                 iValue,
1815                 lpszValue,
1816                 lpcchValue,
1817                 lpdReserved,
1818                 lpdwType,
1819                 lpbData,
1820                 lpcbData
1821         );
1822 }
1823
1824 /* 
1825  *  Close registry key
1826  */
1827 /* RegCloseKey                  [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
1828 WINAPI DWORD
1829 RegCloseKey(HKEY hkey) {
1830         dprintf_reg(stddeb,"RegCloseKey(%ld)\n",hkey);
1831         remove_handle(hkey);
1832         return ERROR_SUCCESS;
1833 }
1834 /* 
1835  * Delete registry key
1836  *
1837  * Callpath:
1838  * RegDeleteKey -> RegDeleteKeyA -> RegDeleteKeyW
1839  */
1840 /* RegDeleteKeyW                [ADVAPI32.134] */
1841 WINAPI DWORD
1842 RegDeleteKeyW(HKEY hkey,LPWSTR lpszSubKey) {
1843         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1844         LPWSTR          *wps;
1845         int             wpc,i;
1846
1847         dprintf_reg(stddeb,"RegDeleteKeyW(%ld,%s)\n",
1848                 hkey,W2C(lpszSubKey,0)
1849         );
1850         lpNextKey       = lookup_hkey(hkey);
1851         if (!lpNextKey)
1852                 return SHELL_ERROR_BADKEY;
1853         /* we need to know the previous key in the hier. */
1854         if (!lpszSubKey || !*lpszSubKey)
1855                 return SHELL_ERROR_BADKEY;
1856         split_keypath(lpszSubKey,&wps,&wpc);
1857         i       = 0;
1858         lpxkey  = lpNextKey;
1859         while (i<wpc-1) {
1860                 lpxkey=lpNextKey->nextsub;
1861                 while (lpxkey) {
1862                         if (!strcmpW(wps[i],lpxkey->keyname))
1863                                 break;
1864                         lpxkey=lpxkey->next;
1865                 }
1866                 if (!lpxkey) {
1867                         FREE_KEY_PATH;
1868                         /* not found is success */
1869                         return SHELL_ERROR_SUCCESS;
1870                 }
1871                 i++;
1872                 lpNextKey       = lpxkey;
1873         }
1874         lpxkey  = lpNextKey->nextsub;
1875         lplpPrevKey = &(lpNextKey->nextsub);
1876         while (lpxkey) {
1877                 if (!strcmpW(wps[i],lpxkey->keyname))
1878                         break;
1879                 lplpPrevKey     = &(lpxkey->next);
1880                 lpxkey          = lpxkey->next;
1881         }
1882         if (!lpxkey)
1883                 return SHELL_ERROR_SUCCESS;
1884         if (lpxkey->nextsub)
1885                 return SHELL_ERROR_CANTWRITE;
1886         *lplpPrevKey    = lpxkey->next;
1887         free(lpxkey->keyname);
1888         if (lpxkey->class)
1889                 free(lpxkey->class);
1890         if (lpxkey->values)
1891                 free(lpxkey->values);
1892         free(lpxkey);
1893         FREE_KEY_PATH;
1894         return  SHELL_ERROR_SUCCESS;
1895 }
1896
1897 /* RegDeleteKeyA                [ADVAPI32.133] */
1898 WINAPI DWORD
1899 RegDeleteKeyA(HKEY hkey,LPCSTR lpszSubKey) {
1900         LPWSTR  lpszSubKeyW;
1901         DWORD   ret;
1902
1903         dprintf_reg(stddeb,"RegDeleteKeyA(%ld,%s)\n",
1904                 hkey,lpszSubKey
1905         );
1906         lpszSubKeyW=strdupA2W(lpszSubKey);
1907         ret=RegDeleteKeyW(hkey,lpszSubKeyW);
1908         free(lpszSubKeyW);
1909         return ret;
1910 }
1911
1912 /* RegDeleteKey                 [SHELL.4] [KERNEL.219] */
1913 WINAPI DWORD
1914 RegDeleteKey(HKEY hkey,LPCSTR lpszSubKey) {
1915         dprintf_reg(stddeb,"RegDeleteKey(%ld,%s)\n",
1916                 hkey,lpszSubKey
1917         );
1918         return RegDeleteKeyA(hkey,lpszSubKey);
1919 }
1920
1921 /* 
1922  * Delete registry value
1923  *
1924  * Callpath:
1925  * RegDeleteValue -> RegDeleteValueA -> RegDeleteValueW
1926  */
1927 /* RegDeleteValueW              [ADVAPI32.136] */
1928 WINAPI DWORD
1929 RegDeleteValueW(HKEY hkey,LPWSTR lpszValue) {
1930         DWORD           i;
1931         LPKEYSTRUCT     lpkey;
1932         LPKEYVALUE      val;
1933
1934         dprintf_reg(stddeb,"RegDeleteValueW(%ld,%s)\n",
1935                 hkey,W2C(lpszValue,0)
1936         );
1937         lpkey=lookup_hkey(hkey);
1938         if (!lpkey)
1939                 return SHELL_ERROR_BADKEY;
1940         if (lpszValue) {
1941                 for (i=0;i<lpkey->nrofvalues;i++)
1942                         if (!strcmpW(lpkey->values[i].name,lpszValue))
1943                                 break;
1944         } else {
1945                 for (i=0;i<lpkey->nrofvalues;i++)
1946                         if (lpkey->values[i].name==NULL)
1947                                 break;
1948         }
1949         if (i==lpkey->nrofvalues)
1950                 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
1951         val     = lpkey->values+i;
1952         if (val->name) free(val->name);
1953         if (val->data) free(val->data);
1954         memcpy( 
1955                 lpkey->values+i,
1956                 lpkey->values+i+1,
1957                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
1958         );
1959         lpkey->values   = (LPKEYVALUE)xrealloc(
1960                                 lpkey->values,
1961                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
1962                         );
1963         lpkey->nrofvalues--;
1964         return SHELL_ERROR_SUCCESS;
1965 }
1966
1967 /* RegDeleteValueA              [ADVAPI32.135] */
1968 WINAPI DWORD
1969 RegDeleteValueA(HKEY hkey,LPSTR lpszValue) {
1970         LPWSTR  lpszValueW;
1971         DWORD   ret;
1972
1973         dprintf_reg(stddeb,"RegDeleteValueA(%ld,%s)\n",
1974                 hkey,lpszValue
1975         );
1976         if (lpszValue)
1977                 lpszValueW=strdupA2W(lpszValue);
1978         else
1979                 lpszValueW=NULL;
1980         ret=RegDeleteValueW(hkey,lpszValueW);
1981         if (lpszValueW)
1982                 free(lpszValueW);
1983         return ret;
1984 }
1985
1986 /* RegDeleteValue               [KERNEL.222] */
1987 WINAPI DWORD
1988 RegDeleteValue(HKEY hkey,LPSTR lpszValue) {
1989         dprintf_reg(stddeb,"RegDeleteValue(%ld,%s)\n",
1990                 hkey,lpszValue
1991         );
1992         return RegDeleteValueA(hkey,lpszValue);
1993 }
1994
1995 /* RegFlushKey                  [ADVAPI32.143] [KERNEL.227] */
1996 WINAPI DWORD
1997 RegFlushKey(HKEY hkey) {
1998         dprintf_reg(stddeb,"RegFlushKey(%ld), STUB.\n",hkey);
1999         return SHELL_ERROR_SUCCESS;
2000 }
2001
2002 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2003
2004 /* RegQueryInfoKeyW             [ADVAPI32.153] */
2005 WINAPI DWORD
2006 RegQueryInfoKeyW(
2007         HKEY    hkey,
2008         LPWSTR  lpszClass,
2009         LPDWORD lpcchClass,
2010         LPDWORD lpdwReserved,
2011         LPDWORD lpcSubKeys,
2012         LPDWORD lpcchMaxSubkey,
2013         LPDWORD lpcchMaxClass,
2014         LPDWORD lpcValues,
2015         LPDWORD lpcchMaxValueName,
2016         LPDWORD lpccbMaxValueData,
2017         LPDWORD lpcbSecurityDescriptor,
2018         FILETIME        *ft
2019 ) {
2020         LPKEYSTRUCT     lpkey,lpxkey;
2021         int             nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2022         int             i;
2023
2024         dprintf_reg(stddeb,"RegQueryInfoKeyW(%lx,......)\n",hkey);
2025         lpkey=lookup_hkey(hkey);
2026         if (!lpkey)
2027                 return SHELL_ERROR_BADKEY;
2028         if (lpszClass) {
2029                 if (lpkey->class) {
2030                         if (strlenW(lpkey->class)*2+2>*lpcchClass) {
2031                                 *lpcchClass=strlenW(lpkey->class)*2;
2032                                 return ERROR_MORE_DATA;
2033                         }
2034                         *lpcchClass=strlenW(lpkey->class)*2;
2035                         memcpy(lpszClass,lpkey->class,strlenW(lpkey->class));
2036                 } else {
2037                         *lpszClass      = 0;
2038                         *lpcchClass     = 0;
2039                 }
2040         } else {
2041                 if (lpcchClass)
2042                         *lpcchClass     = strlenW(lpkey->class)*2;
2043         }
2044         lpxkey=lpkey->nextsub;
2045         nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2046         while (lpxkey) {
2047                 nrofkeys++;
2048                 if (strlenW(lpxkey->keyname)>maxsubkey)
2049                         maxsubkey=strlenW(lpxkey->keyname);
2050                 if (lpxkey->class && strlenW(lpxkey->class)>maxclass)
2051                         maxclass=strlenW(lpxkey->class);
2052                 if (lpxkey->nrofvalues>maxvalues)
2053                         maxvalues=lpxkey->nrofvalues;
2054                 for (i=0;i<lpxkey->nrofvalues;i++) {
2055                         LPKEYVALUE      val=lpxkey->values+i;
2056
2057                         if (val->name && strlenW(val->name)>maxvname)
2058                                 maxvname=strlenW(val->name);
2059                         if (val->len>maxvdata)
2060                                 maxvdata=val->len;
2061                 }
2062                 lpxkey=lpxkey->next;
2063         }
2064         if (!maxclass) maxclass = 1;
2065         if (!maxvname) maxvname = 1;
2066         if (lpcSubKeys)
2067                 *lpcSubKeys     = nrofkeys;
2068         if (lpcchMaxSubkey)
2069                 *lpcchMaxSubkey = maxsubkey*2;
2070         if (lpcchMaxClass)
2071                 *lpcchMaxClass  = maxclass*2;
2072         if (lpcValues)
2073                 *lpcValues      = maxvalues;
2074         if (lpcchMaxValueName)
2075                 *lpcchMaxValueName= maxvname;
2076         if (lpccbMaxValueData)
2077                 *lpccbMaxValueData= maxvdata;
2078         return SHELL_ERROR_SUCCESS;
2079 }
2080
2081 /* RegQueryInfoKeyA             [ADVAPI32.152] */
2082 WINAPI DWORD
2083 RegQueryInfoKeyA(
2084         HKEY    hkey,
2085         LPSTR   lpszClass,
2086         LPDWORD lpcchClass,
2087         LPDWORD lpdwReserved,
2088         LPDWORD lpcSubKeys,
2089         LPDWORD lpcchMaxSubkey,
2090         LPDWORD lpcchMaxClass,
2091         LPDWORD lpcValues,
2092         LPDWORD lpcchMaxValueName,
2093         LPDWORD lpccbMaxValueData,
2094         LPDWORD lpcbSecurityDescriptor,
2095         FILETIME        *ft
2096 ) {
2097         LPWSTR          lpszClassW;
2098         DWORD           ret;
2099
2100         dprintf_reg(stddeb,"RegQueryInfoKeyA(%lx,......)\n",hkey);
2101         if (lpszClass) {
2102                 *lpcchClass*= 2;
2103                 lpszClassW  = (LPWSTR)xmalloc(*lpcchClass);
2104
2105         } else
2106                 lpszClassW  = NULL;
2107         ret=RegQueryInfoKeyW(
2108                 hkey,
2109                 lpszClassW,
2110                 lpcchClass,
2111                 lpdwReserved,
2112                 lpcSubKeys,
2113                 lpcchMaxSubkey,
2114                 lpcchMaxClass,
2115                 lpcValues,
2116                 lpcchMaxValueName,
2117                 lpccbMaxValueData,
2118                 lpcbSecurityDescriptor,
2119                 ft
2120         );
2121         if (ret==ERROR_SUCCESS)
2122                 strcpyWA(lpszClass,lpszClassW);
2123         if (lpcchClass)
2124                 *lpcchClass/=2;
2125         if (lpcchMaxSubkey)
2126                 *lpcchMaxSubkey/=2;
2127         if (lpcchMaxClass)
2128                 *lpcchMaxClass/=2;
2129         if (lpcchMaxValueName)
2130                 *lpcchMaxValueName/=2;
2131         if (lpszClassW)
2132                 free(lpszClassW);
2133         return ret;
2134 }