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