Release 960913
[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!=FILE_Read(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!=FILE_Read(hfd,&version,4))
1116                 return;
1117         if (4!=FILE_Read(hfd,&rgdbsection,4))
1118                 return;
1119         if (-1==_llseek(hfd,0x20,SEEK_SET))
1120                 return;
1121         if (4!=FILE_Read(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)!=FILE_Read(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]),_w95dkecomp);
1208
1209         /* STEP 2: keydata & values */
1210         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1211                 return;
1212         end             = hfdinfo.nFileSizeLow;
1213         lastmodified    = FileTimeToUnixTime(&(hfdinfo.ftLastWriteTime));
1214
1215         if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1216                 return;
1217         data = (char*)xmalloc(end-rgdbsection);
1218         if ((end-rgdbsection)!=FILE_Read(hfd,data,end-rgdbsection))
1219                 return;
1220         _lclose(hfd);
1221         curdata = data;
1222         memcpy(magic,curdata,4);
1223         memcpy(&off_next_rgdb,curdata+4,4);
1224         nextrgdb = curdata+off_next_rgdb;
1225         if (strcmp(magic,"RGDB")) {
1226                 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1227                 return;
1228         }
1229         curdata=data+0x20;
1230         while (1) {
1231                 struct  dkh dkh;
1232                 int     bytesread;
1233                 struct  _w95key *key,xkey;
1234
1235                 bytesread = 0;
1236                 if (curdata>=nextrgdb) {
1237                         curdata = nextrgdb;
1238                         if (!strncmp(curdata,"RGDB",4)) {
1239                                 memcpy(&off_next_rgdb,curdata+4,4);
1240                                 nextrgdb = curdata+off_next_rgdb;
1241                                 curdata+=0x20;
1242                         } else {
1243                                 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1244                                 break;
1245                         }
1246                 }
1247 #define XREAD(whereto,len) \
1248         if ((curdata-data+len)<end) {\
1249                 memcpy(whereto,curdata,len);\
1250                 curdata+=len;\
1251                 bytesread+=len;\
1252         }
1253
1254                 XREAD(&dkh,sizeof(dkh));
1255                 nr = dkh.nrLS + (dkh.nrMS<<8);
1256                 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1257                         if (dkh.nrLS == 0xFFFF) {
1258                                 /* skip over key using nextkeyoff */
1259                                 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1260                                 continue;
1261                         }
1262                         dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1263                         key = &xkey;
1264                         memset(key,'\0',sizeof(xkey));
1265                 } else {
1266                         key = keys+nr;
1267                         if (!key->dkeaddr)
1268                                 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1269                 }
1270                 key->nrofvals   = dkh.values;
1271                 key->name       = (char*)xmalloc(dkh.keynamelen+1);
1272                 key->xx1        = dkh.xx1;
1273                 XREAD(key->name,dkh.keynamelen);
1274                 key->name[dkh.keynamelen]=0;
1275                 if (key->nrofvals) {
1276                         key->values = (struct _w95keyvalue*)xmalloc(
1277                                 sizeof(struct _w95keyvalue)*key->nrofvals
1278                         );
1279                         for (i=0;i<key->nrofvals;i++) {
1280                                 struct  dkv     dkv;
1281
1282                                 XREAD(&dkv,sizeof(dkv));
1283                                 key->values[i].type = dkv.type;
1284                                 key->values[i].name = (char*)xmalloc(
1285                                         dkv.valnamelen+1
1286                                 );
1287                                 key->values[i].datalen = dkv.valdatalen;
1288                                 key->values[i].data = (unsigned char*)xmalloc(
1289                                         dkv.valdatalen+1
1290                                 );
1291                                 key->values[i].x1   = dkv.x1;
1292                                 XREAD(key->values[i].name,dkv.valnamelen);
1293                                 XREAD(key->values[i].data,dkv.valdatalen);
1294                                 key->values[i].data[dkv.valdatalen]=0;
1295                                 key->values[i].name[dkv.valnamelen]=0;
1296                                 key->values[i].lastmodified=lastmodified;
1297                         }
1298                 }
1299                 if (bytesread != dkh.nextkeyoff) {
1300                         if (dkh.bytesused != bytesread)
1301                                 dprintf_reg(stddeb,
1302                                         "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1303                                         dkh.bytesused
1304                                 );
1305                         curdata += dkh.nextkeyoff-bytesread;
1306                 }
1307                 key->prevlvl    = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1308                 key->nextsub    = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1309                 key->next       = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1310                 if (!bytesread)
1311                         break;
1312         }
1313         free(data);
1314         _w95_walk_tree(lpkey,keys);
1315         free(keys);
1316 }
1317
1318 void
1319 SHELL_LoadRegistry() {
1320         char    *fn;
1321         struct  passwd  *pwd;
1322         LPKEYSTRUCT     lpkey;
1323         HKEY            hkey;
1324
1325
1326         if (key_classes_root==NULL)
1327                 SHELL_Init();
1328
1329         /* Load windows 95 entries */
1330         _w95_loadreg("C:\\system.1st",  key_local_machine);
1331         _w95_loadreg("system.dat",      key_local_machine);
1332         _w95_loadreg("user.dat",        key_users);
1333
1334         /* FIXME: win3.1 reg.dat loader still missing */
1335
1336         /* the global user default is loaded under HKEY_USERS\\.Default */
1337         RegCreateKey16(HKEY_USERS,".Default",&hkey);
1338         lpkey = lookup_hkey(hkey);
1339         _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1340
1341         /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1342         _copy_registry(lpkey,key_current_user);
1343         RegCloseKey(hkey);
1344
1345         /* the global machine defaults */
1346         _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1347
1348         /* load the user saved registries */
1349
1350         /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1351
1352         pwd=getpwuid(getuid());
1353         if (pwd!=NULL && pwd->pw_dir!=NULL) {
1354                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1355                 strcpy(fn,pwd->pw_dir);
1356                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1357                 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1358                 free(fn);
1359                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1360                 strcpy(fn,pwd->pw_dir);
1361                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1362                 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1363                 free(fn);
1364         } else
1365                 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1366         if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1367                 DWORD   junk,type,len;
1368                 char    data[5];
1369
1370                 len=4;
1371                 if ((   RegQueryValueEx32A(
1372                                 hkey,
1373                                 VAL_SAVEUPDATED,
1374                                 &junk,
1375                                 &type,
1376                                 data,
1377                                 &len
1378                         )!=ERROR_SUCCESS) ||
1379                         type != REG_SZ
1380                 )
1381                         RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1382                 RegCloseKey(hkey);
1383         }
1384 }
1385
1386
1387 /********************* API FUNCTIONS ***************************************/
1388 /*
1389  * Open Keys.
1390  *
1391  * All functions are stubs to RegOpenKeyEx32W where all the
1392  * magic happens. 
1393  *
1394  * FIXME: security,options,desiredaccess,...
1395  *
1396  * Callpath:
1397  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1398  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
1399  */
1400
1401 /* RegOpenKeyExW                [ADVAPI32.150] */
1402 DWORD RegOpenKeyEx32W(
1403         HKEY    hkey,
1404         LPCWSTR lpszSubKey,
1405         DWORD   dwReserved,
1406         REGSAM  samDesired,
1407         LPHKEY  retkey
1408 ) {
1409         LPKEYSTRUCT     lpNextKey,lpxkey;
1410         LPWSTR          *wps;
1411         int             wpc,i;
1412         dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1413                 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1414         );
1415
1416         lpNextKey       = lookup_hkey(hkey);
1417         if (!lpNextKey)
1418                 return SHELL_ERROR_BADKEY;
1419         if (!lpszSubKey || !*lpszSubKey) {
1420                 add_handle(++currenthandle,lpNextKey,samDesired);
1421                 *retkey=currenthandle;
1422                 return SHELL_ERROR_SUCCESS;
1423         }
1424         split_keypath(lpszSubKey,&wps,&wpc);
1425         i       = 0;
1426         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1427         lpxkey  = lpNextKey;
1428         while (i<wpc) {
1429                 lpxkey=lpNextKey->nextsub;
1430                 while (lpxkey) {
1431                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
1432                                 break;
1433                         lpxkey=lpxkey->next;
1434                 }
1435                 if (!lpxkey) {
1436                         FREE_KEY_PATH;
1437                         return SHELL_ERROR_BADKEY;
1438                 }
1439                 i++;
1440                 lpNextKey       = lpxkey;
1441         }
1442         add_handle(++currenthandle,lpxkey,samDesired);
1443         *retkey = currenthandle;
1444         FREE_KEY_PATH;
1445         return  SHELL_ERROR_SUCCESS;
1446 }
1447
1448 /* RegOpenKeyW                  [ADVAPI32.151] */
1449 DWORD RegOpenKey32W(
1450         HKEY    hkey,
1451         LPCWSTR lpszSubKey,
1452         LPHKEY  retkey
1453 ) {
1454         dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1455                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1456         );
1457         return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1458 }
1459
1460
1461 /* RegOpenKeyExA                [ADVAPI32.149] */
1462 DWORD RegOpenKeyEx32A(
1463         HKEY    hkey,
1464         LPCSTR  lpszSubKey,
1465         DWORD   dwReserved,
1466         REGSAM  samDesired,
1467         LPHKEY  retkey
1468 ) {
1469         LPWSTR  lpszSubKeyW;
1470         DWORD   ret;
1471
1472         dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1473                 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1474         );
1475         if (lpszSubKey)
1476                 lpszSubKeyW=strdupA2W(lpszSubKey);
1477         else
1478                 lpszSubKeyW=NULL;
1479         ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1480         if (lpszSubKeyW)
1481                 free(lpszSubKeyW);
1482         return ret;
1483 }
1484
1485 /* RegOpenKeyA                  [ADVAPI32.148] */
1486 DWORD RegOpenKey32A(
1487         HKEY    hkey,
1488         LPCSTR  lpszSubKey,
1489         LPHKEY  retkey
1490 ) {
1491         dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1492                 (LONG)hkey,lpszSubKey,retkey
1493         );
1494         return  RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1495 }
1496
1497 /* RegOpenKey                   [SHELL.1] [KERNEL.217] */
1498 DWORD RegOpenKey16(
1499         HKEY    hkey,
1500         LPCSTR  lpszSubKey,
1501         LPHKEY  retkey
1502 ) {
1503         dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1504                 (LONG)hkey,lpszSubKey,retkey
1505         );
1506         return RegOpenKey32A(hkey,lpszSubKey,retkey);
1507 }
1508
1509 /* 
1510  * Create keys
1511  * 
1512  * All those functions convert their respective 
1513  * arguments and call RegCreateKeyExW at the end.
1514  *
1515  * FIXME: no security,no access attrib,no optionhandling yet.
1516  *
1517  * Callpath:
1518  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1519  *                                      RegCreateKey32W   -> RegCreateKeyEx32W
1520  */
1521
1522 /* RegCreateKeyExW              [ADVAPI32.131] */
1523 DWORD RegCreateKeyEx32W(
1524         HKEY    hkey,
1525         LPCWSTR lpszSubKey,
1526         DWORD   dwReserved,
1527         LPWSTR  lpszClass,
1528         DWORD   fdwOptions,
1529         REGSAM  samDesired,
1530         LPSECURITY_ATTRIBUTES lpSecAttribs,
1531         LPHKEY  retkey,
1532         LPDWORD lpDispos
1533 ) {
1534         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1535         LPWSTR          *wps;
1536         int             wpc,i;
1537
1538 /*FIXME: handle security/access/whatever */
1539         dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1540                 (LONG)hkey,
1541                 W2C(lpszSubKey,0),
1542                 dwReserved,
1543                 W2C(lpszClass,1),
1544                 fdwOptions,
1545                 samDesired,
1546                 lpSecAttribs,
1547                 retkey,
1548                 lpDispos
1549         );
1550
1551         lpNextKey       = lookup_hkey(hkey);
1552         if (!lpNextKey)
1553                 return SHELL_ERROR_BADKEY;
1554         if (!lpszSubKey || !*lpszSubKey) {
1555                 add_handle(++currenthandle,lpNextKey,samDesired);
1556                 *retkey=currenthandle;
1557                 return SHELL_ERROR_SUCCESS;
1558         }
1559         split_keypath(lpszSubKey,&wps,&wpc);
1560         i       = 0;
1561         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1562         lpxkey  = lpNextKey;
1563         while (i<wpc) {
1564                 lpxkey=lpNextKey->nextsub;
1565                 while (lpxkey) {
1566                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
1567                                 break;
1568                         lpxkey=lpxkey->next;
1569                 }
1570                 if (!lpxkey)
1571                         break;
1572                 i++;
1573                 lpNextKey       = lpxkey;
1574         }
1575         if (lpxkey) {
1576                 add_handle(++currenthandle,lpxkey,samDesired);
1577                 *retkey         = currenthandle;
1578                 *lpDispos       = REG_OPENED_EXISTING_KEY;
1579                 FREE_KEY_PATH;
1580                 return  SHELL_ERROR_SUCCESS;
1581         }
1582         /* good. now the hard part */
1583         while (i<wpc) {
1584                 lplpPrevKey     = &(lpNextKey->nextsub);
1585                 lpxkey          = *lplpPrevKey;
1586                 while (lpxkey) {
1587                         lplpPrevKey     = &(lpxkey->next);
1588                         lpxkey          = *lplpPrevKey;
1589                 }
1590                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1591                 if (!*lplpPrevKey) {
1592                         FREE_KEY_PATH;
1593                         return SHELL_ERROR_OUTOFMEMORY;
1594                 }
1595                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1596                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1597                 (*lplpPrevKey)->next    = NULL;
1598                 (*lplpPrevKey)->nextsub = NULL;
1599                 (*lplpPrevKey)->values  = NULL;
1600                 (*lplpPrevKey)->nrofvalues = 0;
1601                 if (lpszClass)
1602                         (*lplpPrevKey)->class = strdupW(lpszClass);
1603                 else
1604                         (*lplpPrevKey)->class = NULL;
1605                 lpNextKey       = *lplpPrevKey;
1606                 i++;
1607         }
1608         add_handle(++currenthandle,lpNextKey,samDesired);
1609
1610         /*FIXME: flag handling correct? */
1611         lpNextKey->flags= fdwOptions;
1612         if (lpszClass)
1613                 lpNextKey->class = strdupW(lpszClass);
1614         else
1615                 lpNextKey->class = NULL;
1616         lpNextKey->flags|=REG_OPTION_TAINTED;
1617         *retkey         = currenthandle;
1618         *lpDispos       = REG_CREATED_NEW_KEY;
1619         FREE_KEY_PATH;
1620         return SHELL_ERROR_SUCCESS;
1621 }
1622
1623 /* RegCreateKeyW                [ADVAPI32.132] */
1624 DWORD RegCreateKey32W(
1625         HKEY    hkey,
1626         LPCWSTR lpszSubKey,
1627         LPHKEY  retkey
1628 ) {
1629         DWORD   junk,ret;
1630
1631         dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1632                 (LONG)hkey,W2C(lpszSubKey,0),retkey
1633         );
1634         ret=RegCreateKeyEx32W(
1635                 hkey,           /* key handle */
1636                 lpszSubKey,     /* subkey name */
1637                 0,              /* reserved = 0 */
1638                 NULL,           /* lpszClass? FIXME: ? */
1639                 REG_OPTION_NON_VOLATILE,        /* options */
1640                 KEY_ALL_ACCESS, /* desired access attribs */
1641                 NULL,           /* lpsecurity attributes */
1642                 retkey,         /* lpretkey */
1643                 &junk           /* disposition value */
1644         );
1645         return  ret;
1646 }
1647
1648 /* RegCreateKeyExA              [ADVAPI32.130] */
1649 DWORD RegCreateKeyEx32A(
1650         HKEY    hkey,
1651         LPCSTR  lpszSubKey,
1652         DWORD   dwReserved,
1653         LPSTR   lpszClass,
1654         DWORD   fdwOptions,
1655         REGSAM  samDesired,
1656         LPSECURITY_ATTRIBUTES lpSecAttribs,
1657         LPHKEY  retkey,
1658         LPDWORD lpDispos
1659 ) {
1660         LPWSTR  lpszSubKeyW,lpszClassW;
1661         DWORD   ret;
1662
1663         dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1664                 (LONG)hkey,
1665                 lpszSubKey,
1666                 dwReserved,
1667                 lpszClass,
1668                 fdwOptions,
1669                 samDesired,
1670                 lpSecAttribs,
1671                 retkey,
1672                 lpDispos
1673         );
1674         if (lpszSubKey)
1675                 lpszSubKeyW=strdupA2W(lpszSubKey);
1676         else
1677                 lpszSubKeyW=NULL;
1678         if (lpszClass)
1679                 lpszClassW=strdupA2W(lpszClass);
1680         else
1681                 lpszClassW=NULL;
1682         ret=RegCreateKeyEx32W(
1683                 hkey,
1684                 lpszSubKeyW,
1685                 dwReserved,
1686                 lpszClassW,
1687                 fdwOptions,
1688                 samDesired,
1689                 lpSecAttribs,
1690                 retkey,
1691                 lpDispos
1692         );
1693         if (lpszSubKeyW)
1694                 free(lpszSubKeyW);
1695         if (lpszClassW)
1696                 free(lpszClassW);
1697         return ret;
1698 }
1699
1700 /* RegCreateKeyA                [ADVAPI32.129] */
1701 DWORD RegCreateKey32A(
1702         HKEY    hkey,
1703         LPCSTR  lpszSubKey,
1704         LPHKEY  retkey
1705 ) {
1706         DWORD   junk;
1707
1708         dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1709                 (LONG)hkey,lpszSubKey,retkey
1710         );
1711         return  RegCreateKeyEx32A(
1712                 hkey,           /* key handle */
1713                 lpszSubKey,     /* subkey name */
1714                 0,              /* reserved = 0 */
1715                 NULL,           /* lpszClass? FIXME: ? */
1716                 REG_OPTION_NON_VOLATILE,/* options */
1717                 KEY_ALL_ACCESS, /* desired access attribs */
1718                 NULL,           /* lpsecurity attributes */
1719                 retkey,         /* lpretkey */
1720                 &junk           /* disposition value */
1721         );
1722 }
1723
1724 /* RegCreateKey                 [SHELL.2] [KERNEL.218] */
1725 DWORD RegCreateKey16(
1726         HKEY    hkey,
1727         LPCSTR  lpszSubKey,
1728         LPHKEY  retkey
1729 ) {
1730         dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1731                 (LONG)hkey,lpszSubKey,retkey
1732         );
1733         return RegCreateKey32A(hkey,lpszSubKey,retkey);
1734 }
1735
1736 /* 
1737  * Query Value Functions
1738  * Win32 differs between keynames and valuenames. 
1739  * multiple values may belong to one key, the special value
1740  * with name NULL is the default value used by the win31
1741  * compat functions.
1742  *
1743  * Callpath:
1744  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1745  *                                          RegQueryValue32W -> RegQueryValueEx32W
1746  */
1747
1748 /* RegQueryValueExW             [ADVAPI32.158] */
1749 DWORD RegQueryValueEx32W(
1750         HKEY    hkey,
1751         LPWSTR  lpszValueName,
1752         LPDWORD lpdwReserved,
1753         LPDWORD lpdwType,
1754         LPBYTE  lpbData,
1755         LPDWORD lpcbData
1756 ) {
1757         LPKEYSTRUCT     lpkey;
1758         int             i;
1759
1760         dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1761                 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1762                 lpcbData?*lpcbData:0
1763         );
1764
1765         lpkey   = lookup_hkey(hkey);
1766         if (!lpkey)
1767                 return SHELL_ERROR_BADKEY;
1768         if (lpszValueName==NULL) {
1769                 for (i=0;i<lpkey->nrofvalues;i++)
1770                         if (lpkey->values[i].name==NULL)
1771                                 break;
1772         } else {
1773                 for (i=0;i<lpkey->nrofvalues;i++)
1774                         if (    lpkey->values[i].name &&
1775                                 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
1776                         )
1777                                 break;
1778         }
1779         if (i==lpkey->nrofvalues) {
1780                 if (lpszValueName==NULL) {
1781                         if (lpbData) {
1782                                 *(WCHAR*)lpbData = 0;
1783                                 *lpcbData       = 2;
1784                         }
1785                         if (lpdwType)
1786                                 *lpdwType       = REG_SZ;
1787                         return SHELL_ERROR_SUCCESS;
1788                 }
1789                 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1790         }
1791         if (lpdwType)
1792                 *lpdwType       = lpkey->values[i].type;
1793         if (lpbData==NULL) {
1794                 if (lpcbData==NULL)
1795                         return SHELL_ERROR_SUCCESS;
1796                 *lpcbData       = lpkey->values[i].len;
1797                 return SHELL_ERROR_SUCCESS;
1798         }
1799         if (*lpcbData<lpkey->values[i].len) {
1800                 *(WCHAR*)lpbData
1801                         = 0;
1802                 *lpcbData       = lpkey->values[i].len;
1803                 return ERROR_MORE_DATA;
1804         }
1805         memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1806         *lpcbData       = lpkey->values[i].len;
1807         return SHELL_ERROR_SUCCESS;
1808 }
1809
1810 /* RegQueryValueW               [ADVAPI32.159] */
1811 DWORD RegQueryValue32W(
1812         HKEY    hkey,
1813         LPWSTR  lpszSubKey,
1814         LPWSTR  lpszData,
1815         LPDWORD lpcbData
1816 ) {
1817         HKEY    xhkey;
1818         DWORD   ret,lpdwType;
1819
1820         dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1821                 hkey,W2C(lpszSubKey,0),lpszData,
1822                 lpcbData?*lpcbData:0
1823         );
1824
1825         /* only open subkey, if we really do descend */
1826         if (lpszSubKey && *lpszSubKey) {
1827                 ret     = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1828                 if (ret!=ERROR_SUCCESS)
1829                         return ret;
1830         } else
1831                 xhkey   = hkey;
1832
1833         lpdwType        = REG_SZ;
1834         ret     = RegQueryValueEx32W(
1835                 xhkey,
1836                 NULL,           /* varname NULL -> compat */
1837                 NULL,           /* lpdwReserved, must be NULL */
1838                 &lpdwType,
1839                 (LPBYTE)lpszData,
1840                 lpcbData
1841         );
1842         if (xhkey!=hkey)
1843                 RegCloseKey(xhkey);
1844         return ret;
1845 }
1846
1847 /* RegQueryValueExA             [ADVAPI32.157] */
1848 DWORD RegQueryValueEx32A(
1849         HKEY    hkey,
1850         LPSTR   lpszValueName,
1851         LPDWORD lpdwReserved,
1852         LPDWORD lpdwType,
1853         LPBYTE  lpbData,
1854         LPDWORD lpcbData
1855 ) {
1856         LPWSTR  lpszValueNameW;
1857         LPBYTE  buf;
1858         DWORD   ret,myxlen;
1859         DWORD   *mylen;
1860         DWORD   type;
1861
1862         dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
1863                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1864                 lpcbData?*lpcbData:0
1865         );
1866         if (lpbData) {
1867                 /* double buffer */
1868                 buf     = (LPBYTE)xmalloc((*lpcbData)*2);
1869                 myxlen  = *lpcbData*2;
1870                 mylen   = &myxlen;
1871         } else {
1872                 buf=NULL;
1873                 if (lpcbData) {
1874                         myxlen  = *lpcbData*2;
1875                         mylen   = &myxlen;
1876                 } else
1877                         mylen   = NULL;
1878         }
1879         if (lpszValueName)
1880                 lpszValueNameW=strdupA2W(lpszValueName);
1881         else 
1882                 lpszValueNameW=NULL;
1883
1884         if (lpdwType)
1885                 type=*lpdwType;
1886         ret=RegQueryValueEx32W(
1887                 hkey,
1888                 lpszValueNameW,
1889                 lpdwReserved,
1890                 &type,
1891                 buf,
1892                 mylen
1893         );
1894         if (lpdwType) 
1895                 *lpdwType=type;
1896         if (ret==ERROR_SUCCESS) {
1897                 if (buf) {
1898                         if (UNICONVMASK & (1<<(type))) {
1899                                 /* convert UNICODE to ASCII */
1900                                 strcpyWA(lpbData,(LPWSTR)buf);
1901                                 *lpcbData       = myxlen/2;
1902                         } else {
1903                                 if (myxlen>*lpcbData)
1904                                         ret     = ERROR_MORE_DATA;
1905                                 else
1906                                         memcpy(lpbData,buf,myxlen);
1907
1908                                 *lpcbData       = myxlen;
1909                         }
1910                 } else {
1911                         if ((UNICONVMASK & (1<<(type))) && lpcbData)
1912                                 *lpcbData       = myxlen/2;
1913                 }
1914         } else {
1915                 if ((UNICONVMASK & (1<<(type))) && lpcbData)
1916                         *lpcbData       = myxlen/2;
1917         }
1918         if (buf)
1919                 free(buf);
1920         return ret;
1921 }
1922
1923 /* RegQueryValueEx              [KERNEL.225] */
1924 DWORD RegQueryValueEx16(
1925         HKEY    hkey,
1926         LPSTR   lpszValueName,
1927         LPDWORD lpdwReserved,
1928         LPDWORD lpdwType,
1929         LPBYTE  lpbData,
1930         LPDWORD lpcbData
1931 ) {
1932         dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
1933                 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1934                 lpcbData?*lpcbData:0
1935         );
1936         return RegQueryValueEx32A(
1937                 hkey,
1938                 lpszValueName,
1939                 lpdwReserved,
1940                 lpdwType,
1941                 lpbData,
1942                 lpcbData
1943         );
1944 }
1945
1946 /* RegQueryValueA               [ADVAPI32.156] */
1947 DWORD RegQueryValue32A(
1948         HKEY    hkey,
1949         LPSTR   lpszSubKey,
1950         LPSTR   lpszData,
1951         LPDWORD lpcbData
1952 ) {
1953         HKEY    xhkey;
1954         DWORD   ret,lpdwType;
1955
1956         dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
1957                 hkey,lpszSubKey,lpszData,
1958                 lpcbData?*lpcbData:0
1959         );
1960
1961         /* only open subkey, if we really do descend */
1962         if (lpszSubKey && *lpszSubKey) {
1963                 ret     = RegOpenKey16(hkey,lpszSubKey,&xhkey);
1964                 if (ret!=ERROR_SUCCESS)
1965                         return ret;
1966         } else
1967                 xhkey   = hkey;
1968
1969         lpdwType        = REG_SZ;
1970         ret     = RegQueryValueEx32A(
1971                 xhkey,
1972                 NULL,           /* lpszValueName NULL -> compat */
1973                 NULL,           /* lpdwReserved, must be NULL */
1974                 &lpdwType,
1975                 (LPBYTE)lpszData,
1976                 lpcbData
1977         );
1978         if (xhkey!=hkey)
1979                 RegCloseKey(xhkey);
1980         return ret;
1981 }
1982
1983 /* RegQueryValue                [SHELL.6] [KERNEL.224] */
1984 DWORD RegQueryValue16(
1985         HKEY    hkey,
1986         LPSTR   lpszSubKey,
1987         LPSTR   lpszData,
1988         LPDWORD lpcbData
1989 ) {
1990         dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
1991                 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
1992         );
1993         /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
1994          *       anyway, so we just mask out the high 16 bit.
1995          *       (this (not so much incidently;) hopefully fixes Aldus FH4)
1996          */
1997         if (lpcbData)
1998                 *lpcbData &= 0xFFFF;
1999         return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2000 }
2001
2002 /*
2003  * Setting values of Registry keys
2004  *
2005  * Callpath:
2006  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2007  *                                    RegSetValue32W   -> RegSetValueEx32W
2008  */
2009
2010 /* RegSetValueExW               [ADVAPI32.170] */
2011 DWORD RegSetValueEx32W(
2012         HKEY    hkey,
2013         LPWSTR  lpszValueName,
2014         DWORD   dwReserved,
2015         DWORD   dwType,
2016         LPBYTE  lpbData,
2017         DWORD   cbData
2018 ) {
2019         LPKEYSTRUCT     lpkey;
2020         int             i;
2021
2022         dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2023                 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2024         );
2025         /* we no longer care about the lpbData type here... */
2026         lpkey   = lookup_hkey(hkey);
2027         if (!lpkey)
2028                 return SHELL_ERROR_BADKEY;
2029
2030         lpkey->flags |= REG_OPTION_TAINTED;
2031
2032         if (lpszValueName==NULL) {
2033                 for (i=0;i<lpkey->nrofvalues;i++)
2034                         if (lpkey->values[i].name==NULL)
2035                                 break;
2036         } else {
2037                 for (i=0;i<lpkey->nrofvalues;i++)
2038                         if (    lpkey->values[i].name &&
2039                                 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2040                         )
2041                                 break;
2042         }
2043         if (i==lpkey->nrofvalues) {
2044                 lpkey->values = (LPKEYVALUE)xrealloc(
2045                                         lpkey->values,
2046                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2047                                 );
2048                 lpkey->nrofvalues++;
2049                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2050         }
2051         if (lpkey->values[i].name==NULL)
2052                 if (lpszValueName)
2053                         lpkey->values[i].name = strdupW(lpszValueName);
2054                 else
2055                         lpkey->values[i].name = NULL;
2056         lpkey->values[i].len    = cbData;
2057         lpkey->values[i].type   = dwType;
2058         if (lpkey->values[i].data !=NULL)
2059                 free(lpkey->values[i].data);
2060         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
2061         lpkey->values[i].lastmodified = time(NULL);
2062         memcpy(lpkey->values[i].data,lpbData,cbData);
2063         return SHELL_ERROR_SUCCESS;
2064 }
2065
2066 /* RegSetValueExA               [ADVAPI32.169] */
2067 DWORD RegSetValueEx32A(
2068         HKEY    hkey,
2069         LPSTR   lpszValueName,
2070         DWORD   dwReserved,
2071         DWORD   dwType,
2072         LPBYTE  lpbData,
2073         DWORD   cbData
2074 ) {
2075         LPBYTE  buf;
2076         LPWSTR  lpszValueNameW;
2077         DWORD   ret;
2078
2079         dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2080                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2081         );
2082         if ((1<<dwType) & UNICONVMASK) {
2083                 buf=(LPBYTE)strdupA2W(lpbData);
2084                 cbData=2*strlen(lpbData)+2;
2085         } else
2086                 buf=lpbData;
2087         if (lpszValueName)
2088                 lpszValueNameW = strdupA2W(lpszValueName);
2089         else
2090                 lpszValueNameW = NULL;
2091         ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2092         if (lpszValueNameW)
2093                 free(lpszValueNameW);
2094         if (buf!=lpbData)
2095                 free(buf);
2096         return ret;
2097 }
2098
2099 /* RegSetValueEx                [KERNEL.226] */
2100 DWORD RegSetValueEx16(
2101         HKEY    hkey,
2102         LPSTR   lpszValueName,
2103         DWORD   dwReserved,
2104         DWORD   dwType,
2105         LPBYTE  lpbData,
2106         DWORD   cbData
2107 ) {
2108         dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2109                 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2110         );
2111         return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2112 }
2113
2114 /* RegSetValueW                 [ADVAPI32.171] */
2115 DWORD RegSetValue32W(
2116         HKEY    hkey,
2117         LPCWSTR lpszSubKey,
2118         DWORD   dwType,
2119         LPCWSTR lpszData,
2120         DWORD   cbData
2121 ) {
2122         HKEY    xhkey;
2123         DWORD   ret;
2124
2125         dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2126                 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2127         );
2128         if (lpszSubKey && *lpszSubKey) {
2129                 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2130                 if (ret!=ERROR_SUCCESS)
2131                         return ret;
2132         } else
2133                 xhkey=hkey;
2134         if (dwType!=REG_SZ) {
2135                 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2136                 dwType=REG_SZ;
2137         }
2138         if (cbData!=2*lstrlen32W(lpszData)+2) {
2139                 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2140                         cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2141                 );
2142                 cbData=2*lstrlen32W(lpszData)+2;
2143         }
2144         ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2145         if (hkey!=xhkey)
2146                 RegCloseKey(xhkey);
2147         return ret;
2148
2149 }
2150 /* RegSetValueA                 [ADVAPI32.168] */
2151 DWORD RegSetValue32A(
2152         HKEY    hkey,
2153         LPCSTR  lpszSubKey,
2154         DWORD   dwType,
2155         LPCSTR  lpszData,
2156         DWORD   cbData
2157 ) {
2158         DWORD   ret;
2159         HKEY    xhkey;
2160
2161         dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2162                 hkey,lpszSubKey,dwType,lpszData,cbData
2163         );
2164         if (lpszSubKey && *lpszSubKey) {
2165                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2166                 if (ret!=ERROR_SUCCESS)
2167                         return ret;
2168         } else
2169                 xhkey=hkey;
2170
2171         if (dwType!=REG_SZ) {
2172                 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2173                 dwType=REG_SZ;
2174         }
2175         if (cbData!=strlen(lpszData)+1)
2176                 cbData=strlen(lpszData)+1;
2177         ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2178         if (xhkey!=hkey)
2179                 RegCloseKey(xhkey);
2180         return ret;
2181 }
2182
2183 /* RegSetValue                  [KERNEL.221] [SHELL.5] */
2184 DWORD RegSetValue16(
2185         HKEY    hkey,
2186         LPCSTR  lpszSubKey,
2187         DWORD   dwType,
2188         LPCSTR  lpszData,
2189         DWORD   cbData
2190 ) {
2191         DWORD   ret;
2192         dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2193                 hkey,lpszSubKey,dwType,lpszData,cbData
2194         );
2195         ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2196         return ret;
2197 }
2198
2199 /* 
2200  * Key Enumeration
2201  *
2202  * Callpath:
2203  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2204  *                              RegEnumKey32W   -> RegEnumKeyEx32W
2205  */
2206
2207 /* RegEnumKeyExW                [ADVAPI32.139] */
2208 DWORD RegEnumKeyEx32W(
2209         HKEY    hkey,
2210         DWORD   iSubkey,
2211         LPWSTR  lpszName,
2212         LPDWORD lpcchName,
2213         LPDWORD lpdwReserved,
2214         LPWSTR  lpszClass,
2215         LPDWORD lpcchClass,
2216         FILETIME        *ft
2217 ) {
2218         LPKEYSTRUCT     lpkey,lpxkey;
2219
2220         dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2221                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2222         );
2223         lpkey=lookup_hkey(hkey);
2224         if (!lpkey)
2225                 return SHELL_ERROR_BADKEY;
2226         if (!lpkey->nextsub)
2227                 return ERROR_NO_MORE_ITEMS;
2228         lpxkey=lpkey->nextsub;
2229         while (iSubkey && lpxkey) {
2230                 iSubkey--;
2231                 lpxkey=lpxkey->next;
2232         }
2233         if (iSubkey || !lpxkey)
2234                 return ERROR_NO_MORE_ITEMS;
2235         if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2236                 return ERROR_MORE_DATA;
2237         memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2238         if (lpszClass) {
2239                 /* what should we write into it? */
2240                 *lpszClass              = 0;
2241                 *lpcchClass     = 2;
2242         }
2243         return ERROR_SUCCESS;
2244
2245 }
2246
2247 /* RegEnumKeyW                  [ADVAPI32.140] */
2248 DWORD RegEnumKey32W(
2249         HKEY    hkey,
2250         DWORD   iSubkey,
2251         LPWSTR  lpszName,
2252         DWORD   lpcchName
2253 ) {
2254         FILETIME        ft;
2255
2256         dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2257                 hkey,iSubkey,lpszName,lpcchName
2258         );
2259         return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2260 }
2261 /* RegEnumKeyExA                [ADVAPI32.138] */
2262 DWORD RegEnumKeyEx32A(
2263         HKEY    hkey,
2264         DWORD   iSubkey,
2265         LPSTR   lpszName,
2266         LPDWORD lpcchName,
2267         LPDWORD lpdwReserved,
2268         LPSTR   lpszClass,
2269         LPDWORD lpcchClass,
2270         FILETIME        *ft
2271 ) {
2272         DWORD   ret,lpcchNameW,lpcchClassW;
2273         LPWSTR  lpszNameW,lpszClassW;
2274
2275
2276         dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2277                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2278         );
2279         if (lpszName) {
2280                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
2281                 lpcchNameW      = *lpcchName*2;
2282         } else {
2283                 lpszNameW       = NULL;
2284                 lpcchNameW      = 0;
2285         }
2286         if (lpszClass) {
2287                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
2288                 lpcchClassW     = *lpcchClass*2;
2289         } else {
2290                 lpszClassW      =0;
2291                 lpcchClassW=0;
2292         }
2293         ret=RegEnumKeyEx32W(
2294                 hkey,
2295                 iSubkey,
2296                 lpszNameW,
2297                 &lpcchNameW,
2298                 lpdwReserved,
2299                 lpszClassW,
2300                 &lpcchClassW,
2301                 ft
2302         );
2303         if (ret==ERROR_SUCCESS) {
2304                 strcpyWA(lpszName,lpszNameW);
2305                 *lpcchName=strlen(lpszName);
2306                 if (lpszClassW) {
2307                         strcpyWA(lpszClass,lpszClassW);
2308                         *lpcchClass=strlen(lpszClass);
2309                 }
2310         }
2311         if (lpszNameW)
2312                 free(lpszNameW);
2313         if (lpszClassW)
2314                 free(lpszClassW);
2315         return ret;
2316 }
2317
2318 /* RegEnumKeyA                  [ADVAPI32.137] */
2319 DWORD RegEnumKey32A(
2320         HKEY    hkey,
2321         DWORD   iSubkey,
2322         LPSTR   lpszName,
2323         DWORD   lpcchName
2324 ) {
2325         FILETIME        ft;
2326
2327         dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2328                 hkey,iSubkey,lpszName,lpcchName
2329         );
2330         return  RegEnumKeyEx32A(
2331                 hkey,
2332                 iSubkey,
2333                 lpszName,
2334                 &lpcchName,
2335                 NULL,
2336                 NULL,
2337                 NULL,
2338                 &ft
2339         );
2340 }
2341
2342 /* RegEnumKey                   [SHELL.7] [KERNEL.216] */
2343 DWORD RegEnumKey16(
2344         HKEY    hkey,
2345         DWORD   iSubkey,
2346         LPSTR   lpszName,
2347         DWORD   lpcchName
2348 ) {
2349         dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2350                 hkey,iSubkey,lpszName,lpcchName
2351         );
2352         return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2353 }
2354
2355 /* 
2356  * Enumerate Registry Values
2357  *
2358  * Callpath:
2359  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2360  */
2361
2362 /* RegEnumValueW                [ADVAPI32.142] */
2363 DWORD RegEnumValue32W(
2364         HKEY    hkey,
2365         DWORD   iValue,
2366         LPWSTR  lpszValue,
2367         LPDWORD lpcchValue,
2368         LPDWORD lpdReserved,
2369         LPDWORD lpdwType,
2370         LPBYTE  lpbData,
2371         LPDWORD lpcbData
2372 ) {
2373         LPKEYSTRUCT     lpkey;
2374         LPKEYVALUE      val;
2375
2376         dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2377                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2378         );
2379         lpkey = lookup_hkey(hkey);
2380         if (!lpkey)
2381                 return SHELL_ERROR_BADKEY;
2382         if (lpkey->nrofvalues<=iValue)
2383                 return ERROR_NO_MORE_ITEMS;
2384         val     = lpkey->values+iValue;
2385
2386         if (val->name) {
2387                 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2388                         *lpcchValue = lstrlen32W(val->name)*2+2;
2389                         return ERROR_MORE_DATA;
2390                 }
2391                 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2392                 *lpcchValue=lstrlen32W(val->name)*2+2;
2393         } else {
2394                 /* how to handle NULL value? */
2395                 *lpszValue      = 0;
2396                 *lpcchValue     = 2;
2397         }
2398         *lpdwType=val->type;
2399         if (lpbData) {
2400                 if (val->len>*lpcbData)
2401                         return ERROR_MORE_DATA;
2402                 memcpy(lpbData,val->data,val->len);
2403                 *lpcbData = val->len;
2404         }
2405         return SHELL_ERROR_SUCCESS;
2406 }
2407
2408 /* RegEnumValueA                [ADVAPI32.141] */
2409 DWORD RegEnumValue32A(
2410         HKEY    hkey,
2411         DWORD   iValue,
2412         LPSTR   lpszValue,
2413         LPDWORD lpcchValue,
2414         LPDWORD lpdReserved,
2415         LPDWORD lpdwType,
2416         LPBYTE  lpbData,
2417         LPDWORD lpcbData
2418 ) {
2419         LPWSTR  lpszValueW;
2420         LPBYTE  lpbDataW;
2421         DWORD   ret,lpcbDataW;
2422
2423         dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2424                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2425         );
2426
2427         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2428         if (lpbData) {
2429                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2430                 lpcbDataW = *lpcbData*2;
2431         } else
2432                 lpbDataW = NULL;
2433         ret=RegEnumValue32W(
2434                 hkey,
2435                 iValue,
2436                 lpszValueW,
2437                 lpcchValue,
2438                 lpdReserved,
2439                 lpdwType,
2440                 lpbDataW,
2441                 &lpcbDataW
2442         );
2443
2444         if (ret==ERROR_SUCCESS) {
2445                 strcpyWA(lpszValue,lpszValueW);
2446                 if (lpbData) {
2447                         if ((1<<*lpdwType) & UNICONVMASK) {
2448                                 strcpyWA(lpbData,(LPWSTR)lpbDataW);
2449                         } else {
2450                                 if (lpcbDataW > *lpcbData)
2451                                         ret     = ERROR_MORE_DATA;
2452                                 else
2453                                         memcpy(lpbData,lpbDataW,lpcbDataW);
2454                         }
2455                         *lpcbData = lpcbDataW;
2456                 }
2457         }
2458         if (lpbDataW)
2459                 free(lpbDataW);
2460         if (lpszValueW)
2461                 free(lpszValueW);
2462         return ret;
2463 }
2464
2465 /* RegEnumValue                 [KERNEL.223] */
2466 DWORD RegEnumValue16(
2467         HKEY    hkey,
2468         DWORD   iValue,
2469         LPSTR   lpszValue,
2470         LPDWORD lpcchValue,
2471         LPDWORD lpdReserved,
2472         LPDWORD lpdwType,
2473         LPBYTE  lpbData,
2474         LPDWORD lpcbData
2475 ) {
2476         dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2477                 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2478         );
2479         return RegEnumValue32A(
2480                 hkey,
2481                 iValue,
2482                 lpszValue,
2483                 lpcchValue,
2484                 lpdReserved,
2485                 lpdwType,
2486                 lpbData,
2487                 lpcbData
2488         );
2489 }
2490
2491 /* 
2492  *  Close registry key
2493  */
2494 /* RegCloseKey                  [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2495 DWORD RegCloseKey(HKEY hkey) {
2496         dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2497         remove_handle(hkey);
2498         return ERROR_SUCCESS;
2499 }
2500 /* 
2501  * Delete registry key
2502  *
2503  * Callpath:
2504  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2505  */
2506 /* RegDeleteKeyW                [ADVAPI32.134] */
2507 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2508         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
2509         LPWSTR          *wps;
2510         int             wpc,i;
2511
2512         dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2513                 hkey,W2C(lpszSubKey,0)
2514         );
2515         lpNextKey       = lookup_hkey(hkey);
2516         if (!lpNextKey)
2517                 return SHELL_ERROR_BADKEY;
2518         /* we need to know the previous key in the hier. */
2519         if (!lpszSubKey || !*lpszSubKey)
2520                 return SHELL_ERROR_BADKEY;
2521         split_keypath(lpszSubKey,&wps,&wpc);
2522         i       = 0;
2523         lpxkey  = lpNextKey;
2524         while (i<wpc-1) {
2525                 lpxkey=lpNextKey->nextsub;
2526                 while (lpxkey) {
2527                         if (!lstrcmp32W(wps[i],lpxkey->keyname))
2528                                 break;
2529                         lpxkey=lpxkey->next;
2530                 }
2531                 if (!lpxkey) {
2532                         FREE_KEY_PATH;
2533                         /* not found is success */
2534                         return SHELL_ERROR_SUCCESS;
2535                 }
2536                 i++;
2537                 lpNextKey       = lpxkey;
2538         }
2539         lpxkey  = lpNextKey->nextsub;
2540         lplpPrevKey = &(lpNextKey->nextsub);
2541         while (lpxkey) {
2542                 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2543                         break;
2544                 lplpPrevKey     = &(lpxkey->next);
2545                 lpxkey          = lpxkey->next;
2546         }
2547         if (!lpxkey)
2548                 return SHELL_ERROR_SUCCESS;
2549         if (lpxkey->nextsub)
2550                 return SHELL_ERROR_CANTWRITE;
2551         *lplpPrevKey    = lpxkey->next;
2552         free(lpxkey->keyname);
2553         if (lpxkey->class)
2554                 free(lpxkey->class);
2555         if (lpxkey->values)
2556                 free(lpxkey->values);
2557         free(lpxkey);
2558         FREE_KEY_PATH;
2559         return  SHELL_ERROR_SUCCESS;
2560 }
2561
2562 /* RegDeleteKeyA                [ADVAPI32.133] */
2563 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2564         LPWSTR  lpszSubKeyW;
2565         DWORD   ret;
2566
2567         dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2568                 hkey,lpszSubKey
2569         );
2570         lpszSubKeyW=strdupA2W(lpszSubKey);
2571         ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2572         free(lpszSubKeyW);
2573         return ret;
2574 }
2575
2576 /* RegDeleteKey                 [SHELL.4] [KERNEL.219] */
2577 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2578         dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2579                 hkey,lpszSubKey
2580         );
2581         return RegDeleteKey32A(hkey,lpszSubKey);
2582 }
2583
2584 /* 
2585  * Delete registry value
2586  *
2587  * Callpath:
2588  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2589  */
2590 /* RegDeleteValueW              [ADVAPI32.136] */
2591 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2592         DWORD           i;
2593         LPKEYSTRUCT     lpkey;
2594         LPKEYVALUE      val;
2595
2596         dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2597                 hkey,W2C(lpszValue,0)
2598         );
2599         lpkey=lookup_hkey(hkey);
2600         if (!lpkey)
2601                 return SHELL_ERROR_BADKEY;
2602         if (lpszValue) {
2603                 for (i=0;i<lpkey->nrofvalues;i++)
2604                         if (    lpkey->values[i].name &&
2605                                 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2606                         )
2607                                 break;
2608         } else {
2609                 for (i=0;i<lpkey->nrofvalues;i++)
2610                         if (lpkey->values[i].name==NULL)
2611                                 break;
2612         }
2613         if (i==lpkey->nrofvalues)
2614                 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2615         val     = lpkey->values+i;
2616         if (val->name) free(val->name);
2617         if (val->data) free(val->data);
2618         memcpy( 
2619                 lpkey->values+i,
2620                 lpkey->values+i+1,
2621                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2622         );
2623         lpkey->values   = (LPKEYVALUE)xrealloc(
2624                                 lpkey->values,
2625                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2626                         );
2627         lpkey->nrofvalues--;
2628         return SHELL_ERROR_SUCCESS;
2629 }
2630
2631 /* RegDeleteValueA              [ADVAPI32.135] */
2632 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2633         LPWSTR  lpszValueW;
2634         DWORD   ret;
2635
2636         dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2637         if (lpszValue)
2638                 lpszValueW=strdupA2W(lpszValue);
2639         else
2640                 lpszValueW=NULL;
2641         ret=RegDeleteValue32W(hkey,lpszValueW);
2642         if (lpszValueW)
2643                 free(lpszValueW);
2644         return ret;
2645 }
2646
2647 /* RegDeleteValue               [KERNEL.222] */
2648 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2649         dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2650         return RegDeleteValue32A(hkey,lpszValue);
2651 }
2652
2653 /* RegFlushKey                  [ADVAPI32.143] [KERNEL.227] */
2654 DWORD RegFlushKey(HKEY hkey) {
2655         dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2656         return SHELL_ERROR_SUCCESS;
2657 }
2658
2659 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2660
2661 /* RegQueryInfoKeyW             [ADVAPI32.153] */
2662 DWORD RegQueryInfoKey32W(
2663         HKEY    hkey,
2664         LPWSTR  lpszClass,
2665         LPDWORD lpcchClass,
2666         LPDWORD lpdwReserved,
2667         LPDWORD lpcSubKeys,
2668         LPDWORD lpcchMaxSubkey,
2669         LPDWORD lpcchMaxClass,
2670         LPDWORD lpcValues,
2671         LPDWORD lpcchMaxValueName,
2672         LPDWORD lpccbMaxValueData,
2673         LPDWORD lpcbSecurityDescriptor,
2674         FILETIME        *ft
2675 ) {
2676         LPKEYSTRUCT     lpkey,lpxkey;
2677         int             nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2678         int             i;
2679
2680         dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2681         lpkey=lookup_hkey(hkey);
2682         if (!lpkey)
2683                 return SHELL_ERROR_BADKEY;
2684         if (lpszClass) {
2685                 if (lpkey->class) {
2686                         if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2687                                 *lpcchClass=lstrlen32W(lpkey->class)*2;
2688                                 return ERROR_MORE_DATA;
2689                         }
2690                         *lpcchClass=lstrlen32W(lpkey->class)*2;
2691                         memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2692                 } else {
2693                         *lpszClass      = 0;
2694                         *lpcchClass     = 0;
2695                 }
2696         } else {
2697                 if (lpcchClass)
2698                         *lpcchClass     = lstrlen32W(lpkey->class)*2;
2699         }
2700         lpxkey=lpkey->nextsub;
2701         nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2702         while (lpxkey) {
2703                 nrofkeys++;
2704                 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2705                         maxsubkey=lstrlen32W(lpxkey->keyname);
2706                 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2707                         maxclass=lstrlen32W(lpxkey->class);
2708                 if (lpxkey->nrofvalues>maxvalues)
2709                         maxvalues=lpxkey->nrofvalues;
2710                 for (i=0;i<lpxkey->nrofvalues;i++) {
2711                         LPKEYVALUE      val=lpxkey->values+i;
2712
2713                         if (val->name && lstrlen32W(val->name)>maxvname)
2714                                 maxvname=lstrlen32W(val->name);
2715                         if (val->len>maxvdata)
2716                                 maxvdata=val->len;
2717                 }
2718                 lpxkey=lpxkey->next;
2719         }
2720         if (!maxclass) maxclass = 1;
2721         if (!maxvname) maxvname = 1;
2722         if (lpcSubKeys)
2723                 *lpcSubKeys     = nrofkeys;
2724         if (lpcchMaxSubkey)
2725                 *lpcchMaxSubkey = maxsubkey*2;
2726         if (lpcchMaxClass)
2727                 *lpcchMaxClass  = maxclass*2;
2728         if (lpcValues)
2729                 *lpcValues      = maxvalues;
2730         if (lpcchMaxValueName)
2731                 *lpcchMaxValueName= maxvname;
2732         if (lpccbMaxValueData)
2733                 *lpccbMaxValueData= maxvdata;
2734         return SHELL_ERROR_SUCCESS;
2735 }
2736
2737 /* RegQueryInfoKeyA             [ADVAPI32.152] */
2738 DWORD RegQueryInfoKey32A(
2739         HKEY    hkey,
2740         LPSTR   lpszClass,
2741         LPDWORD lpcchClass,
2742         LPDWORD lpdwReserved,
2743         LPDWORD lpcSubKeys,
2744         LPDWORD lpcchMaxSubkey,
2745         LPDWORD lpcchMaxClass,
2746         LPDWORD lpcValues,
2747         LPDWORD lpcchMaxValueName,
2748         LPDWORD lpccbMaxValueData,
2749         LPDWORD lpcbSecurityDescriptor,
2750         FILETIME        *ft
2751 ) {
2752         LPWSTR          lpszClassW;
2753         DWORD           ret;
2754
2755         dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2756         if (lpszClass) {
2757                 *lpcchClass*= 2;
2758                 lpszClassW  = (LPWSTR)xmalloc(*lpcchClass);
2759
2760         } else
2761                 lpszClassW  = NULL;
2762         ret=RegQueryInfoKey32W(
2763                 hkey,
2764                 lpszClassW,
2765                 lpcchClass,
2766                 lpdwReserved,
2767                 lpcSubKeys,
2768                 lpcchMaxSubkey,
2769                 lpcchMaxClass,
2770                 lpcValues,
2771                 lpcchMaxValueName,
2772                 lpccbMaxValueData,
2773                 lpcbSecurityDescriptor,
2774                 ft
2775         );
2776         if (ret==ERROR_SUCCESS)
2777                 strcpyWA(lpszClass,lpszClassW);
2778         if (lpcchClass)
2779                 *lpcchClass/=2;
2780         if (lpcchMaxSubkey)
2781                 *lpcchMaxSubkey/=2;
2782         if (lpcchMaxClass)
2783                 *lpcchMaxClass/=2;
2784         if (lpcchMaxValueName)
2785                 *lpcchMaxValueName/=2;
2786         if (lpszClassW)
2787                 free(lpszClassW);
2788         return ret;
2789 }