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