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