Release 960824
[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 <malloc.h>
11 #include <unistd.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
16 #include <sys/stat.h>
17 #include <pwd.h>
18 #include <time.h>
19 #include "windows.h"
20 #include "win.h"
21 #include "winerror.h"
22 #include "file.h"
23 #include "string32.h"   
24 #include "stddebug.h"
25 #include "debug.h"
26 #include "xmalloc.h"
27 #include "winreg.h"
28
29 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
30
31 /* FIXME: following defines should be configured global ... */
32
33 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
34 #define WINE_PREFIX                     "/.wine"
35 #define SAVE_USERS_DEFAULT              "/usr/local/etc/wine.userreg"
36 #define SAVE_LOCAL_MACHINE_DEFAULT      "/usr/local/etc/wine.systemreg"
37
38 /* relative in ~user/.wine/ : */
39 #define SAVE_CURRENT_USER               "user.reg"
40 #define SAVE_LOCAL_MACHINE              "system.reg"
41
42 #define KEY_REGISTRY    "Software\\The WINE team\\WINE\\Registry"
43 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
44
45 /* one value of a key */
46 typedef struct tagKEYVALUE
47 {
48     LPWSTR   name;          /* name of value (UNICODE) or NULL for win31 */
49     DWORD    type;          /* type of value */
50     DWORD    len;           /* length of data */
51     DWORD    lastmodified;  /* time of seconds since 1.1.1970 */
52     LPBYTE   data;          /* content, may be strings, binaries, etc. */
53 } KEYVALUE,*LPKEYVALUE;
54
55 /* a registry key */
56 typedef struct tagKEYSTRUCT
57 {
58     LPWSTR               keyname;       /* name of THIS key (UNICODE) */
59     DWORD                flags;         /* flags. */
60     LPWSTR               class;
61     /* values */
62     DWORD                nrofvalues;    /* nr of values in THIS key */
63     LPKEYVALUE           values;        /* values in THIS key */
64     /* key management pointers */
65     struct tagKEYSTRUCT *next;          /* next key on same hierarchy */
66     struct tagKEYSTRUCT *nextsub;       /* keys that hang below THIS key */
67 } KEYSTRUCT, *LPKEYSTRUCT;
68
69
70 static KEYSTRUCT        *key_classes_root=NULL; /* windows 3.1 global values */
71 static KEYSTRUCT        *key_current_user=NULL; /* user specific values */
72 static KEYSTRUCT        *key_local_machine=NULL;/* machine specific values */
73 static KEYSTRUCT        *key_users=NULL;        /* all users? */
74
75 /* dynamic, not saved */
76 static KEYSTRUCT        *key_performance_data=NULL;
77 static KEYSTRUCT        *key_current_config=NULL;
78 static KEYSTRUCT        *key_dyn_data=NULL;
79
80 /* what valuetypes do we need to convert? */
81 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
82
83 #define strdupA2W(x)    STRING32_DupAnsiToUni(x)
84 #define strdupW2A(x)    STRING32_DupUniToAnsi(x)
85 #define strdupW(x)      STRING32_strdupW(x)
86 #define strcmpniW(a,b)  STRING32_lstrcmpniW(a,b)
87 #define strchrW(a,c)    STRING32_lstrchrW(a,c)
88 #define strcpyWA(a,b)   STRING32_UniToAnsi(a,b)
89
90 static struct openhandle {
91         LPKEYSTRUCT     lpkey;
92         HKEY            hkey;
93         REGSAM          accessmask;
94 }  *openhandles=NULL;
95 static int      nrofopenhandles=0;
96 static int      currenthandle=1;
97
98 static void
99 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
100         int     i;
101
102         for (i=0;i<nrofopenhandles;i++) {
103                 if (openhandles[i].lpkey==lpkey) {
104                         dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
105                 }
106                 if (openhandles[i].hkey==hkey) {
107                         dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
108                 }
109         }
110         openhandles=xrealloc(   openhandles,
111                                 sizeof(struct openhandle)*(nrofopenhandles+1)
112                 );
113         openhandles[i].lpkey    = lpkey;
114         openhandles[i].hkey     = hkey;
115         openhandles[i].accessmask= accessmask;
116         nrofopenhandles++;
117 }
118
119 static LPKEYSTRUCT
120 get_handle(HKEY hkey) {
121         int     i;
122
123         for (i=0;i<nrofopenhandles;i++)
124                 if (openhandles[i].hkey==hkey)
125                         return openhandles[i].lpkey;
126         dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
127         return NULL;
128 }
129
130 static void
131 remove_handle(HKEY hkey) {
132         int     i;
133
134         for (i=0;i<nrofopenhandles;i++)
135                 if (openhandles[i].hkey==hkey)
136                         break;
137         if (i==nrofopenhandles) {
138                 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
139                 return;
140         }
141         memcpy( openhandles+i,
142                 openhandles+i+1,
143                 sizeof(struct openhandle)*(nrofopenhandles-i-1)
144         );
145         openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
146         nrofopenhandles--;
147         return;
148 }
149
150
151 /* debug function, converts a unicode into a static memory area 
152  * (sub for using two static strings, in case we need them in a single call)
153  */
154 LPSTR
155 W2C(LPCWSTR x,int sub) {
156         static  LPSTR   unicodedebug[2]={NULL,NULL};
157         if (x==NULL)
158                 return "<NULL>";
159         if (sub!=0 && sub!=1)
160                 return "<W2C:bad sub>";
161         if (unicodedebug[sub]) free(unicodedebug[sub]);
162         unicodedebug[sub]       = strdupW2A(x);
163         return unicodedebug[sub];
164 }
165
166 static LPKEYSTRUCT
167 lookup_hkey(HKEY hkey) {
168         switch (hkey) {
169         case 0x00000000:
170         case 0x00000001:
171         case HKEY_CLASSES_ROOT:
172                 return key_classes_root;
173         case HKEY_CURRENT_USER:
174                 return key_current_user;
175         case HKEY_LOCAL_MACHINE:
176                 return key_local_machine;
177         case HKEY_USERS:
178                 return key_users;
179         case HKEY_PERFORMANCE_DATA:
180                 return key_performance_data;
181         case HKEY_DYN_DATA:
182                 return key_dyn_data;
183         case HKEY_CURRENT_CONFIG:
184                 return key_current_config;
185         default:
186                 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
187                         (LONG)hkey
188                 );
189                 return get_handle(hkey);
190         }
191         /*NOTREACHED*/
192 }
193
194 /* 
195  * splits the unicode string 'wp' into an array of strings.
196  * the array is allocated by this function. 
197  * the number of components will be stored in 'wpc'
198  * Free the array using FREE_KEY_PATH
199  */
200 static void
201 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
202         int     i,j,len;
203         LPWSTR  ws;
204
205         ws      = strdupW(wp);
206         *wpc    = 1;
207         for (i=0;ws[i];i++) {
208                 if (ws[i]=='\\') {
209                         ws[i]=0;
210                         (*wpc)++;
211                 }
212         }
213         len     = i;
214         *wpv    = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2));
215         (*wpv)[0]= ws;
216         j       = 1;
217         for (i=1;i<len;i++)
218                 if (ws[i-1]==0)
219                         (*wpv)[j++]=ws+i;
220         (*wpv)[j]=NULL;
221 }
222 #define FREE_KEY_PATH   free(wps[0]);free(wps);
223
224 /*
225  * Shell initialisation, allocates keys. 
226  */
227 void
228 SHELL_Init() {
229         struct  passwd  *pwd;
230
231         HKEY    cl_r_hkey,c_u_hkey;
232 #define ADD_ROOT_KEY(xx) \
233         xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
234         memset(xx,'\0',sizeof(KEYSTRUCT));\
235         xx->keyname= strdupA2W("<should_not_appear_anywhere>");
236
237         ADD_ROOT_KEY(key_local_machine);
238         if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
239                 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
240                 exit(1);
241         }
242         key_classes_root = lookup_hkey(cl_r_hkey);
243
244         ADD_ROOT_KEY(key_users);
245
246 #if 0
247         /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg 
248          *        (later, when a win32 registry editing tool becomes avail.)
249          */
250         while (pwd=getpwent()) {
251                 if (pwd->pw_name == NULL)
252                         continue;
253                 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
254                 RegCloseKey(c_u_hkey);
255         }
256 #endif
257         pwd=getpwuid(getuid());
258         if (pwd && pwd->pw_name) {
259                 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
260                 key_current_user = lookup_hkey(c_u_hkey);
261         } else {
262                 ADD_ROOT_KEY(key_current_user);
263         }
264         ADD_ROOT_KEY(key_performance_data);
265         ADD_ROOT_KEY(key_current_config);
266         ADD_ROOT_KEY(key_dyn_data);
267 #undef ADD_ROOT_KEY
268 }
269
270 /************************ SAVE Registry Function ****************************/
271
272 #define REGISTRY_SAVE_VERSION   0x00000001
273
274 /* Registry saveformat:
275  * If you change it, increase above number by 1, which will flush
276  * old registry database files.
277  * 
278  * Global:
279  *      "WINE REGISTRY Version %d"
280  *      subkeys....
281  * Subkeys:
282  *      keyname
283  *              valuename=lastmodified,type,data
284  *              ...
285  *              subkeys
286  *      ...
287  * keyname,valuename,stringdata:
288  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
289  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
290  *      ( "=\\\t" escaped in \uXXXX form.)
291  * type,lastmodified: 
292  *      int
293  * 
294  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
295  *
296  * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
297  * SaveOnlyUpdatedKeys=yes
298  */
299 static int
300 _save_check_tainted(LPKEYSTRUCT lpkey) {
301         int             tainted;
302
303         if (!lpkey)
304                 return 0;
305         if (lpkey->flags & REG_OPTION_TAINTED)
306                 tainted = 1;
307         else
308                 tainted = 0;
309         while (lpkey) {
310                 if (_save_check_tainted(lpkey->nextsub)) {
311                         lpkey->flags |= REG_OPTION_TAINTED;
312                         tainted = 1;
313                 }
314                 lpkey   = lpkey->next;
315         }
316         return tainted;
317 }
318
319 static void
320 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
321         LPWSTR  s;
322         int     doescape;
323
324         if (wstr==NULL)
325                 return;
326         s=wstr;
327         while (*s) {
328                 doescape=0;
329                 if (*s>0xff)
330                         doescape = 1;
331                 if (*s=='\n')
332                         doescape = 1;
333                 if (escapeeq && *s=='=')
334                         doescape = 1;
335                 if (*s=='\\')
336                         fputc(*s,F); /* if \\ than put it twice. */
337                 if (doescape)
338                         fprintf(F,"\\u%04x",*((unsigned short*)s));
339                 else
340                         fputc(*s,F);
341                 s++;
342         }
343 }
344
345 static int
346 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
347         LPKEYSTRUCT     lpxkey;
348         int             i,tabs,j;
349
350         lpxkey  = lpkey;
351         while (lpxkey) {
352                 if (    !(lpxkey->flags & REG_OPTION_VOLATILE) &&
353                         (all || (lpxkey->flags & REG_OPTION_TAINTED))
354                 ) {
355                         for (tabs=level;tabs--;)
356                                 fputc('\t',F);
357                         _save_USTRING(F,lpxkey->keyname,1);
358                         fputs("\n",F);
359                         for (i=0;i<lpxkey->nrofvalues;i++) {
360                                 LPKEYVALUE      val=lpxkey->values+i;
361
362                                 for (tabs=level+1;tabs--;)
363                                         fputc('\t',F);
364                                 _save_USTRING(F,val->name,0);
365                                 fputc('=',F);
366                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
367                                 if ((1<<val->type) & UNICONVMASK)
368                                         _save_USTRING(F,(LPWSTR)val->data,0);
369                                 else
370                                         for (j=0;j<val->len;j++)
371                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
372                                 fputs("\n",F);
373                         }
374                         /* descend recursively */
375                         if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
376                                 return 0;
377                 }
378                 lpxkey=lpxkey->next;
379         }
380         return 1;
381 }
382
383 static int
384 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
385         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
386         _save_check_tainted(lpkey->nextsub);
387         return _savesubkey(F,lpkey->nextsub,0,all);
388 }
389
390 static void
391 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
392         FILE    *F;
393
394         F=fopen(fn,"w");
395         if (F==NULL) {
396                 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
397                         fn,strerror(errno)
398                 );
399                 return;
400         }
401         if (!_savesubreg(F,lpkey,all)) {
402                 fclose(F);
403                 unlink(fn);
404                 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
405                 return;
406         }
407         fclose(F);
408 }
409
410 void
411 SHELL_SaveRegistry() {
412         char    *fn;
413         struct  passwd  *pwd;
414         char    buf[4];
415         HKEY    hkey;
416         int     all;
417
418         all=0;
419         if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
420                 strcpy(buf,"yes");
421         } else {
422                 DWORD len,junk,type;
423
424                 len=4;
425                 if (    (ERROR_SUCCESS!=RegQueryValueEx32A(
426                                 hkey,
427                                 VAL_SAVEUPDATED,
428                                 &junk,
429                                 &type,
430                                 buf,
431                                 &len
432                         ))|| (type!=REG_SZ)
433                 )
434                         strcpy(buf,"yes");
435                 RegCloseKey(hkey);
436         }
437         if (lstrcmpi32A(buf,"yes"))
438                 all=1;
439         pwd=getpwuid(getuid());
440         if (pwd!=NULL && pwd->pw_dir!=NULL) {
441                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_USERS_DEFAULT)+2);
442                 strcpy(fn,pwd->pw_dir);
443                 strcat(fn,WINE_PREFIX);
444                 /* create the directory. don't care about errorcodes. */
445                 mkdir(fn,0755); /* drwxr-xr-x */
446                 strcat(fn,"/"SAVE_CURRENT_USER);
447                 _savereg(key_current_user,fn,all);
448                 free(fn);
449                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
450                 strcpy(fn,pwd->pw_dir);
451                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
452                 _savereg(key_local_machine,fn,all);
453                 free(fn);
454         } else
455                 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
456 }
457
458 /************************ LOAD Registry Function ****************************/
459
460 static LPKEYSTRUCT
461 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
462         LPKEYSTRUCT     lpxkey,*lplpkey;
463
464         lplpkey= &(lpkey->nextsub);
465         lpxkey  = *lplpkey;
466         while (lpxkey) {
467                 if (!lstrcmp32W(lpxkey->keyname,keyname))
468                         break;
469                 lplpkey = &(lpxkey->next);
470                 lpxkey  = *lplpkey;
471         }
472         if (lpxkey==NULL) {
473                 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
474                 lpxkey  = *lplpkey;
475                 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
476                 lpxkey->keyname = keyname;
477         } else
478                 free(keyname);
479         return lpxkey;
480 }
481
482 static void
483 _find_or_add_value(
484         LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
485         DWORD lastmodified
486 ) {
487         LPKEYVALUE      val=NULL;
488         int             i;
489
490         for (i=0;i<lpkey->nrofvalues;i++) {
491                 val=lpkey->values+i;
492                 if (name==NULL) {
493                         if (val->name==NULL)
494                                 break;
495                 } else {
496                         if (    val->name!=NULL && 
497                                 !lstrcmp32W(val->name,name)
498                         )
499                                 break;
500                 }
501         }
502         if (i==lpkey->nrofvalues) {
503                 lpkey->values = xrealloc(
504                         lpkey->values,
505                         (++lpkey->nrofvalues)*sizeof(KEYVALUE)
506                 );
507                 val=lpkey->values+i;
508                 memset(val,'\0',sizeof(KEYVALUE));
509                 val->name = name;
510         } else {
511                 if (name)
512                         free(name);
513         }
514         if (val->lastmodified<lastmodified) {
515                 val->lastmodified=lastmodified;
516                 val->type = type;
517                 val->len  = len;
518                 if (val->data) 
519                         free(val->data);
520                 val->data = data;
521         } else
522                 free(data);
523 }
524
525
526 /* reads a line including dynamically enlarging the readbuffer and throwing
527  * away comments
528  */
529 static int 
530 _wine_read_line(FILE *F,char **buf,int *len) {
531         char    *s,*curread;
532         int     mylen,curoff;
533
534         curread = *buf;
535         mylen   = *len;
536         **buf   = '\0';
537         while (1) {
538                 while (1) {
539                         s=fgets(curread,mylen,F);
540                         if (s==NULL)
541                                 return 0; /* EOF */
542                         if (NULL==(s=strchr(curread,'\n'))) {
543                                 /* buffer wasn't large enough */
544                                 curoff  = strlen(*buf);
545                                 *buf    = xrealloc(*buf,*len*2);
546                                 curread = *buf + curoff;
547                                 mylen   = *len; /* we filled up the buffer and 
548                                                  * got new '*len' bytes to fill
549                                                  */
550                                 *len    = *len * 2;
551                         } else {
552                                 *s='\0';
553                                 break;
554                         }
555                 }
556                 /* throw away comments */
557                 if (**buf=='#' || **buf==';') {
558                         curread = *buf;
559                         mylen   = *len;
560                         continue;
561                 }
562                 if (s)  /* got end of line */
563                         break;
564         }
565         return 1;
566 }
567
568 /* converts a char* into a UNICODE string (up to a special char)
569  * and returns the position exactly after that string
570  */
571 static char*
572 _wine_read_USTRING(char *buf,LPWSTR *str) {
573         char    *s;
574         LPWSTR  ws;
575
576         /* read up to "=" or "\0" or "\n" */
577         s       = buf;
578         if (*s == '=') {
579                 /* empty string is the win3.1 default value(NULL)*/
580                 *str    = NULL;
581                 return s;
582         }
583         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
584         ws      = *str;
585         while (*s && (*s!='\n') && (*s!='=')) {
586                 if (*s!='\\')
587                         *ws++=*((unsigned char*)s++);
588                 else {
589                         s++;
590                         if (*s=='\\') {
591                                 *ws+='\\';
592                                 s++;
593                                 continue;
594                         }
595                         if (*s!='u') {
596                                 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
597                                 *ws++='\\';
598                                 *ws++=*s++;
599                         } else {
600                                 char    xbuf[5];
601                                 int     wc;
602
603                                 s++;
604                                 memcpy(xbuf,s,4);xbuf[4]='\0';
605                                 if (!sscanf(xbuf,"%x",&wc))
606                                         fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
607                                 s+=4;
608                                 *ws++   =(unsigned short)wc;
609                         }
610                 }
611         }
612         *ws     = 0;
613         ws      = *str;
614         *str    = strdupW(*str);
615         free(ws);
616         return s;
617 }
618
619 static int
620 _wine_loadsubkey(
621         FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
622 ) {
623         LPKEYSTRUCT     lpxkey;
624         int             i;
625         char            *s;
626         LPWSTR          name;
627
628         lpkey->flags |= optflag;
629
630         /* good. we already got a line here ... so parse it */
631         lpxkey  = NULL;
632         while (1) {
633                 i=0;s=*buf;
634                 while (*s=='\t') {
635                         s++;
636                         i++;
637                 }
638                 if (i>level) {
639                         if (lpxkey==NULL) {
640                                 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
641                                 return 0;
642                         }
643                         _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
644                         continue;
645                 }
646                 /* let the caller handle this line */
647                 if (i<level || **buf=='\0')
648                         return 1;
649
650                 /* it can be: a value or a keyname. Parse the name first */
651                 s=_wine_read_USTRING(s,&name);
652
653                 /* switch() default: hack to avoid gotos */
654                 switch (0) {
655                 default:
656                         if (*s=='\0') {
657                                 lpxkey=_find_or_add_key(lpkey,name);
658                         } else {
659                                 LPBYTE          data;
660                                 int             len,lastmodified,type;
661
662                                 if (*s!='=') {
663                                         fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
664                                         break;
665                                 }
666                                 s++;
667                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
668                                         fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
669                                         break;
670                                 }
671                                 /* skip the 2 , */
672                                 s=strchr(s,',');s++;
673                                 s=strchr(s,',');s++;
674                                 if ((1<<type) & UNICONVMASK) {
675                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
676                                         if (data)
677                                                 len = lstrlen32W((LPWSTR)data)*2+2;
678                                         else    
679                                                 len = 0;
680                                 } else {
681                                         len=strlen(s)/2;
682                                         data = (LPBYTE)xmalloc(len+1);
683                                         for (i=0;i<len;i++) {
684                                                 data[i]=0;
685                                                 if (*s>='0' && *s<='9')
686                                                         data[i]=(*s-'0')<<4;
687                                                 if (*s>='a' && *s<='f')
688                                                         data[i]=(*s-'a')<<4;
689                                                 if (*s>='A' && *s<='F')
690                                                         data[i]=(*s-'A')<<4;
691                                                 s++;
692                                                 if (*s>='0' && *s<='9')
693                                                         data[i]|=*s-'0';
694                                                 if (*s>='a' && *s<='f')
695                                                         data[i]|=*s-'a';
696                                                 if (*s>='A' && *s<='F')
697                                                         data[i]|=*s-'A';
698                                                 s++;
699                                         }
700                                 }
701                                 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
702                         }
703                 }
704                 /* read the next line */
705                 if (!_wine_read_line(F,buf,buflen))
706                         return 1;
707         }
708         return 1;
709 }
710
711 static int
712 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
713         int     ver;
714         char    *buf;
715         int     buflen;
716
717         buf=xmalloc(10);buflen=10;
718         if (!_wine_read_line(F,&buf,&buflen)) {
719                 free(buf);
720                 return 0;
721         }
722         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
723                 free(buf);
724                 return 0;
725         }
726         if (ver!=REGISTRY_SAVE_VERSION) {
727                 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
728                 free(buf);
729                 return 0;
730         }
731         if (!_wine_read_line(F,&buf,&buflen)) {
732                 free(buf);
733                 return 0;
734         }
735         if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
736                 free(buf);
737                 return 0;
738         }
739         free(buf);
740         return 1;
741 }
742
743 static void
744 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
745         FILE    *F;
746
747         F=fopen(fn,"rb");
748         if (F==NULL) {
749                 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
750                         fn,strerror(errno)
751                 );
752                 return;
753         }
754         if (!_wine_loadsubreg(F,lpkey,optflag)) {
755                 fclose(F);
756                 unlink(fn);
757                 return;
758         }
759         fclose(F);
760 }
761
762 static void
763 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
764         LPKEYSTRUCT     lpxkey;
765         int             j;
766         LPKEYVALUE      valfrom;
767
768         from=from->nextsub;
769         while (from) {
770                 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
771
772                 for (j=0;j<from->nrofvalues;j++) {
773                         LPWSTR  name;
774                         LPBYTE  data;
775
776                         valfrom = from->values+j;
777                         name=valfrom->name;
778                         if (name) name=strdupW(name);
779                         data=(LPBYTE)malloc(valfrom->len);
780                         memcpy(data,valfrom->data,valfrom->len);
781
782                         _find_or_add_value(
783                                 lpxkey,
784                                 name,
785                                 valfrom->type,
786                                 data,
787                                 valfrom->len,
788                                 valfrom->lastmodified
789                         );
790                 }
791                 _copy_registry(from,lpxkey);
792                 from = from->next;
793         }
794 }
795
796 /* WINDOWS 95 REGISTRY LOADER */
797 /* 
798  * Structure of a win95 registry database.
799  * main header:
800  * 0 :  "CREG"  - magic
801  * 4 :  DWORD version
802  * 8 :  DWORD offset_of_RGDB_part
803  * 0C..1F:      ? (someone fill in please)
804  *
805  * 20: RGKN_section:
806  *   header:
807  *      0 :             "RGKN"  - magic
808  *      4..0x1B:        ? (fill in)
809  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
810  *
811  *   Disk Key Entry Structure:
812  *      00: DWORD       - unknown
813  *      04: DWORD       - unknown
814  *      08: DWORD       - unknown, but usually 0xFFFFFFFF on win95 systems
815  *      0C: DWORD       - disk address of PreviousLevel Key.
816  *      10: DWORD       - disk address of Next Sublevel Key.
817  *      14: DWORD       - disk address of Next Key (on same level).
818  * DKEP>18: WORD        - Nr, Low Significant part.
819  *      1A: WORD        - Nr, High Significant part.
820  *
821  * The disk address always points to the nr part of the previous key entry 
822  * of the referenced key. Don't ask me why, or even if I got this correct
823  * from staring at 1kg of hexdumps. (DKEP)
824  *
825  * The number of the entry is the low byte of the Low Significant Part ored
826  * with 0x100 * (low byte of the High Significant part)
827  * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
828  *
829  * There are two minor corrections to the position of that structure.
830  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
831  *    the DKE reread from there.
832  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
833  * (FIXME: slightly better explanation needed here)
834  *
835  * RGDB_section:
836  *      00:             "RGDB"  - magic
837  *      04: DWORD       offset to next RGDB section (perhaps WORD)
838  *      08...1F:        ?
839  *      20.....:        disk keys
840  *
841  * disk key:
842  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
843  *      08:     WORD    nrLS            - low significant part of NR
844  *      0A:     WORD    nrHS            - high significant part of NR
845  *      0C:     DWORD   bytesused       - bytes used in this structure.
846  *      10:     WORD    name_len        - length of name in bytes. without \0
847  *      12:     WORD    nr_of_values    - number of values.
848  *      14:     char    name[name_len]  - name string. No \0.
849  *      14+name_len: disk values
850  *      nextkeyoffset: ... next disk key
851  *
852  * disk value:
853  *      00:     DWORD   type            - value type (hmm, could be WORD too)
854  *      04:     DWORD                   - unknown, usually 0
855  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
856  *      0C:     WORD    datalen         - length of Data.
857  *      10:     char    name[namelen]   - name, no \0
858  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
859  *      10+namelen+datalen: next values or disk key
860  *
861  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
862  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
863  * structure) and reading another RGDB_section.
864  * repeat until end of file.
865  *
866  * FIXME: this description needs some serious help, yes.
867  */
868
869 struct  _w95keyvalue {
870         unsigned long           type;
871         unsigned short          datalen;
872         char                    *name;
873         unsigned char           *data;
874         unsigned long           x1;
875         int                     lastmodified;
876 };
877
878 struct  _w95key {
879         char                    *name;
880         int                     nrofvals;
881         struct  _w95keyvalue    *values;
882         unsigned long           dkeaddr;
883         unsigned long           x1;
884         unsigned long           x2;
885         unsigned long           x3;
886         unsigned long           xx1;
887         struct _w95key          *prevlvl;
888         struct _w95key          *nextsub;
889         struct _w95key          *next;
890 };
891
892 /* fast lookup table dkeaddr->nr */
893 struct  _w95nr2da {
894         unsigned long           dkeaddr;
895         unsigned long           nr;
896 };
897
898
899 static void
900 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
901         int             i;
902         LPKEYSTRUCT     lpxkey;
903         LPWSTR          name;
904
905         while (key) {
906                 if (key->name == NULL) {
907                         fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
908                                 key->dkeaddr
909                         );
910                         return;
911                 }
912                 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
913
914                 if (key->nrofvals<0) {
915                         /* shouldn't happen */
916                         fprintf(stderr,"key %s already processed!\n",key->name);
917                         key = key->next;
918                         continue;
919                 }
920                 for (i=0;i<key->nrofvals;i++) {
921                         LPBYTE  data;
922                         int     len;
923
924                         name = strdupA2W(key->values[i].name);
925                         if (!*name) name = NULL;
926                         free(key->values[i].name);
927
928                         len     = key->values[i].datalen;
929                         data    = key->values[i].data;
930                         if ((1<<key->values[i].type) & UNICONVMASK) {
931                                 data = (BYTE*)strdupA2W(data);
932                                 len  = lstrlen32W((LPWSTR)data)*2+2;
933                                 free(key->values[i].data);
934                         }
935                         _find_or_add_value(
936                                 lpxkey,
937                                 name,
938                                 key->values[i].type,
939                                 data,
940                                 len,
941                                 key->values[i].lastmodified
942                         );
943                 }
944                 if (key->values) {
945                         free(key->values);
946                         key->values = NULL;
947                 }
948                 key->nrofvals=-key->nrofvals-1;
949                 _w95_walk_tree(lpxkey,key->nextsub);
950                 key=key->next;
951         }
952 }
953
954 /* small helper function to adjust address offset (dkeaddrs) */
955 static unsigned long
956 _w95_adj_da(unsigned long dkeaddr) {
957         if ((dkeaddr&0xFFF)<0x018) {
958                 int     diff;
959
960                 diff=0x1C-(dkeaddr&0xFFF);
961                 return dkeaddr+diff;
962         }
963         if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
964                 /* readjust to 0x000,
965                  * but ONLY if we are >0x1000 already
966                  */
967                 if (dkeaddr & ~0xFFF)
968                         return dkeaddr & ~0xFFF;
969         }
970         return dkeaddr;
971 }
972
973 static int
974 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
975
976 static struct _w95key*
977 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
978         int     i,off;
979
980         if (dkeaddr == 0xFFFFFFFF)
981                 return NULL;
982         if (dkeaddr<0x20)
983                 return NULL;
984         dkeaddr=_w95_adj_da(dkeaddr+0x1c);
985         off = (dkeaddr-0x3c)/0x1c;
986         for (i=0;i<n;i++)
987                 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
988                         return keys+nr2da[(i+off)%n].nr;
989         /* 0x3C happens often, just report unusual values */
990         if (dkeaddr!=0x3c)
991                 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
992         return NULL;
993 }
994
995 static void
996 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
997         /* Disk Key Entry structure (RGKN part) */
998         struct  dke {
999                 unsigned long           x1;
1000                 unsigned long           x2;
1001                 unsigned long           x3;/*usually 0xFFFFFFFF */
1002                 unsigned long           prevlvl;
1003                 unsigned long           nextsub;
1004                 unsigned long           next;
1005                 unsigned short          nrLS;
1006                 unsigned short          nrMS;
1007         };
1008         /* Disk Key Header structure (RGDB part) */
1009         struct  dkh {
1010                 unsigned long           nextkeyoff; 
1011                 unsigned short          nrLS;
1012                 unsigned short          nrMS;
1013                 unsigned long           bytesused;
1014                 unsigned short          keynamelen;
1015                 unsigned short          values;
1016                 unsigned long           xx1;
1017                 /* keyname */
1018                 /* disk key values or nothing */
1019         };
1020         /* Disk Key Value structure */
1021         struct  dkv {
1022                 unsigned long           type;
1023                 unsigned long           x1;
1024                 unsigned short          valnamelen;
1025                 unsigned short          valdatalen;
1026                 /* valname, valdata */
1027         };
1028         struct  _w95nr2da       *nr2da;
1029
1030         HFILE           hfd;
1031         int             fd,lastmodified;
1032         char            magic[5];
1033         unsigned long   nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1034         struct  _w95key *keys;
1035         int             nrofdkes;
1036         unsigned char   *data,*curdata,*nextrgdb;
1037         OFSTRUCT        ofs;
1038         struct  stat    stbuf;
1039
1040         dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1041         hfd=OpenFile(fn,&ofs,OF_READ);
1042         if (hfd==HFILE_ERROR)
1043                 return;
1044         fd = FILE_GetUnixHandle(hfd);
1045         magic[4]=0;
1046         if (4!=read(fd,magic,4))
1047                 return;
1048         if (strcmp(magic,"CREG")) {
1049                 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1050                 return;
1051         }
1052         if (4!=read(fd,&version,4))
1053                 return;
1054         if (4!=read(fd,&rgdbsection,4))
1055                 return;
1056         if (-1==lseek(fd,0x20,SEEK_SET))
1057                 return;
1058         if (4!=read(fd,magic,4))
1059                 return;
1060         if (strcmp(magic,"RGKN")) {
1061                 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1062                 return;
1063         }
1064
1065         /* STEP 1: Keylink structures */
1066         if (-1==lseek(fd,0x40,SEEK_SET))
1067                 return;
1068         where   = 0x40;
1069         end     = rgdbsection;
1070
1071         nrofdkes = (end-where)/sizeof(struct dke)+100;
1072         data = (char*)xmalloc(end-where);
1073         if ((end-where)!=read(fd,data,end-where))
1074                 return;
1075         curdata = data;
1076
1077         keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1078         memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1079         nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1080         memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1081
1082         for (i=0;i<nrofdkes;i++) {
1083                 struct  dke     dke;
1084                 unsigned long   dkeaddr;
1085
1086                 pos=curdata-data+0x40;
1087                 memcpy(&dke,curdata,sizeof(dke));
1088                 curdata+=sizeof(dke);
1089                 nr = dke.nrLS + (dke.nrMS<<8);
1090                 dkeaddr=pos-4;
1091                 if ((dkeaddr&0xFFF)<0x018) {
1092                         int     diff;
1093
1094                         diff=0x1C-(dkeaddr&0xFFF);
1095                         dkeaddr+=diff;
1096                         curdata+=diff-sizeof(dke);
1097                         memcpy(&dke,curdata,sizeof(dke));
1098                         nr = dke.nrLS + (dke.nrMS<<8);
1099                         curdata+=sizeof(dke);
1100                 }
1101                 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1102                         /* readjust to 0x000,
1103                          * but ONLY if we are >0x1000 already
1104                          */
1105                         if (dkeaddr & ~0xFFF)
1106                                 dkeaddr = dkeaddr & ~0xFFF;
1107                 }
1108                 if (nr>nrofdkes) {
1109                         /* 0xFFFFFFFF happens often, just report unusual values */
1110                         if (nr!=0xFFFFFFFF)
1111                                 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1112                         continue;
1113                 }
1114                 if (keys[nr].dkeaddr) {
1115                         int     x;
1116
1117                         for (x=sizeof(dke);x--;)
1118                                 if (((char*)&dke)[x])
1119                                         break;
1120                         if (x==-1)
1121                                 break; /* finished reading if we got only 0 */
1122                         if (nr) {
1123                                 if (    (dke.next!=(long)keys[nr].next) ||
1124                                         (dke.nextsub!=(long)keys[nr].nextsub)   ||
1125                                         (dke.prevlvl!=(long)keys[nr].prevlvl) 
1126                                 )
1127                                         dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1128                         }
1129                         continue;
1130                 }
1131                 nr2da[i].nr      = nr;
1132                 nr2da[i].dkeaddr = dkeaddr;
1133
1134                 keys[nr].dkeaddr = dkeaddr;
1135                 keys[nr].x1 = dke.x1;
1136                 keys[nr].x2 = dke.x2;
1137                 keys[nr].x3 = dke.x3;
1138                 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1139                 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1140                 keys[nr].next   = (struct _w95key*)dke.next;
1141         }
1142         free(data);
1143
1144         qsort(nr2da,nrofdkes,sizeof(nr2da[0]),_w95dkecomp);
1145
1146         /* STEP 2: keydata & values */
1147         if (-1==fstat(fd,&stbuf))
1148                 return;
1149         end             = stbuf.st_size;
1150         lastmodified    = stbuf.st_mtime;
1151
1152         if (-1==lseek(fd,rgdbsection,SEEK_SET))
1153                 return;
1154         data = (char*)xmalloc(end-rgdbsection);
1155         if ((end-rgdbsection)!=read(fd,data,end-rgdbsection))
1156                 return;
1157         _lclose(hfd);
1158         curdata = data;
1159         memcpy(magic,curdata,4);
1160         memcpy(&off_next_rgdb,curdata+4,4);
1161         nextrgdb = curdata+off_next_rgdb;
1162         if (strcmp(magic,"RGDB")) {
1163                 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1164                 return;
1165         }
1166         curdata=data+0x20;
1167         while (1) {
1168                 struct  dkh dkh;
1169                 int     bytesread;
1170                 struct  _w95key *key,xkey;
1171
1172                 bytesread = 0;
1173                 if (curdata>=nextrgdb) {
1174                         curdata = nextrgdb;
1175                         if (!strncmp(curdata,"RGDB",4)) {
1176                                 memcpy(&off_next_rgdb,curdata+4,4);
1177                                 nextrgdb = curdata+off_next_rgdb;
1178                                 curdata+=0x20;
1179                         } else {
1180                                 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1181                                 break;
1182                         }
1183                 }
1184 #define XREAD(whereto,len) \
1185         if ((curdata-data+len)<end) {\
1186                 memcpy(whereto,curdata,len);\
1187                 curdata+=len;\
1188                 bytesread+=len;\
1189         }
1190
1191                 XREAD(&dkh,sizeof(dkh));
1192                 nr = dkh.nrLS + (dkh.nrMS<<8);
1193                 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1194                         if (dkh.nrLS == 0xFFFF) {
1195                                 /* skip over key using nextkeyoff */
1196                                 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1197                                 continue;
1198                         }
1199                         dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1200                         key = &xkey;
1201                         memset(key,'\0',sizeof(xkey));
1202                 } else {
1203                         key = keys+nr;
1204                         if (!key->dkeaddr)
1205                                 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1206                 }
1207                 key->nrofvals   = dkh.values;
1208                 key->name       = (char*)xmalloc(dkh.keynamelen+1);
1209                 key->xx1        = dkh.xx1;
1210                 XREAD(key->name,dkh.keynamelen);
1211                 key->name[dkh.keynamelen]=0;
1212                 if (key->nrofvals) {
1213                         key->values = (struct _w95keyvalue*)xmalloc(
1214                                 sizeof(struct _w95keyvalue)*key->nrofvals
1215                         );
1216                         for (i=0;i<key->nrofvals;i++) {
1217                                 struct  dkv     dkv;
1218
1219                                 XREAD(&dkv,sizeof(dkv));
1220                                 key->values[i].type = dkv.type;
1221                                 key->values[i].name = (char*)xmalloc(
1222                                         dkv.valnamelen+1
1223                                 );
1224                                 key->values[i].datalen = dkv.valdatalen;
1225                                 key->values[i].data = (unsigned char*)xmalloc(
1226                                         dkv.valdatalen+1
1227                                 );
1228                                 key->values[i].x1   = dkv.x1;
1229                                 XREAD(key->values[i].name,dkv.valnamelen);
1230                                 XREAD(key->values[i].data,dkv.valdatalen);
1231                                 key->values[i].data[dkv.valdatalen]=0;
1232                                 key->values[i].name[dkv.valnamelen]=0;
1233                                 key->values[i].lastmodified=lastmodified;
1234                         }
1235                 }
1236                 if (bytesread != dkh.nextkeyoff) {
1237                         if (dkh.bytesused != bytesread)
1238                                 dprintf_reg(stddeb,
1239                                         "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1240                                         dkh.bytesused
1241                                 );
1242                         curdata += dkh.nextkeyoff-bytesread;
1243                 }
1244                 key->prevlvl    = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1245                 key->nextsub    = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1246                 key->next       = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1247                 if (!bytesread)
1248                         break;
1249         }
1250         free(data);
1251         _w95_walk_tree(lpkey,keys);
1252         free(keys);
1253 }
1254
1255 void
1256 SHELL_LoadRegistry() {
1257         char    *fn;
1258         struct  passwd  *pwd;
1259         LPKEYSTRUCT     lpkey;
1260         HKEY            hkey;
1261
1262
1263         if (key_classes_root==NULL)
1264                 SHELL_Init();
1265
1266         /* Load windows 95 entries */
1267         _w95_loadreg("C:\\system.1st",  key_local_machine);
1268         _w95_loadreg("system.dat",      key_local_machine);
1269         _w95_loadreg("user.dat",        key_users);
1270
1271         /* FIXME: win3.1 reg.dat loader still missing */
1272
1273         /* the global user default is loaded under HKEY_USERS\\.Default */
1274         RegCreateKey16(HKEY_USERS,".Default",&hkey);
1275         lpkey = lookup_hkey(hkey);
1276         _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1277
1278         /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1279         _copy_registry(lpkey,key_current_user);
1280         RegCloseKey(hkey);
1281
1282         /* the global machine defaults */
1283         _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1284
1285         /* load the user saved registries */
1286
1287         /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1288
1289         pwd=getpwuid(getuid());
1290         if (pwd!=NULL && pwd->pw_dir!=NULL) {
1291                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1292                 strcpy(fn,pwd->pw_dir);
1293                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1294                 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1295                 free(fn);
1296                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1297                 strcpy(fn,pwd->pw_dir);
1298                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1299                 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1300                 free(fn);
1301         } else
1302                 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1303         if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1304                 DWORD   junk,type,len;
1305                 char    data[5];
1306
1307                 len=4;
1308                 if ((   RegQueryValueEx32A(
1309                                 hkey,
1310                                 VAL_SAVEUPDATED,
1311                                 &junk,
1312                                 &type,
1313                                 data,
1314                                 &len
1315                         )!=ERROR_SUCCESS) ||
1316                         type != REG_SZ
1317                 )
1318                         RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1319                 RegCloseKey(hkey);
1320         }
1321 }
1322
1323
1324 /********************* API FUNCTIONS ***************************************/
1325 /*
1326  * Open Keys.
1327  *
1328  * All functions are stubs to RegOpenKeyEx32W where all the
1329  * magic happens. 
1330  *
1331  * FIXME: security,options,desiredaccess,...
1332  *
1333  * Callpath:
1334  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1335  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
1336  */
1337
1338 /* RegOpenKeyExW                [ADVAPI32.150] */
1339 DWORD RegOpenKeyEx32W(
1340         HKEY    hkey,
1341         LPCWSTR lpszSubKey,
1342         DWORD   dwReserved,
1343         REGSAM  samDesired,
1344         LPHKEY  retkey
1345 ) {
1346         LPKEYSTRUCT     lpNextKey,lpxkey;
1347         LPWSTR          *wps;
1348         int             wpc,i;
1349         dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1350                 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1351         );
1352
1353         lpNextKey       = lookup_hkey(hkey);
1354         if (!lpNextKey)
1355                 return SHELL_ERROR_BADKEY;
1356         if (!lpszSubKey || !*lpszSubKey) {
1357                 add_handle(++currenthandle,lpNextKey,samDesired);
1358                 *retkey=currenthandle;
1359                 return SHELL_ERROR_SUCCESS;
1360         }
1361         split_keypath(lpszSubKey,&wps,&wpc);
1362         i       = 0;
1363         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1364         lpxkey  = lpNextKey;
1365         while (i<wpc) {
1366                 lpxkey=lpNextKey->nextsub;
1367                 while (lpxkey) {
1368                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
1369                                 break;
1370                         lpxkey=lpxkey->next;
1371                 }
1372                 if (!lpxkey) {
1373                         FREE_KEY_PATH;
1374                         return SHELL_ERROR_BADKEY;
1375                 }
1376                 i++;
1377                 lpNextKey       = lpxkey;
1378         }
1379         add_handle(++currenthandle,lpxkey,samDesired);
1380         *retkey = currenthandle;
1381         FREE_KEY_PATH;
1382         return  SHELL_ERROR_SUCCESS;
1383 }
1384
1385 /* RegOpenKeyW                  [ADVAPI32.151] */
1386 DWORD RegOpenKey32W(
1387         HKEY    hkey,
1388         LPCWSTR lpszSubKey,
1389         LPHKEY  retkey
1390 ) {
1391         dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1392                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1393         );
1394         return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1395 }
1396
1397
1398 /* RegOpenKeyExA                [ADVAPI32.149] */
1399 DWORD RegOpenKeyEx32A(
1400         HKEY    hkey,
1401         LPCSTR  lpszSubKey,
1402         DWORD   dwReserved,
1403         REGSAM  samDesired,
1404         LPHKEY  retkey
1405 ) {
1406         LPWSTR  lpszSubKeyW;
1407         DWORD   ret;
1408
1409         dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1410                 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1411         );
1412         if (lpszSubKey)
1413                 lpszSubKeyW=strdupA2W(lpszSubKey);
1414         else
1415                 lpszSubKeyW=NULL;
1416         ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1417         if (lpszSubKeyW)
1418                 free(lpszSubKeyW);
1419         return ret;
1420 }
1421
1422 /* RegOpenKeyA                  [ADVAPI32.148] */
1423 DWORD RegOpenKey32A(
1424         HKEY    hkey,
1425         LPCSTR  lpszSubKey,
1426         LPHKEY  retkey
1427 ) {
1428         dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1429                 (LONG)hkey,lpszSubKey,retkey
1430         );
1431         return  RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1432 }
1433
1434 /* RegOpenKey                   [SHELL.1] [KERNEL.217] */
1435 DWORD RegOpenKey16(
1436         HKEY    hkey,
1437         LPCSTR  lpszSubKey,
1438         LPHKEY  retkey
1439 ) {
1440         dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1441                 (LONG)hkey,lpszSubKey,retkey
1442         );
1443         return RegOpenKey32A(hkey,lpszSubKey,retkey);
1444 }
1445
1446 /* 
1447  * Create keys
1448  * 
1449  * All those functions convert their respective 
1450  * arguments and call RegCreateKeyExW at the end.
1451  *
1452  * FIXME: no security,no access attrib,no optionhandling yet.
1453  *
1454  * Callpath:
1455  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1456  *                                      RegCreateKey32W   -> RegCreateKeyEx32W
1457  */
1458
1459 /* RegCreateKeyExW              [ADVAPI32.131] */
1460 DWORD RegCreateKeyEx32W(
1461         HKEY    hkey,
1462         LPCWSTR lpszSubKey,
1463         DWORD   dwReserved,
1464         LPWSTR  lpszClass,
1465         DWORD   fdwOptions,
1466         REGSAM  samDesired,
1467         LPSECURITY_ATTRIBUTES lpSecAttribs,
1468         LPHKEY  retkey,
1469         LPDWORD lpDispos
1470 ) {
1471         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1472         LPWSTR          *wps;
1473         int             wpc,i;
1474
1475 /*FIXME: handle security/access/whatever */
1476         dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1477                 (LONG)hkey,
1478                 W2C(lpszSubKey,0),
1479                 dwReserved,
1480                 W2C(lpszClass,1),
1481                 fdwOptions,
1482                 samDesired,
1483                 lpSecAttribs,
1484                 retkey,
1485                 lpDispos
1486         );
1487
1488         lpNextKey       = lookup_hkey(hkey);
1489         if (!lpNextKey)
1490                 return SHELL_ERROR_BADKEY;
1491         if (!lpszSubKey || !*lpszSubKey) {
1492                 add_handle(++currenthandle,lpNextKey,samDesired);
1493                 *retkey=currenthandle;
1494                 return SHELL_ERROR_SUCCESS;
1495         }
1496         split_keypath(lpszSubKey,&wps,&wpc);
1497         i       = 0;
1498         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1499         lpxkey  = lpNextKey;
1500         while (i<wpc) {
1501                 lpxkey=lpNextKey->nextsub;
1502                 while (lpxkey) {
1503                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
1504                                 break;
1505                         lpxkey=lpxkey->next;
1506                 }
1507                 if (!lpxkey)
1508                         break;
1509                 i++;
1510                 lpNextKey       = lpxkey;
1511         }
1512         if (lpxkey) {
1513                 add_handle(++currenthandle,lpxkey,samDesired);
1514                 *retkey         = currenthandle;
1515                 *lpDispos       = REG_OPENED_EXISTING_KEY;
1516                 FREE_KEY_PATH;
1517                 return  SHELL_ERROR_SUCCESS;
1518         }
1519         /* good. now the hard part */
1520         while (i<wpc) {
1521                 lplpPrevKey     = &(lpNextKey->nextsub);
1522                 lpxkey          = *lplpPrevKey;
1523                 while (lpxkey) {
1524                         lplpPrevKey     = &(lpxkey->next);
1525                         lpxkey          = *lplpPrevKey;
1526                 }
1527                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1528                 if (!*lplpPrevKey) {
1529                         FREE_KEY_PATH;
1530                         return SHELL_ERROR_OUTOFMEMORY;
1531                 }
1532                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1533                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1534                 (*lplpPrevKey)->next    = NULL;
1535                 (*lplpPrevKey)->nextsub = NULL;
1536                 (*lplpPrevKey)->values  = NULL;
1537                 (*lplpPrevKey)->nrofvalues = 0;
1538                 if (lpszClass)
1539                         (*lplpPrevKey)->class = strdupW(lpszClass);
1540                 else
1541                         (*lplpPrevKey)->class = NULL;
1542                 lpNextKey       = *lplpPrevKey;
1543                 i++;
1544         }
1545         add_handle(++currenthandle,lpNextKey,samDesired);
1546
1547         /*FIXME: flag handling correct? */
1548         lpNextKey->flags= fdwOptions;
1549         if (lpszClass)
1550                 lpNextKey->class = strdupW(lpszClass);
1551         else
1552                 lpNextKey->class = NULL;
1553         lpNextKey->flags|=REG_OPTION_TAINTED;
1554         *retkey         = currenthandle;
1555         *lpDispos       = REG_CREATED_NEW_KEY;
1556         FREE_KEY_PATH;
1557         return SHELL_ERROR_SUCCESS;
1558 }
1559
1560 /* RegCreateKeyW                [ADVAPI32.132] */
1561 DWORD RegCreateKey32W(
1562         HKEY    hkey,
1563         LPCWSTR lpszSubKey,
1564         LPHKEY  retkey
1565 ) {
1566         DWORD   junk,ret;
1567
1568         dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1569                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1570         );
1571         ret=RegCreateKeyEx32W(
1572                 hkey,           /* key handle */
1573                 lpszSubKey,     /* subkey name */
1574                 0,              /* reserved = 0 */
1575                 NULL,           /* lpszClass? FIXME: ? */
1576                 REG_OPTION_NON_VOLATILE,        /* options */
1577                 KEY_ALL_ACCESS, /* desired access attribs */
1578                 NULL,           /* lpsecurity attributes */
1579                 retkey,         /* lpretkey */
1580                 &junk           /* disposition value */
1581         );
1582         return  ret;
1583 }
1584
1585 /* RegCreateKeyExA              [ADVAPI32.130] */
1586 DWORD RegCreateKeyEx32A(
1587         HKEY    hkey,
1588         LPCSTR  lpszSubKey,
1589         DWORD   dwReserved,
1590         LPSTR   lpszClass,
1591         DWORD   fdwOptions,
1592         REGSAM  samDesired,
1593         LPSECURITY_ATTRIBUTES lpSecAttribs,
1594         LPHKEY  retkey,
1595         LPDWORD lpDispos
1596 ) {
1597         LPWSTR  lpszSubKeyW,lpszClassW;
1598         DWORD   ret;
1599
1600         dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1601                 (LONG)hkey,
1602                 lpszSubKey,
1603                 dwReserved,
1604                 lpszClass,
1605                 fdwOptions,
1606                 samDesired,
1607                 lpSecAttribs,
1608                 retkey,
1609                 lpDispos
1610         );
1611         if (lpszSubKey)
1612                 lpszSubKeyW=strdupA2W(lpszSubKey);
1613         else
1614                 lpszSubKeyW=NULL;
1615         if (lpszClass)
1616                 lpszClassW=strdupA2W(lpszClass);
1617         else
1618                 lpszClassW=NULL;
1619         ret=RegCreateKeyEx32W(
1620                 hkey,
1621                 lpszSubKeyW,
1622                 dwReserved,
1623                 lpszClassW,
1624                 fdwOptions,
1625                 samDesired,
1626                 lpSecAttribs,
1627                 retkey,
1628                 lpDispos
1629         );
1630         if (lpszSubKeyW)
1631                 free(lpszSubKeyW);
1632         if (lpszClassW)
1633                 free(lpszClassW);
1634         return ret;
1635 }
1636
1637 /* RegCreateKeyA                [ADVAPI32.129] */
1638 DWORD RegCreateKey32A(
1639         HKEY    hkey,
1640         LPCSTR  lpszSubKey,
1641         LPHKEY  retkey
1642 ) {
1643         DWORD   junk;
1644
1645         dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1646                 (LONG)hkey,lpszSubKey,retkey
1647         );
1648         return  RegCreateKeyEx32A(
1649                 hkey,           /* key handle */
1650                 lpszSubKey,     /* subkey name */
1651                 0,              /* reserved = 0 */
1652                 NULL,           /* lpszClass? FIXME: ? */
1653                 REG_OPTION_NON_VOLATILE,/* options */
1654                 KEY_ALL_ACCESS, /* desired access attribs */
1655                 NULL,           /* lpsecurity attributes */
1656                 retkey,         /* lpretkey */
1657                 &junk           /* disposition value */
1658         );
1659 }
1660
1661 /* RegCreateKey                 [SHELL.2] [KERNEL.218] */
1662 DWORD RegCreateKey16(
1663         HKEY    hkey,
1664         LPCSTR  lpszSubKey,
1665         LPHKEY  retkey
1666 ) {
1667         dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1668                 (LONG)hkey,lpszSubKey,retkey
1669         );
1670         return RegCreateKey32A(hkey,lpszSubKey,retkey);
1671 }
1672
1673 /* 
1674  * Query Value Functions
1675  * Win32 differs between keynames and valuenames. 
1676  * multiple values may belong to one key, the special value
1677  * with name NULL is the default value used by the win31
1678  * compat functions.
1679  *
1680  * Callpath:
1681  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1682  *                                          RegQueryValue32W -> RegQueryValueEx32W
1683  */
1684
1685 /* RegQueryValueExW             [ADVAPI32.158] */
1686 DWORD RegQueryValueEx32W(
1687         HKEY    hkey,
1688         LPWSTR  lpszValueName,
1689         LPDWORD lpdwReserved,
1690         LPDWORD lpdwType,
1691         LPBYTE  lpbData,
1692         LPDWORD lpcbData
1693 ) {
1694         LPKEYSTRUCT     lpkey;
1695         int             i;
1696
1697         dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1698                 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1699                 lpcbData?*lpcbData:0
1700         );
1701
1702         lpkey   = lookup_hkey(hkey);
1703         if (!lpkey)
1704                 return SHELL_ERROR_BADKEY;
1705         if (lpszValueName==NULL) {
1706                 for (i=0;i<lpkey->nrofvalues;i++)
1707                         if (lpkey->values[i].name==NULL)
1708                                 break;
1709         } else {
1710                 for (i=0;i<lpkey->nrofvalues;i++)
1711                         if (    lpkey->values[i].name &&
1712                                 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1713                         )
1714                                 break;
1715         }
1716         if (i==lpkey->nrofvalues) {
1717                 if (lpszValueName==NULL) {
1718                         if (lpbData) {
1719                                 *(WCHAR*)lpbData = 0;
1720                                 *lpcbData       = 2;
1721                         }
1722                         if (lpdwType)
1723                                 *lpdwType       = REG_SZ;
1724                         return SHELL_ERROR_SUCCESS;
1725                 }
1726                 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1727         }
1728         if (lpdwType)
1729                 *lpdwType       = lpkey->values[i].type;
1730         if (lpbData==NULL) {
1731                 if (lpcbData==NULL)
1732                         return SHELL_ERROR_SUCCESS;
1733                 *lpcbData       = lpkey->values[i].len;
1734                 return SHELL_ERROR_SUCCESS;
1735         }
1736         if (*lpcbData<lpkey->values[i].len) {
1737                 *(WCHAR*)lpbData
1738                         = 0;
1739                 *lpcbData       = lpkey->values[i].len;
1740                 return ERROR_MORE_DATA;
1741         }
1742         memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1743         *lpcbData       = lpkey->values[i].len;
1744         return SHELL_ERROR_SUCCESS;
1745 }
1746
1747 /* RegQueryValueW               [ADVAPI32.159] */
1748 DWORD RegQueryValue32W(
1749         HKEY    hkey,
1750         LPWSTR  lpszSubKey,
1751         LPWSTR  lpszData,
1752         LPDWORD lpcbData
1753 ) {
1754         HKEY    xhkey;
1755         DWORD   ret,lpdwType;
1756
1757         dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1758                 hkey,W2C(lpszSubKey,0),lpszData,
1759                 lpcbData?*lpcbData:0
1760         );
1761
1762         /* only open subkey, if we really do descend */
1763         if (lpszSubKey && *lpszSubKey) {
1764                 ret     = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1765                 if (ret!=ERROR_SUCCESS)
1766                         return ret;
1767         } else
1768                 xhkey   = hkey;
1769
1770         lpdwType        = REG_SZ;
1771         ret     = RegQueryValueEx32W(
1772                 xhkey,
1773                 NULL,           /* varname NULL -> compat */
1774                 NULL,           /* lpdwReserved, must be NULL */
1775                 &lpdwType,
1776                 (LPBYTE)lpszData,
1777                 lpcbData
1778         );
1779         if (xhkey!=hkey)
1780                 RegCloseKey(xhkey);
1781         return ret;
1782 }
1783
1784 /* RegQueryValueExA             [ADVAPI32.157] */
1785 DWORD RegQueryValueEx32A(
1786         HKEY    hkey,
1787         LPSTR   lpszValueName,
1788         LPDWORD lpdwReserved,
1789         LPDWORD lpdwType,
1790         LPBYTE  lpbData,
1791         LPDWORD lpcbData
1792 ) {
1793         LPWSTR  lpszValueNameW;
1794         LPBYTE  buf;
1795         DWORD   ret,myxlen;
1796         DWORD   *mylen;
1797         DWORD   type;
1798
1799         dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
1800                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1801                 lpcbData?*lpcbData:0
1802         );
1803         if (lpbData) {
1804                 /* double buffer */
1805                 buf     = (LPBYTE)xmalloc((*lpcbData)*2);
1806                 myxlen  = *lpcbData*2;
1807                 mylen   = &myxlen;
1808         } else {
1809                 buf=NULL;
1810                 if (lpcbData) {
1811                         myxlen  = *lpcbData*2;
1812                         mylen   = &myxlen;
1813                 } else
1814                         mylen   = NULL;
1815         }
1816         if (lpszValueName)
1817                 lpszValueNameW=strdupA2W(lpszValueName);
1818         else 
1819                 lpszValueNameW=NULL;
1820
1821         if (lpdwType)
1822                 type=*lpdwType;
1823         ret=RegQueryValueEx32W(
1824                 hkey,
1825                 lpszValueNameW,
1826                 lpdwReserved,
1827                 &type,
1828                 buf,
1829                 mylen
1830         );
1831         if (lpdwType) 
1832                 *lpdwType=type;
1833         if (ret==ERROR_SUCCESS) {
1834                 if (buf) {
1835                         if (UNICONVMASK & (1<<(type))) {
1836                                 /* convert UNICODE to ASCII */
1837                                 strcpyWA(lpbData,(LPWSTR)buf);
1838                                 *lpcbData       = myxlen/2;
1839                         } else {
1840                                 if (myxlen>*lpcbData)
1841                                         ret     = ERROR_MORE_DATA;
1842                                 else
1843                                         memcpy(lpbData,buf,myxlen);
1844
1845                                 *lpcbData       = myxlen;
1846                         }
1847                 } else {
1848                         if ((UNICONVMASK & (1<<(type))) && lpcbData)
1849                                 *lpcbData       = myxlen/2;
1850                 }
1851         } else {
1852                 if ((UNICONVMASK & (1<<(type))) && lpcbData)
1853                         *lpcbData       = myxlen/2;
1854         }
1855         if (buf)
1856                 free(buf);
1857         return ret;
1858 }
1859
1860 /* RegQueryValueEx              [KERNEL.225] */
1861 DWORD RegQueryValueEx16(
1862         HKEY    hkey,
1863         LPSTR   lpszValueName,
1864         LPDWORD lpdwReserved,
1865         LPDWORD lpdwType,
1866         LPBYTE  lpbData,
1867         LPDWORD lpcbData
1868 ) {
1869         dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
1870                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1871                 lpcbData?*lpcbData:0
1872         );
1873         return RegQueryValueEx32A(
1874                 hkey,
1875                 lpszValueName,
1876                 lpdwReserved,
1877                 lpdwType,
1878                 lpbData,
1879                 lpcbData
1880         );
1881 }
1882
1883 /* RegQueryValueA               [ADVAPI32.156] */
1884 DWORD RegQueryValue32A(
1885         HKEY    hkey,
1886         LPSTR   lpszSubKey,
1887         LPSTR   lpszData,
1888         LPDWORD lpcbData
1889 ) {
1890         HKEY    xhkey;
1891         DWORD   ret,lpdwType;
1892
1893         dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
1894                 hkey,lpszSubKey,lpszData,
1895                 lpcbData?*lpcbData:0
1896         );
1897
1898         /* only open subkey, if we really do descend */
1899         if (lpszSubKey && *lpszSubKey) {
1900                 ret     = RegOpenKey16(hkey,lpszSubKey,&xhkey);
1901                 if (ret!=ERROR_SUCCESS)
1902                         return ret;
1903         } else
1904                 xhkey   = hkey;
1905
1906         lpdwType        = REG_SZ;
1907         ret     = RegQueryValueEx32A(
1908                 xhkey,
1909                 NULL,           /* lpszValueName NULL -> compat */
1910                 NULL,           /* lpdwReserved, must be NULL */
1911                 &lpdwType,
1912                 (LPBYTE)lpszData,
1913                 lpcbData
1914         );
1915         if (xhkey!=hkey)
1916                 RegCloseKey(xhkey);
1917         return ret;
1918 }
1919
1920 /* RegQueryValue                [SHELL.6] [KERNEL.224] */
1921 DWORD RegQueryValue16(
1922         HKEY    hkey,
1923         LPSTR   lpszSubKey,
1924         LPSTR   lpszData,
1925         LPDWORD lpcbData
1926 ) {
1927         dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
1928                 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
1929         );
1930         /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
1931          *       anyway, so we just mask out the high 16 bit.
1932          *       (this (not so much incidently;) hopefully fixes Aldus FH4)
1933          */
1934         if (lpcbData)
1935                 *lpcbData &= 0xFFFF;
1936         return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
1937 }
1938
1939 /*
1940  * Setting values of Registry keys
1941  *
1942  * Callpath:
1943  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
1944  *                                    RegSetValue32W   -> RegSetValueEx32W
1945  */
1946
1947 /* RegSetValueExW               [ADVAPI32.170] */
1948 DWORD RegSetValueEx32W(
1949         HKEY    hkey,
1950         LPWSTR  lpszValueName,
1951         DWORD   dwReserved,
1952         DWORD   dwType,
1953         LPBYTE  lpbData,
1954         DWORD   cbData
1955 ) {
1956         LPKEYSTRUCT     lpkey;
1957         int             i;
1958
1959         dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
1960                 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
1961         );
1962         /* we no longer care about the lpbData type here... */
1963         lpkey   = lookup_hkey(hkey);
1964         if (!lpkey)
1965                 return SHELL_ERROR_BADKEY;
1966
1967         lpkey->flags |= REG_OPTION_TAINTED;
1968
1969         if (lpszValueName==NULL) {
1970                 for (i=0;i<lpkey->nrofvalues;i++)
1971                         if (lpkey->values[i].name==NULL)
1972                                 break;
1973         } else {
1974                 for (i=0;i<lpkey->nrofvalues;i++)
1975                         if (    lpkey->values[i].name &&
1976                                 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1977                         )
1978                                 break;
1979         }
1980         if (i==lpkey->nrofvalues) {
1981                 lpkey->values = (LPKEYVALUE)xrealloc(
1982                                         lpkey->values,
1983                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
1984                                 );
1985                 lpkey->nrofvalues++;
1986                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
1987         }
1988         if (lpkey->values[i].name==NULL)
1989                 if (lpszValueName)
1990                         lpkey->values[i].name = strdupW(lpszValueName);
1991                 else
1992                         lpkey->values[i].name = NULL;
1993         lpkey->values[i].len    = cbData;
1994         lpkey->values[i].type   = dwType;
1995         if (lpkey->values[i].data !=NULL)
1996                 free(lpkey->values[i].data);
1997         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
1998         lpkey->values[i].lastmodified = time(NULL);
1999         memcpy(lpkey->values[i].data,lpbData,cbData);
2000         return SHELL_ERROR_SUCCESS;
2001 }
2002
2003 /* RegSetValueExA               [ADVAPI32.169] */
2004 DWORD RegSetValueEx32A(
2005         HKEY    hkey,
2006         LPSTR   lpszValueName,
2007         DWORD   dwReserved,
2008         DWORD   dwType,
2009         LPBYTE  lpbData,
2010         DWORD   cbData
2011 ) {
2012         LPBYTE  buf;
2013         LPWSTR  lpszValueNameW;
2014         DWORD   ret;
2015
2016         dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2017                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2018         );
2019         if ((1<<dwType) & UNICONVMASK) {
2020                 buf=(LPBYTE)strdupA2W(lpbData);
2021                 cbData=2*strlen(lpbData)+2;
2022         } else
2023                 buf=lpbData;
2024         if (lpszValueName)
2025                 lpszValueNameW = strdupA2W(lpszValueName);
2026         else
2027                 lpszValueNameW = NULL;
2028         ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2029         if (lpszValueNameW)
2030                 free(lpszValueNameW);
2031         if (buf!=lpbData)
2032                 free(buf);
2033         return ret;
2034 }
2035
2036 /* RegSetValueEx                [KERNEL.226] */
2037 DWORD RegSetValueEx16(
2038         HKEY    hkey,
2039         LPSTR   lpszValueName,
2040         DWORD   dwReserved,
2041         DWORD   dwType,
2042         LPBYTE  lpbData,
2043         DWORD   cbData
2044 ) {
2045         dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2046                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2047         );
2048         return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2049 }
2050
2051 /* RegSetValueW                 [ADVAPI32.171] */
2052 DWORD RegSetValue32W(
2053         HKEY    hkey,
2054         LPCWSTR lpszSubKey,
2055         DWORD   dwType,
2056         LPCWSTR lpszData,
2057         DWORD   cbData
2058 ) {
2059         HKEY    xhkey;
2060         DWORD   ret;
2061
2062         dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2063                 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2064         );
2065         if (lpszSubKey && *lpszSubKey) {
2066                 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2067                 if (ret!=ERROR_SUCCESS)
2068                         return ret;
2069         } else
2070                 xhkey=hkey;
2071         if (dwType!=REG_SZ) {
2072                 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2073                 dwType=REG_SZ;
2074         }
2075         if (cbData!=2*lstrlen32W(lpszData)+2) {
2076                 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2077                         cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2078                 );
2079                 cbData=2*lstrlen32W(lpszData)+2;
2080         }
2081         ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2082         if (hkey!=xhkey)
2083                 RegCloseKey(xhkey);
2084         return ret;
2085
2086 }
2087 /* RegSetValueA                 [ADVAPI32.168] */
2088 DWORD RegSetValue32A(
2089         HKEY    hkey,
2090         LPCSTR  lpszSubKey,
2091         DWORD   dwType,
2092         LPCSTR  lpszData,
2093         DWORD   cbData
2094 ) {
2095         DWORD   ret;
2096         HKEY    xhkey;
2097
2098         dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2099                 hkey,lpszSubKey,dwType,lpszData,cbData
2100         );
2101         if (lpszSubKey && *lpszSubKey) {
2102                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2103                 if (ret!=ERROR_SUCCESS)
2104                         return ret;
2105         } else
2106                 xhkey=hkey;
2107
2108         if (dwType!=REG_SZ) {
2109                 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2110                 dwType=REG_SZ;
2111         }
2112         if (cbData!=strlen(lpszData)+1)
2113                 cbData=strlen(lpszData)+1;
2114         ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2115         if (xhkey!=hkey)
2116                 RegCloseKey(xhkey);
2117         return ret;
2118 }
2119
2120 /* RegSetValue                  [KERNEL.221] [SHELL.5] */
2121 DWORD RegSetValue16(
2122         HKEY    hkey,
2123         LPCSTR  lpszSubKey,
2124         DWORD   dwType,
2125         LPCSTR  lpszData,
2126         DWORD   cbData
2127 ) {
2128         DWORD   ret;
2129         dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2130                 hkey,lpszSubKey,dwType,lpszData,cbData
2131         );
2132         ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2133         return ret;
2134 }
2135
2136 /* 
2137  * Key Enumeration
2138  *
2139  * Callpath:
2140  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2141  *                              RegEnumKey32W   -> RegEnumKeyEx32W
2142  */
2143
2144 /* RegEnumKeyExW                [ADVAPI32.139] */
2145 DWORD RegEnumKeyEx32W(
2146         HKEY    hkey,
2147         DWORD   iSubkey,
2148         LPWSTR  lpszName,
2149         LPDWORD lpcchName,
2150         LPDWORD lpdwReserved,
2151         LPWSTR  lpszClass,
2152         LPDWORD lpcchClass,
2153         FILETIME        *ft
2154 ) {
2155         LPKEYSTRUCT     lpkey,lpxkey;
2156
2157         dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2158                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2159         );
2160         lpkey=lookup_hkey(hkey);
2161         if (!lpkey)
2162                 return SHELL_ERROR_BADKEY;
2163         if (!lpkey->nextsub)
2164                 return ERROR_NO_MORE_ITEMS;
2165         lpxkey=lpkey->nextsub;
2166         while (iSubkey && lpxkey) {
2167                 iSubkey--;
2168                 lpxkey=lpxkey->next;
2169         }
2170         if (iSubkey || !lpxkey)
2171                 return ERROR_NO_MORE_ITEMS;
2172         if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2173                 return ERROR_MORE_DATA;
2174         memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2175         if (lpszClass) {
2176                 /* what should we write into it? */
2177                 *lpszClass              = 0;
2178                 *lpcchClass     = 2;
2179         }
2180         return ERROR_SUCCESS;
2181
2182 }
2183
2184 /* RegEnumKeyW                  [ADVAPI32.140] */
2185 DWORD RegEnumKey32W(
2186         HKEY    hkey,
2187         DWORD   iSubkey,
2188         LPWSTR  lpszName,
2189         DWORD   lpcchName
2190 ) {
2191         FILETIME        ft;
2192
2193         dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2194                 hkey,iSubkey,lpszName,lpcchName
2195         );
2196         return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2197 }
2198 /* RegEnumKeyExA                [ADVAPI32.138] */
2199 DWORD RegEnumKeyEx32A(
2200         HKEY    hkey,
2201         DWORD   iSubkey,
2202         LPSTR   lpszName,
2203         LPDWORD lpcchName,
2204         LPDWORD lpdwReserved,
2205         LPSTR   lpszClass,
2206         LPDWORD lpcchClass,
2207         FILETIME        *ft
2208 ) {
2209         DWORD   ret,lpcchNameW,lpcchClassW;
2210         LPWSTR  lpszNameW,lpszClassW;
2211
2212
2213         dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2214                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2215         );
2216         if (lpszName) {
2217                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
2218                 lpcchNameW      = *lpcchName*2;
2219         } else {
2220                 lpszNameW       = NULL;
2221                 lpcchNameW      = 0;
2222         }
2223         if (lpszClass) {
2224                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
2225                 lpcchClassW     = *lpcchClass*2;
2226         } else {
2227                 lpszClassW      =0;
2228                 lpcchClassW=0;
2229         }
2230         ret=RegEnumKeyEx32W(
2231                 hkey,
2232                 iSubkey,
2233                 lpszNameW,
2234                 &lpcchNameW,
2235                 lpdwReserved,
2236                 lpszClassW,
2237                 &lpcchClassW,
2238                 ft
2239         );
2240         if (ret==ERROR_SUCCESS) {
2241                 strcpyWA(lpszName,lpszNameW);
2242                 *lpcchName=strlen(lpszName);
2243                 if (lpszClassW) {
2244                         strcpyWA(lpszClass,lpszClassW);
2245                         *lpcchClass=strlen(lpszClass);
2246                 }
2247         }
2248         if (lpszNameW)
2249                 free(lpszNameW);
2250         if (lpszClassW)
2251                 free(lpszClassW);
2252         return ret;
2253 }
2254
2255 /* RegEnumKeyA                  [ADVAPI32.137] */
2256 DWORD RegEnumKey32A(
2257         HKEY    hkey,
2258         DWORD   iSubkey,
2259         LPSTR   lpszName,
2260         DWORD   lpcchName
2261 ) {
2262         FILETIME        ft;
2263
2264         dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2265                 hkey,iSubkey,lpszName,lpcchName
2266         );
2267         return  RegEnumKeyEx32A(
2268                 hkey,
2269                 iSubkey,
2270                 lpszName,
2271                 &lpcchName,
2272                 NULL,
2273                 NULL,
2274                 NULL,
2275                 &ft
2276         );
2277 }
2278
2279 /* RegEnumKey                   [SHELL.7] [KERNEL.216] */
2280 DWORD RegEnumKey16(
2281         HKEY    hkey,
2282         DWORD   iSubkey,
2283         LPSTR   lpszName,
2284         DWORD   lpcchName
2285 ) {
2286         dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2287                 hkey,iSubkey,lpszName,lpcchName
2288         );
2289         return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2290 }
2291
2292 /* 
2293  * Enumerate Registry Values
2294  *
2295  * Callpath:
2296  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2297  */
2298
2299 /* RegEnumValueW                [ADVAPI32.142] */
2300 DWORD RegEnumValue32W(
2301         HKEY    hkey,
2302         DWORD   iValue,
2303         LPWSTR  lpszValue,
2304         LPDWORD lpcchValue,
2305         LPDWORD lpdReserved,
2306         LPDWORD lpdwType,
2307         LPBYTE  lpbData,
2308         LPDWORD lpcbData
2309 ) {
2310         LPKEYSTRUCT     lpkey;
2311         LPKEYVALUE      val;
2312
2313         dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2314                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2315         );
2316         lpkey = lookup_hkey(hkey);
2317         if (!lpkey)
2318                 return SHELL_ERROR_BADKEY;
2319         if (lpkey->nrofvalues<=iValue)
2320                 return ERROR_NO_MORE_ITEMS;
2321         val     = lpkey->values+iValue;
2322
2323         if (val->name) {
2324                 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2325                         *lpcchValue = lstrlen32W(val->name)*2+2;
2326                         return ERROR_MORE_DATA;
2327                 }
2328                 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2329                 *lpcchValue=lstrlen32W(val->name)*2+2;
2330         } else {
2331                 /* how to handle NULL value? */
2332                 *lpszValue      = 0;
2333                 *lpcchValue     = 2;
2334         }
2335         *lpdwType=val->type;
2336         if (lpbData) {
2337                 if (val->len>*lpcbData)
2338                         return ERROR_MORE_DATA;
2339                 memcpy(lpbData,val->data,val->len);
2340                 *lpcbData = val->len;
2341         }
2342         return SHELL_ERROR_SUCCESS;
2343 }
2344
2345 /* RegEnumValueA                [ADVAPI32.141] */
2346 DWORD RegEnumValue32A(
2347         HKEY    hkey,
2348         DWORD   iValue,
2349         LPSTR   lpszValue,
2350         LPDWORD lpcchValue,
2351         LPDWORD lpdReserved,
2352         LPDWORD lpdwType,
2353         LPBYTE  lpbData,
2354         LPDWORD lpcbData
2355 ) {
2356         LPWSTR  lpszValueW;
2357         LPBYTE  lpbDataW;
2358         DWORD   ret,lpcbDataW;
2359
2360         dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2361                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2362         );
2363
2364         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2365         if (lpbData) {
2366                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2367                 lpcbDataW = *lpcbData*2;
2368         } else
2369                 lpbDataW = NULL;
2370         ret=RegEnumValue32W(
2371                 hkey,
2372                 iValue,
2373                 lpszValueW,
2374                 lpcchValue,
2375                 lpdReserved,
2376                 lpdwType,
2377                 lpbDataW,
2378                 &lpcbDataW
2379         );
2380
2381         if (ret==ERROR_SUCCESS) {
2382                 strcpyWA(lpszValue,lpszValueW);
2383                 if (lpbData) {
2384                         if ((1<<*lpdwType) & UNICONVMASK) {
2385                                 strcpyWA(lpbData,(LPWSTR)lpbDataW);
2386                         } else {
2387                                 if (lpcbDataW > *lpcbData)
2388                                         ret     = ERROR_MORE_DATA;
2389                                 else
2390                                         memcpy(lpbData,lpbDataW,lpcbDataW);
2391                         }
2392                         *lpcbData = lpcbDataW;
2393                 }
2394         }
2395         if (lpbDataW)
2396                 free(lpbDataW);
2397         if (lpszValueW)
2398                 free(lpszValueW);
2399         return ret;
2400 }
2401
2402 /* RegEnumValue                 [KERNEL.223] */
2403 DWORD RegEnumValue16(
2404         HKEY    hkey,
2405         DWORD   iValue,
2406         LPSTR   lpszValue,
2407         LPDWORD lpcchValue,
2408         LPDWORD lpdReserved,
2409         LPDWORD lpdwType,
2410         LPBYTE  lpbData,
2411         LPDWORD lpcbData
2412 ) {
2413         dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2414                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2415         );
2416         return RegEnumValue32A(
2417                 hkey,
2418                 iValue,
2419                 lpszValue,
2420                 lpcchValue,
2421                 lpdReserved,
2422                 lpdwType,
2423                 lpbData,
2424                 lpcbData
2425         );
2426 }
2427
2428 /* 
2429  *  Close registry key
2430  */
2431 /* RegCloseKey                  [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2432 DWORD RegCloseKey(HKEY hkey) {
2433         dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2434         remove_handle(hkey);
2435         return ERROR_SUCCESS;
2436 }
2437 /* 
2438  * Delete registry key
2439  *
2440  * Callpath:
2441  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2442  */
2443 /* RegDeleteKeyW                [ADVAPI32.134] */
2444 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2445         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
2446         LPWSTR          *wps;
2447         int             wpc,i;
2448
2449         dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2450                 hkey,W2C(lpszSubKey,0)
2451         );
2452         lpNextKey       = lookup_hkey(hkey);
2453         if (!lpNextKey)
2454                 return SHELL_ERROR_BADKEY;
2455         /* we need to know the previous key in the hier. */
2456         if (!lpszSubKey || !*lpszSubKey)
2457                 return SHELL_ERROR_BADKEY;
2458         split_keypath(lpszSubKey,&wps,&wpc);
2459         i       = 0;
2460         lpxkey  = lpNextKey;
2461         while (i<wpc-1) {
2462                 lpxkey=lpNextKey->nextsub;
2463                 while (lpxkey) {
2464                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
2465                                 break;
2466                         lpxkey=lpxkey->next;
2467                 }
2468                 if (!lpxkey) {
2469                         FREE_KEY_PATH;
2470                         /* not found is success */
2471                         return SHELL_ERROR_SUCCESS;
2472                 }
2473                 i++;
2474                 lpNextKey       = lpxkey;
2475         }
2476         lpxkey  = lpNextKey->nextsub;
2477         lplpPrevKey = &(lpNextKey->nextsub);
2478         while (lpxkey) {
2479                 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2480                         break;
2481                 lplpPrevKey     = &(lpxkey->next);
2482                 lpxkey          = lpxkey->next;
2483         }
2484         if (!lpxkey)
2485                 return SHELL_ERROR_SUCCESS;
2486         if (lpxkey->nextsub)
2487                 return SHELL_ERROR_CANTWRITE;
2488         *lplpPrevKey    = lpxkey->next;
2489         free(lpxkey->keyname);
2490         if (lpxkey->class)
2491                 free(lpxkey->class);
2492         if (lpxkey->values)
2493                 free(lpxkey->values);
2494         free(lpxkey);
2495         FREE_KEY_PATH;
2496         return  SHELL_ERROR_SUCCESS;
2497 }
2498
2499 /* RegDeleteKeyA                [ADVAPI32.133] */
2500 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2501         LPWSTR  lpszSubKeyW;
2502         DWORD   ret;
2503
2504         dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2505                 hkey,lpszSubKey
2506         );
2507         lpszSubKeyW=strdupA2W(lpszSubKey);
2508         ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2509         free(lpszSubKeyW);
2510         return ret;
2511 }
2512
2513 /* RegDeleteKey                 [SHELL.4] [KERNEL.219] */
2514 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2515         dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2516                 hkey,lpszSubKey
2517         );
2518         return RegDeleteKey32A(hkey,lpszSubKey);
2519 }
2520
2521 /* 
2522  * Delete registry value
2523  *
2524  * Callpath:
2525  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2526  */
2527 /* RegDeleteValueW              [ADVAPI32.136] */
2528 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2529         DWORD           i;
2530         LPKEYSTRUCT     lpkey;
2531         LPKEYVALUE      val;
2532
2533         dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2534                 hkey,W2C(lpszValue,0)
2535         );
2536         lpkey=lookup_hkey(hkey);
2537         if (!lpkey)
2538                 return SHELL_ERROR_BADKEY;
2539         if (lpszValue) {
2540                 for (i=0;i<lpkey->nrofvalues;i++)
2541                         if (    lpkey->values[i].name &&
2542                                 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2543                         )
2544                                 break;
2545         } else {
2546                 for (i=0;i<lpkey->nrofvalues;i++)
2547                         if (lpkey->values[i].name==NULL)
2548                                 break;
2549         }
2550         if (i==lpkey->nrofvalues)
2551                 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2552         val     = lpkey->values+i;
2553         if (val->name) free(val->name);
2554         if (val->data) free(val->data);
2555         memcpy( 
2556                 lpkey->values+i,
2557                 lpkey->values+i+1,
2558                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2559         );
2560         lpkey->values   = (LPKEYVALUE)xrealloc(
2561                                 lpkey->values,
2562                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2563                         );
2564         lpkey->nrofvalues--;
2565         return SHELL_ERROR_SUCCESS;
2566 }
2567
2568 /* RegDeleteValueA              [ADVAPI32.135] */
2569 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2570         LPWSTR  lpszValueW;
2571         DWORD   ret;
2572
2573         dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2574         if (lpszValue)
2575                 lpszValueW=strdupA2W(lpszValue);
2576         else
2577                 lpszValueW=NULL;
2578         ret=RegDeleteValue32W(hkey,lpszValueW);
2579         if (lpszValueW)
2580                 free(lpszValueW);
2581         return ret;
2582 }
2583
2584 /* RegDeleteValue               [KERNEL.222] */
2585 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2586         dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2587         return RegDeleteValue32A(hkey,lpszValue);
2588 }
2589
2590 /* RegFlushKey                  [ADVAPI32.143] [KERNEL.227] */
2591 DWORD RegFlushKey(HKEY hkey) {
2592         dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2593         return SHELL_ERROR_SUCCESS;
2594 }
2595
2596 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2597
2598 /* RegQueryInfoKeyW             [ADVAPI32.153] */
2599 DWORD RegQueryInfoKey32W(
2600         HKEY    hkey,
2601         LPWSTR  lpszClass,
2602         LPDWORD lpcchClass,
2603         LPDWORD lpdwReserved,
2604         LPDWORD lpcSubKeys,
2605         LPDWORD lpcchMaxSubkey,
2606         LPDWORD lpcchMaxClass,
2607         LPDWORD lpcValues,
2608         LPDWORD lpcchMaxValueName,
2609         LPDWORD lpccbMaxValueData,
2610         LPDWORD lpcbSecurityDescriptor,
2611         FILETIME        *ft
2612 ) {
2613         LPKEYSTRUCT     lpkey,lpxkey;
2614         int             nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2615         int             i;
2616
2617         dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2618         lpkey=lookup_hkey(hkey);
2619         if (!lpkey)
2620                 return SHELL_ERROR_BADKEY;
2621         if (lpszClass) {
2622                 if (lpkey->class) {
2623                         if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2624                                 *lpcchClass=lstrlen32W(lpkey->class)*2;
2625                                 return ERROR_MORE_DATA;
2626                         }
2627                         *lpcchClass=lstrlen32W(lpkey->class)*2;
2628                         memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2629                 } else {
2630                         *lpszClass      = 0;
2631                         *lpcchClass     = 0;
2632                 }
2633         } else {
2634                 if (lpcchClass)
2635                         *lpcchClass     = lstrlen32W(lpkey->class)*2;
2636         }
2637         lpxkey=lpkey->nextsub;
2638         nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2639         while (lpxkey) {
2640                 nrofkeys++;
2641                 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2642                         maxsubkey=lstrlen32W(lpxkey->keyname);
2643                 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2644                         maxclass=lstrlen32W(lpxkey->class);
2645                 if (lpxkey->nrofvalues>maxvalues)
2646                         maxvalues=lpxkey->nrofvalues;
2647                 for (i=0;i<lpxkey->nrofvalues;i++) {
2648                         LPKEYVALUE      val=lpxkey->values+i;
2649
2650                         if (val->name && lstrlen32W(val->name)>maxvname)
2651                                 maxvname=lstrlen32W(val->name);
2652                         if (val->len>maxvdata)
2653                                 maxvdata=val->len;
2654                 }
2655                 lpxkey=lpxkey->next;
2656         }
2657         if (!maxclass) maxclass = 1;
2658         if (!maxvname) maxvname = 1;
2659         if (lpcSubKeys)
2660                 *lpcSubKeys     = nrofkeys;
2661         if (lpcchMaxSubkey)
2662                 *lpcchMaxSubkey = maxsubkey*2;
2663         if (lpcchMaxClass)
2664                 *lpcchMaxClass  = maxclass*2;
2665         if (lpcValues)
2666                 *lpcValues      = maxvalues;
2667         if (lpcchMaxValueName)
2668                 *lpcchMaxValueName= maxvname;
2669         if (lpccbMaxValueData)
2670                 *lpccbMaxValueData= maxvdata;
2671         return SHELL_ERROR_SUCCESS;
2672 }
2673
2674 /* RegQueryInfoKeyA             [ADVAPI32.152] */
2675 DWORD RegQueryInfoKey32A(
2676         HKEY    hkey,
2677         LPSTR   lpszClass,
2678         LPDWORD lpcchClass,
2679         LPDWORD lpdwReserved,
2680         LPDWORD lpcSubKeys,
2681         LPDWORD lpcchMaxSubkey,
2682         LPDWORD lpcchMaxClass,
2683         LPDWORD lpcValues,
2684         LPDWORD lpcchMaxValueName,
2685         LPDWORD lpccbMaxValueData,
2686         LPDWORD lpcbSecurityDescriptor,
2687         FILETIME        *ft
2688 ) {
2689         LPWSTR          lpszClassW;
2690         DWORD           ret;
2691
2692         dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2693         if (lpszClass) {
2694                 *lpcchClass*= 2;
2695                 lpszClassW  = (LPWSTR)xmalloc(*lpcchClass);
2696
2697         } else
2698                 lpszClassW  = NULL;
2699         ret=RegQueryInfoKey32W(
2700                 hkey,
2701                 lpszClassW,
2702                 lpcchClass,
2703                 lpdwReserved,
2704                 lpcSubKeys,
2705                 lpcchMaxSubkey,
2706                 lpcchMaxClass,
2707                 lpcValues,
2708                 lpcchMaxValueName,
2709                 lpccbMaxValueData,
2710                 lpcbSecurityDescriptor,
2711                 ft
2712         );
2713         if (ret==ERROR_SUCCESS)
2714                 strcpyWA(lpszClass,lpszClassW);
2715         if (lpcchClass)
2716                 *lpcchClass/=2;
2717         if (lpcchMaxSubkey)
2718                 *lpcchMaxSubkey/=2;
2719         if (lpcchMaxClass)
2720                 *lpcchMaxClass/=2;
2721         if (lpcchMaxValueName)
2722                 *lpcchMaxValueName/=2;
2723         if (lpszClassW)
2724                 free(lpszClassW);
2725         return ret;
2726 }