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