New Wine internal interface for handling CD Rom (especially audio CD
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  * Copyright 1998 Matthew Becker
6  *
7  * December 21, 1997 - Kevin Cozens
8  * Fixed bugs in the _w95_loadreg() function. Added extra information
9  * regarding the format of the Windows '95 registry files.
10  *
11  * NOTES
12  *    When changing this file, please re-run the regtest program to ensure
13  *    the conditions are handled properly.
14  *
15  * TODO
16  *    Security access
17  *    Option handling
18  *    Time for RegEnumKey*, RegQueryInfoKey*
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
29 #include <sys/stat.h>
30 #include <pwd.h>
31 #include <assert.h>
32 #include <time.h>
33 #include "windows.h"
34 #include "win.h"
35 #include "winerror.h"
36 #include "file.h"
37 #include "heap.h"
38 #include "debug.h"
39 #include "xmalloc.h"
40 #include "winreg.h"
41 #include "winversion.h"
42
43 static void REGISTRY_Init(void);
44 /* FIXME: following defines should be configured global ... */
45
46 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
47 #define WINE_PREFIX                     "/.wine"
48 #define SAVE_USERS_DEFAULT              "/usr/local/etc/wine.userreg"
49 #define SAVE_LOCAL_MACHINE_DEFAULT      "/usr/local/etc/wine.systemreg"
50
51 /* relative in ~user/.wine/ : */
52 #define SAVE_CURRENT_USER               "user.reg"
53 #define SAVE_LOCAL_MACHINE              "system.reg"
54
55 #define KEY_REGISTRY    "Software\\The WINE team\\WINE\\Registry"
56 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57
58 /* one value of a key */
59 typedef struct tagKEYVALUE
60 {
61     LPWSTR   name;          /* name of value (UNICODE) or NULL for win31 */
62     DWORD    type;          /* type of value */
63     DWORD    len;           /* length of data in BYTEs */
64     DWORD    lastmodified;  /* time of seconds since 1.1.1970 */
65     LPBYTE   data;          /* content, may be strings, binaries, etc. */
66 } KEYVALUE,*LPKEYVALUE;
67
68 /* a registry key */
69 typedef struct tagKEYSTRUCT
70 {
71     LPWSTR               keyname;       /* name of THIS key (UNICODE) */
72     DWORD                flags;         /* flags. */
73     LPWSTR               class;
74     /* values */
75     DWORD                nrofvalues;    /* nr of values in THIS key */
76     LPKEYVALUE           values;        /* values in THIS key */
77     /* key management pointers */
78     struct tagKEYSTRUCT *next;          /* next key on same hierarchy */
79     struct tagKEYSTRUCT *nextsub;       /* keys that hang below THIS key */
80 } KEYSTRUCT, *LPKEYSTRUCT;
81
82
83 static KEYSTRUCT        *key_classes_root=NULL; /* windows 3.1 global values */
84 static KEYSTRUCT        *key_current_user=NULL; /* user specific values */
85 static KEYSTRUCT        *key_local_machine=NULL;/* machine specific values */
86 static KEYSTRUCT        *key_users=NULL;        /* all users? */
87
88 /* dynamic, not saved */
89 static KEYSTRUCT        *key_performance_data=NULL;
90 static KEYSTRUCT        *key_current_config=NULL;
91 static KEYSTRUCT        *key_dyn_data=NULL;
92
93 /* what valuetypes do we need to convert? */
94 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
95
96
97 static struct openhandle {
98         LPKEYSTRUCT     lpkey;
99         HKEY            hkey;
100         REGSAM          accessmask;
101 }  *openhandles=NULL;
102 static int      nrofopenhandles=0;
103 /* Starts after 1 because 0,1 are reserved for Win16 */
104 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
105          HKEYs for remote registry access */
106 static int      currenthandle=2;
107
108
109 /*
110  * QUESTION
111  *   Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112  *   If so, can we remove them?
113  * ANSWER
114  *   No, the memory handling functions are called very often in here, 
115  *   just replacing them by HeapAlloc(SystemHeap,...) makes registry
116  *   loading 100 times slower. -MM
117  */
118 static LPWSTR strdupA2W(LPCSTR src)
119 {
120     if(src) {
121         LPWSTR dest=xmalloc(2*strlen(src)+2);
122         lstrcpyAtoW(dest,src);
123         return dest;
124     }
125     return NULL;
126 }
127
128 static LPWSTR strdupW(LPCWSTR a) {
129         LPWSTR  b;
130         int     len;
131
132     if(a) {
133         len=sizeof(WCHAR)*(lstrlen32W(a)+1);
134         b=(LPWSTR)xmalloc(len);
135         memcpy(b,a,len);
136         return b;
137     }
138     return NULL;
139 }
140
141 LPWSTR strcvtA2W(LPCSTR src, int nchars)
142
143 {
144    LPWSTR dest = xmalloc (2 * nchars + 2);
145
146    lstrcpynAtoW(dest,src,nchars+1);
147    dest[nchars] = 0;
148    return dest;
149 }
150 /*
151  * we need to convert A to W with '\0' in strings (MULTI_SZ) 
152  */
153
154 static LPWSTR  lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT32 n )
155 {       LPWSTR p = dst;
156
157         TRACE(reg,"\"%s\" %i\n",src, n);
158
159         while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
160
161         return dst;
162 }
163 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT32 n )
164 {       LPSTR p = dst;
165
166         TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
167
168         while (n-- > 0) *p++ = (CHAR)*src++;
169
170         return dst;
171 }
172
173 static void debug_print_value (LPBYTE lpbData, DWORD type, DWORD len)
174 {       if (TRACE_ON(reg) && lpbData) 
175         { switch(type)
176           { case REG_SZ:
177                 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
178                 break;
179
180             case REG_DWORD:
181                 TRACE(reg," Data(dword)=0x%08lx\n",(DWORD)*lpbData);
182                 break;
183                 
184             case REG_MULTI_SZ:
185                 { int i;
186                   LPCWSTR ptr = (LPCWSTR)lpbData;
187                   for (i=0;ptr[0];i++)
188                   { TRACE(reg, " MULTI_SZ(%i=%s)\n", i, debugstr_w(ptr));
189                     ptr += lstrlen32W(ptr)+1;
190                   }
191                 }
192                 break;
193
194             case REG_BINARY:
195                 { char szTemp[100];                     /* 3*32 + 3 + 1 */
196                   int i;
197                   for ( i = 0; i < len ; i++)             
198                   { sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
199                     if (i>=31)
200                     { sprintf (&(szTemp[i*3+3]),"...");
201                       break;
202                     }
203                   }
204                   TRACE(reg," Data(raw)=(%s)\n", szTemp);                  
205                 }
206                 break;
207                 
208             default:
209                 FIXME(reg, " Unknown data type %ld\n", type);
210           } /* switch */
211         } /* if */
212 }
213
214
215
216 /******************************************************************************
217  * is_standard_hkey [Internal]
218  * Determines if a hkey is a standard key
219  */
220 static BOOL32 is_standard_hkey( HKEY hkey )
221 {
222     switch(hkey) {
223         case 0x00000000:
224         case 0x00000001:
225         case HKEY_CLASSES_ROOT:
226         case HKEY_CURRENT_CONFIG:
227         case HKEY_CURRENT_USER:
228         case HKEY_LOCAL_MACHINE:
229         case HKEY_USERS:
230         case HKEY_PERFORMANCE_DATA:
231         case HKEY_DYN_DATA:
232             return TRUE;
233         default:
234             return FALSE;
235     }
236 }
237
238 /******************************************************************************
239  * add_handle [Internal]
240  */
241 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
242 {
243     int i;
244
245     TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
246     /* Check for duplicates */
247     for (i=0;i<nrofopenhandles;i++) {
248         if (openhandles[i].lpkey==lpkey) {
249             /* This is not really an error - the user is allowed to create
250                two (or more) handles to the same key */
251             /*WARN(reg, "Adding key %p twice\n",lpkey);*/
252         }
253         if (openhandles[i].hkey==hkey) {
254             WARN(reg, "Adding handle %x twice\n",hkey);
255         }
256     }
257     openhandles=xrealloc( openhandles, 
258                           sizeof(struct openhandle)*(nrofopenhandles+1));
259
260     openhandles[i].lpkey = lpkey;
261     openhandles[i].hkey = hkey;
262     openhandles[i].accessmask = accessmask;
263     nrofopenhandles++;
264 }
265
266
267 /******************************************************************************
268  * get_handle [Internal]
269  *
270  * RETURNS
271  *    Success: Pointer to key
272  *    Failure: NULL
273  */
274 static LPKEYSTRUCT get_handle( HKEY hkey )
275 {
276     int i;
277
278     for (i=0; i<nrofopenhandles; i++)
279         if (openhandles[i].hkey == hkey)
280             return openhandles[i].lpkey;
281     WARN(reg, "Could not find handle 0x%x\n",hkey);
282     return NULL;
283 }
284
285
286 /******************************************************************************
287  * remove_handle [Internal]
288  *
289  * PARAMS
290  *    hkey [I] Handle of key to remove
291  *
292  * RETURNS
293  *    Success: ERROR_SUCCESS
294  *    Failure: ERROR_INVALID_HANDLE
295  */
296 static DWORD remove_handle( HKEY hkey )
297 {
298     int i;
299
300     for (i=0;i<nrofopenhandles;i++)
301         if (openhandles[i].hkey==hkey)
302             break;
303
304     if (i == nrofopenhandles) {
305         WARN(reg, "Could not find handle 0x%x\n",hkey);
306         return ERROR_INVALID_HANDLE;
307     }
308
309     memcpy( openhandles+i,
310             openhandles+i+1,
311             sizeof(struct openhandle)*(nrofopenhandles-i-1)
312     );
313     openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
314     nrofopenhandles--;
315     return ERROR_SUCCESS;
316 }
317
318 /******************************************************************************
319  * lookup_hkey [Internal]
320  * 
321  * Just as the name says. Creates the root keys on demand, so we can call the
322  * Reg* functions at any time.
323  *
324  * RETURNS
325  *    Success: Pointer to key structure
326  *    Failure: NULL
327  */
328 #define ADD_ROOT_KEY(xx) \
329         xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
330         memset(xx,'\0',sizeof(KEYSTRUCT));\
331         xx->keyname= strdupA2W("<should_not_appear_anywhere>");
332
333 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
334 {
335         switch (hkey) {
336         /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
337          * some programs. Do not remove those cases. -MM
338          */
339         case 0x00000000:
340         case 0x00000001:
341         case HKEY_CLASSES_ROOT: {
342                 if (!key_classes_root) {
343                         HKEY    cl_r_hkey;
344
345                         /* calls lookup_hkey recursively, TWICE */
346                         if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
347                                 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
348                                 exit(1);
349                         }
350                         key_classes_root = lookup_hkey(cl_r_hkey);
351                 }
352                 return key_classes_root;
353         }
354         case HKEY_CURRENT_USER:
355                 if (!key_current_user) {
356                         HKEY    c_u_hkey;
357                         struct  passwd  *pwd;
358
359                         pwd=getpwuid(getuid());
360                         /* calls lookup_hkey recursively, TWICE */
361                         if (pwd && pwd->pw_name) {
362                                 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
363                                         ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
364                                         exit(1);
365                                 }
366                                 key_current_user = lookup_hkey(c_u_hkey);
367                         } else {
368                                 /* nothing found, use standalone */
369                                 ADD_ROOT_KEY(key_current_user);
370                         }
371                 }
372                 return key_current_user;
373         case HKEY_LOCAL_MACHINE:
374                 if (!key_local_machine) {
375                         ADD_ROOT_KEY(key_local_machine);
376                         REGISTRY_Init();
377                 }
378                 return key_local_machine;
379         case HKEY_USERS:
380                 if (!key_users) {
381                         ADD_ROOT_KEY(key_users);
382                 }
383                 return key_users;
384         case HKEY_PERFORMANCE_DATA:
385                 if (!key_performance_data) {
386                         ADD_ROOT_KEY(key_performance_data);
387                 }
388                 return key_performance_data;
389         case HKEY_DYN_DATA:
390                 if (!key_dyn_data) {
391                         ADD_ROOT_KEY(key_dyn_data);
392                 }
393                 return key_dyn_data;
394         case HKEY_CURRENT_CONFIG:
395                 if (!key_current_config) {
396                         ADD_ROOT_KEY(key_current_config);
397                 }
398                 return key_current_config;
399         default:
400                 return get_handle(hkey);
401         }
402         /*NOTREACHED*/
403 }
404 #undef ADD_ROOT_KEY
405 /* so we don't accidently access them ... */
406 #define key_current_config NULL NULL
407 #define key_current_user NULL NULL
408 #define key_users NULL NULL
409 #define key_local_machine NULL NULL
410 #define key_classes_root NULL NULL
411 #define key_dyn_data NULL NULL
412 #define key_performance_data NULL NULL
413
414 /******************************************************************************
415  * split_keypath [Internal]
416  * splits the unicode string 'wp' into an array of strings.
417  * the array is allocated by this function. 
418  * Free the array using FREE_KEY_PATH
419  *
420  * PARAMS
421  *    wp  [I] String to split up
422  *    wpv [O] Array of pointers to strings
423  *    wpc [O] Number of components
424  */
425 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
426 {
427     int i,j,len;
428     LPWSTR ws;
429
430     TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
431
432     ws  = HEAP_strdupW( SystemHeap, 0, wp );
433
434     /* We know we have at least one substring */
435     *wpc = 1;
436
437     /* Replace each backslash with NULL, and increment the count */
438     for (i=0;ws[i];i++) {
439         if (ws[i]=='\\') {
440             ws[i]=0;
441             (*wpc)++;
442         }
443     }
444
445     len = i;
446
447     /* Allocate the space for the array of pointers, leaving room for the
448        NULL at the end */
449     *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
450     (*wpv)[0]= ws;
451
452     /* Assign each pointer to the appropriate character in the string */
453     j = 1;
454     for (i=1;i<len;i++)
455         if (ws[i-1]==0) {
456             (*wpv)[j++]=ws+i;
457             /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
458         }
459
460     (*wpv)[j]=NULL;
461 }
462 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
463
464
465
466
467 /******************************************************************************
468  * REGISTRY_Init [Internal]
469  * Registry initialisation, allocates some default keys. 
470  */
471 static void REGISTRY_Init(void) {
472         HKEY    hkey;
473         char    buf[200];
474
475         TRACE(reg,"(void)\n");
476
477         RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
478         RegCloseKey(hkey);
479
480         /* This was an Open, but since it is called before the real registries
481            are loaded, it was changed to a Create - MTB 980507*/
482         RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
483         RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
484         RegCloseKey(hkey);
485
486         /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
487          *                                              CurrentVersion
488          *                                              CurrentBuildNumber
489          *                                              CurrentType
490          *                                      string  RegisteredOwner
491          *                                      string  RegisteredOrganization
492          *
493          */
494         /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
495          *                                      string  SysContact
496          *                                      string  SysLocation
497          *                                              SysServices
498          */                                             
499         if (-1!=gethostname(buf,200)) {
500                 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
501                 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
502                 RegCloseKey(hkey);
503         }
504 }
505
506
507 /************************ SAVE Registry Function ****************************/
508
509 #define REGISTRY_SAVE_VERSION   0x00000001
510
511 /* Registry saveformat:
512  * If you change it, increase above number by 1, which will flush
513  * old registry database files.
514  * 
515  * Global:
516  *      "WINE REGISTRY Version %d"
517  *      subkeys....
518  * Subkeys:
519  *      keyname
520  *              valuename=lastmodified,type,data
521  *              ...
522  *              subkeys
523  *      ...
524  * keyname,valuename,stringdata:
525  *      the usual ascii characters from 0x00-0xff (well, not 0x00)
526  *      and \uXXXX as UNICODE value XXXX with XXXX>0xff
527  *      ( "=\\\t" escaped in \uXXXX form.)
528  * type,lastmodified: 
529  *      int
530  * 
531  * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
532  *
533  * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
534  * SaveOnlyUpdatedKeys=yes
535  */
536
537 /******************************************************************************
538  * _save_check_tainted [Internal]
539  */
540 static int _save_check_tainted( LPKEYSTRUCT lpkey )
541 {
542         int             tainted;
543
544         if (!lpkey)
545                 return 0;
546         if (lpkey->flags & REG_OPTION_TAINTED)
547                 tainted = 1;
548         else
549                 tainted = 0;
550         while (lpkey) {
551                 if (_save_check_tainted(lpkey->nextsub)) {
552                         lpkey->flags |= REG_OPTION_TAINTED;
553                         tainted = 1;
554                 }
555                 lpkey   = lpkey->next;
556         }
557         return tainted;
558 }
559
560 /******************************************************************************
561  * _save_USTRING [Internal]
562  */
563 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
564 {
565         LPWSTR  s;
566         int     doescape;
567
568         if (wstr==NULL)
569                 return;
570         s=wstr;
571         while (*s) {
572                 doescape=0;
573                 if (*s>0xff)
574                         doescape = 1;
575                 if (*s=='\n')
576                         doescape = 1;
577                 if (escapeeq && *s=='=')
578                         doescape = 1;
579                 if (*s=='\\')
580                         fputc(*s,F); /* if \\ then put it twice. */
581                 if (doescape)
582                         fprintf(F,"\\u%04x",*((unsigned short*)s));
583                 else
584                         fputc(*s,F);
585                 s++;
586         }
587 }
588
589 /******************************************************************************
590  * _savesubkey [Internal]
591  *
592  * NOTES
593  *  REG_MULTI_SZ is handled as binary (like in win95) (js)
594  */
595 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
596 {
597         LPKEYSTRUCT     lpxkey;
598         int             i,tabs,j;
599
600         lpxkey  = lpkey;
601         while (lpxkey) {
602                 if (    !(lpxkey->flags & REG_OPTION_VOLATILE) &&
603                         (all || (lpxkey->flags & REG_OPTION_TAINTED))
604                 ) {
605                         for (tabs=level;tabs--;)
606                                 fputc('\t',F);
607                         _save_USTRING(F,lpxkey->keyname,1);
608                         fputs("\n",F);
609                         for (i=0;i<lpxkey->nrofvalues;i++) {
610                                 LPKEYVALUE      val=lpxkey->values+i;
611
612                                 for (tabs=level+1;tabs--;)
613                                         fputc('\t',F);
614                                 _save_USTRING(F,val->name,0);
615                                 fputc('=',F);
616                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
617                                 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
618                                         _save_USTRING(F,(LPWSTR)val->data,0);
619                                 else
620                                         for (j=0;j<val->len;j++)
621                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
622                                 fputs("\n",F);
623                         }
624                         /* descend recursively */
625                         if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
626                                 return 0;
627                 }
628                 lpxkey=lpxkey->next;
629         }
630         return 1;
631 }
632
633
634 /******************************************************************************
635  * _savesubreg [Internal]
636  */
637 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
638 {
639         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
640         _save_check_tainted(lpkey->nextsub);
641         return _savesubkey(F,lpkey->nextsub,0,all);
642 }
643
644
645 /******************************************************************************
646  * _savereg [Internal]
647  */
648 static BOOL32 _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
649 {
650         FILE    *F;
651
652         F=fopen(fn,"w");
653         if (F==NULL) {
654                 WARN(reg,"Couldn't open %s for writing: %s\n",
655                         fn,strerror(errno)
656                 );
657                 return FALSE;
658         }
659         if (!_savesubreg(F,lpkey,all)) {
660                 fclose(F);
661                 unlink(fn);
662                 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
663                 return FALSE;
664         }
665         fclose(F);
666         return TRUE;
667 }
668
669
670 /******************************************************************************
671  * SHELL_SaveRegistry [Internal]
672  */
673 void SHELL_SaveRegistry( void )
674 {
675         char    *fn;
676         struct  passwd  *pwd;
677         char    buf[4];
678         HKEY    hkey;
679         int     all;
680
681     TRACE(reg,"(void)\n");
682
683         all=0;
684         if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
685                 strcpy(buf,"yes");
686         } else {
687                 DWORD len,junk,type;
688
689                 len=4;
690                 if (    (ERROR_SUCCESS!=RegQueryValueEx32A(
691                                 hkey,
692                                 VAL_SAVEUPDATED,
693                                 &junk,
694                                 &type,
695                                 buf,
696                                 &len
697                         ))|| (type!=REG_SZ)
698                 )
699                         strcpy(buf,"yes");
700                 RegCloseKey(hkey);
701         }
702         if (lstrcmpi32A(buf,"yes"))
703                 all=1;
704         pwd=getpwuid(getuid());
705         if (pwd!=NULL && pwd->pw_dir!=NULL)
706         {
707                 char *tmp;
708
709                 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
710                                    strlen(SAVE_CURRENT_USER) + 2 );
711                 strcpy(fn,pwd->pw_dir);
712                 strcat(fn,WINE_PREFIX);
713                 /* create the directory. don't care about errorcodes. */
714                 mkdir(fn,0755); /* drwxr-xr-x */
715                 strcat(fn,"/"SAVE_CURRENT_USER);
716                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
717                 strcpy(tmp,fn);strcat(tmp,".tmp");
718                 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
719                         if (-1==rename(tmp,fn)) {
720                                 perror("rename tmp registry");
721                                 unlink(tmp);
722                         }
723                 }
724                 free(tmp);
725                 free(fn);
726                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
727                 strcpy(fn,pwd->pw_dir);
728                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
729                 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
730                 strcpy(tmp,fn);strcat(tmp,".tmp");
731                 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
732                         if (-1==rename(tmp,fn)) {
733                                 perror("rename tmp registry");
734                                 unlink(tmp);
735                         }
736                 }
737                 free(tmp);
738                 free(fn);
739         } else
740                 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
741 }
742
743
744 /************************ LOAD Registry Function ****************************/
745
746
747
748 /******************************************************************************
749  * _find_or_add_key [Internal]
750  */
751 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
752 {
753         LPKEYSTRUCT     lpxkey,*lplpkey;
754
755         if ((!keyname) || (keyname[0]==0)) {
756                 free(keyname);
757                 return lpkey;
758         }
759         lplpkey= &(lpkey->nextsub);
760         lpxkey  = *lplpkey;
761         while (lpxkey) {
762                 if (    (lpxkey->keyname[0]==keyname[0]) && 
763                         !lstrcmpi32W(lpxkey->keyname,keyname)
764                 )
765                         break;
766                 lplpkey = &(lpxkey->next);
767                 lpxkey  = *lplpkey;
768         }
769         if (lpxkey==NULL) {
770                 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
771                 lpxkey  = *lplpkey;
772                 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
773                 lpxkey->keyname = keyname;
774         } else
775                 free(keyname);
776         return lpxkey;
777 }
778
779 /******************************************************************************
780  * _find_or_add_value [Internal]
781  */
782 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
783                                 LPBYTE data, DWORD len, DWORD lastmodified )
784 {
785         LPKEYVALUE      val=NULL;
786         int             i;
787
788         if (name && !*name) {/* empty string equals default (NULL) value */
789                 free(name);
790                 name = NULL;
791         }
792
793         for (i=0;i<lpkey->nrofvalues;i++) {
794                 val=lpkey->values+i;
795                 if (name==NULL) {
796                         if (val->name==NULL)
797                                 break;
798                 } else {
799                         if (    val->name!=NULL && 
800                                 val->name[0]==name[0] &&
801                                 !lstrcmpi32W(val->name,name)
802                         )
803                                 break;
804                 }
805         }
806         if (i==lpkey->nrofvalues) {
807                 lpkey->values = xrealloc(
808                         lpkey->values,
809                         (++lpkey->nrofvalues)*sizeof(KEYVALUE)
810                 );
811                 val=lpkey->values+i;
812                 memset(val,'\0',sizeof(KEYVALUE));
813                 val->name = name;
814         } else {
815                 if (name)
816                         free(name);
817         }
818         if (val->lastmodified<lastmodified) {
819                 val->lastmodified=lastmodified;
820                 val->type = type;
821                 val->len  = len;
822                 if (val->data) 
823                         free(val->data);
824                 val->data = data;
825         } else
826                 free(data);
827 }
828
829
830 /******************************************************************************
831  * _wine_read_line [Internal]
832  *
833  * reads a line including dynamically enlarging the readbuffer and throwing
834  * away comments
835  */
836 static int _wine_read_line( FILE *F, char **buf, int *len )
837 {
838         char    *s,*curread;
839         int     mylen,curoff;
840
841         curread = *buf;
842         mylen   = *len;
843         **buf   = '\0';
844         while (1) {
845                 while (1) {
846                         s=fgets(curread,mylen,F);
847                         if (s==NULL)
848                                 return 0; /* EOF */
849                         if (NULL==(s=strchr(curread,'\n'))) {
850                                 /* buffer wasn't large enough */
851                                 curoff  = strlen(*buf);
852                                 *buf    = xrealloc(*buf,*len*2);
853                                 curread = *buf + curoff;
854                                 mylen   = *len; /* we filled up the buffer and 
855                                                  * got new '*len' bytes to fill
856                                                  */
857                                 *len    = *len * 2;
858                         } else {
859                                 *s='\0';
860                                 break;
861                         }
862                 }
863                 /* throw away comments */
864                 if (**buf=='#' || **buf==';') {
865                         curread = *buf;
866                         mylen   = *len;
867                         continue;
868                 }
869                 if (s)  /* got end of line */
870                         break;
871         }
872         return 1;
873 }
874
875
876 /******************************************************************************
877  * _wine_read_USTRING [Internal]
878  *
879  * converts a char* into a UNICODE string (up to a special char)
880  * and returns the position exactly after that string
881  */
882 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
883 {
884         char    *s;
885         LPWSTR  ws;
886
887         /* read up to "=" or "\0" or "\n" */
888         s       = buf;
889         if (*s == '=') {
890                 /* empty string is the win3.1 default value(NULL)*/
891                 *str    = NULL;
892                 return s;
893         }
894         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
895         ws      = *str;
896         while (*s && (*s!='\n') && (*s!='=')) {
897                 if (*s!='\\')
898                         *ws++=*((unsigned char*)s++);
899                 else {
900                         s++;
901                         if (!*s) {
902                                 /* Dangling \ ... may only happen if a registry
903                                  * write was short. FIXME: What do to?
904                                  */
905                                  break;
906                         }
907                         if (*s=='\\') {
908                                 *ws++='\\';
909                                 s++;
910                                 continue;
911                         }
912                         if (*s!='u') {
913                                 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
914                                 *ws++='\\';
915                                 *ws++=*s++;
916                         } else {
917                                 char    xbuf[5];
918                                 int     wc;
919
920                                 s++;
921                                 memcpy(xbuf,s,4);xbuf[4]='\0';
922                                 if (!sscanf(xbuf,"%x",&wc))
923                                         WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
924                                 s+=4;
925                                 *ws++   =(unsigned short)wc;
926                         }
927                 }
928         }
929         *ws     = 0;
930         ws      = *str;
931         if (*ws)
932                 *str    = strdupW(*str);
933         else
934                 *str    = NULL;
935         free(ws);
936         return s;
937 }
938
939
940 /******************************************************************************
941  * _wine_loadsubkey [Internal]
942  *
943  * NOTES
944  *    It seems like this is returning a boolean.  Should it?
945  *
946  * RETURNS
947  *    Success: 1
948  *    Failure: 0
949  */
950 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
951                              int *buflen, DWORD optflag )
952 {
953         LPKEYSTRUCT     lpxkey;
954         int             i;
955         char            *s;
956         LPWSTR          name;
957
958     TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
959           *buflen, optflag);
960
961     lpkey->flags |= optflag;
962
963     /* Good.  We already got a line here ... so parse it */
964     lpxkey = NULL;
965     while (1) {
966         i=0;s=*buf;
967         while (*s=='\t') {
968             s++;
969             i++;
970         }
971         if (i>level) {
972             if (lpxkey==NULL) {
973                 WARN(reg,"Got a subhierarchy without resp. key?\n");
974                 return 0;
975             }
976             _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
977             continue;
978         }
979
980                 /* let the caller handle this line */
981                 if (i<level || **buf=='\0')
982                         return 1;
983
984                 /* it can be: a value or a keyname. Parse the name first */
985                 s=_wine_read_USTRING(s,&name);
986
987                 /* switch() default: hack to avoid gotos */
988                 switch (0) {
989                 default:
990                         if (*s=='\0') {
991                                 lpxkey=_find_or_add_key(lpkey,name);
992                         } else {
993                                 LPBYTE          data;
994                                 int             len,lastmodified,type;
995
996                                 if (*s!='=') {
997                                         WARN(reg,"Unexpected character: %c\n",*s);
998                                         break;
999                                 }
1000                                 s++;
1001                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1002                                         WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1003                                         break;
1004                                 }
1005                                 /* skip the 2 , */
1006                                 s=strchr(s,',');s++;
1007                                 s=strchr(s,',');s++;
1008                                 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1009                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
1010                                         if (data)
1011                                                 len = lstrlen32W((LPWSTR)data)*2+2;
1012                                         else    
1013                                                 len = 0;
1014                                 } else {
1015                                         len=strlen(s)/2;
1016                                         data = (LPBYTE)xmalloc(len+1);
1017                                         for (i=0;i<len;i++) {
1018                                                 data[i]=0;
1019                                                 if (*s>='0' && *s<='9')
1020                                                         data[i]=(*s-'0')<<4;
1021                                                 if (*s>='a' && *s<='f')
1022                                                         data[i]=(*s-'a'+'\xa')<<4;
1023                                                 if (*s>='A' && *s<='F')
1024                                                         data[i]=(*s-'A'+'\xa')<<4;
1025                                                 s++;
1026                                                 if (*s>='0' && *s<='9')
1027                                                         data[i]|=*s-'0';
1028                                                 if (*s>='a' && *s<='f')
1029                                                         data[i]|=*s-'a'+'\xa';
1030                                                 if (*s>='A' && *s<='F')
1031                                                         data[i]|=*s-'A'+'\xa';
1032                                                 s++;
1033                                         }
1034                                 }
1035                                 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1036                         }
1037                 }
1038                 /* read the next line */
1039                 if (!_wine_read_line(F,buf,buflen))
1040                         return 1;
1041     }
1042     return 1;
1043 }
1044
1045
1046 /******************************************************************************
1047  * _wine_loadsubreg [Internal]
1048  */
1049 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1050 {
1051         int     ver;
1052         char    *buf;
1053         int     buflen;
1054
1055         buf=xmalloc(10);buflen=10;
1056         if (!_wine_read_line(F,&buf,&buflen)) {
1057                 free(buf);
1058                 return 0;
1059         }
1060         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1061                 free(buf);
1062                 return 0;
1063         }
1064         if (ver!=REGISTRY_SAVE_VERSION) {
1065                 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1066                 free(buf);
1067                 return 0;
1068         }
1069         if (!_wine_read_line(F,&buf,&buflen)) {
1070                 free(buf);
1071                 return 0;
1072         }
1073         if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1074                 free(buf);
1075                 return 0;
1076         }
1077         free(buf);
1078         return 1;
1079 }
1080
1081
1082 /******************************************************************************
1083  * _wine_loadreg [Internal]
1084  */
1085 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1086 {
1087     FILE *F;
1088
1089     TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1090
1091     F = fopen(fn,"rb");
1092     if (F==NULL) {
1093         WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1094         return;
1095     }
1096     if (!_wine_loadsubreg(F,lpkey,optflag)) {
1097         fclose(F);
1098         unlink(fn);
1099         return;
1100     }
1101     fclose(F);
1102 }
1103
1104
1105 /******************************************************************************
1106  * _copy_registry [Internal]
1107  */
1108 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1109 {
1110         LPKEYSTRUCT     lpxkey;
1111         int             j;
1112         LPKEYVALUE      valfrom;
1113
1114         from=from->nextsub;
1115         while (from) {
1116                 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1117
1118                 for (j=0;j<from->nrofvalues;j++) {
1119                         LPWSTR  name;
1120                         LPBYTE  data;
1121
1122                         valfrom = from->values+j;
1123                         name=valfrom->name;
1124                         if (name) name=strdupW(name);
1125                         data=(LPBYTE)xmalloc(valfrom->len);
1126                         memcpy(data,valfrom->data,valfrom->len);
1127
1128                         _find_or_add_value(
1129                                 lpxkey,
1130                                 name,
1131                                 valfrom->type,
1132                                 data,
1133                                 valfrom->len,
1134                                 valfrom->lastmodified
1135                         );
1136                 }
1137                 _copy_registry(from,lpxkey);
1138                 from = from->next;
1139         }
1140 }
1141
1142
1143 /* WINDOWS 95 REGISTRY LOADER */
1144 /* 
1145  * Structure of a win95 registry database.
1146  * main header:
1147  * 0 :  "CREG"  - magic
1148  * 4 :  DWORD version
1149  * 8 :  DWORD offset_of_RGDB_part
1150  * 0C..0F:      ? (someone fill in please)
1151  * 10:  WORD    number of RGDB blocks
1152  * 12:  WORD    ?
1153  * 14:  WORD    always 0000?
1154  * 16:  WORD    always 0001?
1155  * 18..1F:      ? (someone fill in please)
1156  *
1157  * 20: RGKN_section:
1158  *   header:
1159  *      0 :             "RGKN"  - magic
1160  *      4 : DWORD       offset to first RGDB section
1161  *      8 : DWORD       offset to the root record
1162  *      C..0x1B:        ? (fill in)
1163  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1164  *
1165  *   Disk Key Entry Structure:
1166  *      00: DWORD       - Free entry indicator(?)
1167  *      04: DWORD       - Hash = sum of bytes of keyname
1168  *      08: DWORD       - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1169  *      0C: DWORD       - disk address of PreviousLevel Key.
1170  *      10: DWORD       - disk address of Next Sublevel Key.
1171  *      14: DWORD       - disk address of Next Key (on same level).
1172  * DKEP>18: WORD        - Nr, Low Significant part.
1173  *      1A: WORD        - Nr, High Significant part.
1174  *
1175  * The disk address always points to the nr part of the previous key entry 
1176  * of the referenced key. Don't ask me why, or even if I got this correct
1177  * from staring at 1kg of hexdumps. (DKEP)
1178  *
1179  * The High significant part of the structure seems to equal the number
1180  * of the RGDB section. The low significant part is a unique ID within
1181  * that RGDB section
1182  *
1183  * There are two minor corrections to the position of that structure.
1184  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
1185  *    the DKE reread from there.
1186  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1187  * CPS - I have not experienced the above phenomenon in my registry files
1188  *
1189  * RGDB_section:
1190  *      00:             "RGDB"  - magic
1191  *      04: DWORD       offset to next RGDB section
1192  *      08: DWORD       ?
1193  *      0C: WORD        always 000d?
1194  *      0E: WORD        RGDB block number
1195  *      10:     DWORD   ? (equals value at offset 4 - value at offset 8)
1196  *      14..1F:         ?
1197  *      20.....:        disk keys
1198  *
1199  * disk key:
1200  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
1201  *      08:     WORD    nrLS            - low significant part of NR
1202  *      0A:     WORD    nrHS            - high significant part of NR
1203  *      0C:     DWORD   bytesused       - bytes used in this structure.
1204  *      10:     WORD    name_len        - length of name in bytes. without \0
1205  *      12:     WORD    nr_of_values    - number of values.
1206  *      14:     char    name[name_len]  - name string. No \0.
1207  *      14+name_len: disk values
1208  *      nextkeyoffset: ... next disk key
1209  *
1210  * disk value:
1211  *      00:     DWORD   type            - value type (hmm, could be WORD too)
1212  *      04:     DWORD                   - unknown, usually 0
1213  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
1214  *      0C:     WORD    datalen         - length of Data.
1215  *      10:     char    name[namelen]   - name, no \0
1216  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
1217  *      10+namelen+datalen: next values or disk key
1218  *
1219  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1220  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1221  * structure) and reading another RGDB_section.
1222  * repeat until end of file.
1223  *
1224  * An interesting relationship exists in RGDB_section. The value at offset
1225  * 10 equals the value at offset 4 minus the value at offset 8. I have no
1226  * idea at the moment what this means.  (Kevin Cozens)
1227  *
1228  * FIXME: this description needs some serious help, yes.
1229  */
1230
1231 struct  _w95keyvalue {
1232         unsigned long           type;
1233         unsigned short          datalen;
1234         char                    *name;
1235         unsigned char           *data;
1236         unsigned long           x1;
1237         int                     lastmodified;
1238 };
1239
1240 struct  _w95key {
1241         char                    *name;
1242         int                     nrofvals;
1243         struct  _w95keyvalue    *values;
1244         struct _w95key          *prevlvl;
1245         struct _w95key          *nextsub;
1246         struct _w95key          *next;
1247 };
1248
1249
1250 struct _w95_info {
1251   char *rgknbuffer;
1252   int  rgknsize;
1253   char *rgdbbuffer;
1254   int  rgdbsize;
1255   int  depth;
1256   int  lastmodified;
1257 };
1258
1259
1260 /******************************************************************************
1261  * _w95_processKey [Internal]
1262  */
1263 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey, 
1264                                    int nrLS, int nrMS, struct _w95_info *info )
1265
1266 {
1267   /* Disk Key Header structure (RGDB part) */
1268         struct  dkh {
1269                 unsigned long           nextkeyoff; 
1270                 unsigned short          nrLS;
1271                 unsigned short          nrMS;
1272                 unsigned long           bytesused;
1273                 unsigned short          keynamelen;
1274                 unsigned short          values;
1275                 unsigned long           xx1;
1276                 /* keyname */
1277                 /* disk key values or nothing */
1278         };
1279         /* Disk Key Value structure */
1280         struct  dkv {
1281                 unsigned long           type;
1282                 unsigned long           x1;
1283                 unsigned short          valnamelen;
1284                 unsigned short          valdatalen;
1285                 /* valname, valdata */
1286         };
1287
1288         
1289         struct  dkh dkh;
1290         int     bytesread = 0;
1291         char    *rgdbdata = info->rgdbbuffer;
1292         int     nbytes = info->rgdbsize;
1293         char    *curdata = rgdbdata;
1294         char    *end = rgdbdata + nbytes;
1295         int     off_next_rgdb;
1296         char    *next = rgdbdata;
1297         int     nrgdb, i;
1298         LPKEYSTRUCT     lpxkey;
1299         
1300         do {
1301           curdata = next;
1302           if (strncmp(curdata, "RGDB", 4)) return (NULL);
1303             
1304           memcpy(&off_next_rgdb,curdata+4,4);
1305           next = curdata + off_next_rgdb;
1306           nrgdb = (int) *((short *)curdata + 7);
1307
1308         } while (nrgdb != nrMS && (next < end));
1309
1310         /* curdata now points to the start of the right RGDB section */
1311         curdata += 0x20;
1312
1313 #define XREAD(whereto,len) \
1314         if ((curdata + len) <end) {\
1315                 memcpy(whereto,curdata,len);\
1316                 curdata+=len;\
1317                 bytesread+=len;\
1318         }
1319
1320         while (curdata < next) {
1321           struct        dkh *xdkh = (struct dkh*)curdata;
1322
1323           bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1324           if (xdkh->nrLS == nrLS) {
1325                 memcpy(&dkh,xdkh,sizeof(dkh));
1326                 curdata += sizeof(dkh);
1327                 break;
1328           }
1329           curdata += xdkh->nextkeyoff;
1330         };
1331
1332         if (dkh.nrLS != nrLS) return (NULL);
1333
1334         if (nrgdb != dkh.nrMS)
1335           return (NULL);
1336
1337         assert((dkh.keynamelen<2) || curdata[0]);
1338         lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1339         curdata += dkh.keynamelen;
1340
1341         for (i=0;i< dkh.values; i++) {
1342           struct dkv dkv;
1343           LPBYTE data;
1344           int len;
1345           LPWSTR name;
1346
1347           XREAD(&dkv,sizeof(dkv));
1348
1349           name = strcvtA2W(curdata, dkv.valnamelen);
1350           curdata += dkv.valnamelen;
1351
1352           if ((1 << dkv.type) & UNICONVMASK) {
1353             data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1354             len = 2*(dkv.valdatalen + 1);
1355           } else {
1356             /* I don't think we want to NULL terminate all data */
1357             data = xmalloc(dkv.valdatalen);
1358             memcpy (data, curdata, dkv.valdatalen);
1359             len = dkv.valdatalen;
1360           }
1361
1362           curdata += dkv.valdatalen;
1363           
1364           _find_or_add_value(
1365                              lpxkey,
1366                              name,
1367                              dkv.type,
1368                              data,
1369                              len,
1370                              info->lastmodified
1371                              );
1372         }
1373         return (lpxkey);
1374 }
1375
1376 /******************************************************************************
1377  * _w95_walkrgkn [Internal]
1378  */
1379 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off, 
1380                            struct _w95_info *info )
1381
1382 {
1383   /* Disk Key Entry structure (RGKN part) */
1384   struct        dke {
1385     unsigned long               x1;
1386     unsigned long               x2;
1387     unsigned long               x3;/*usually 0xFFFFFFFF */
1388     unsigned long               prevlvl;
1389     unsigned long               nextsub;
1390     unsigned long               next;
1391     unsigned short              nrLS;
1392     unsigned short              nrMS;
1393   } *dke = (struct dke *)off;
1394   LPKEYSTRUCT  lpxkey;
1395
1396   if (dke == NULL) {
1397     dke = (struct dke *) ((char *)info->rgknbuffer);
1398   }
1399
1400   lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1401   /* XXX <-- This is a hack*/
1402   if (!lpxkey) {
1403     lpxkey = prevkey;
1404   }
1405
1406   if (dke->nextsub != -1 && 
1407       ((dke->nextsub - 0x20) < info->rgknsize) 
1408       && (dke->nextsub > 0x20)) {
1409     
1410     _w95_walkrgkn(lpxkey, 
1411                   info->rgknbuffer + dke->nextsub - 0x20, 
1412                   info);
1413   }
1414   
1415   if (dke->next != -1 && 
1416       ((dke->next - 0x20) < info->rgknsize) && 
1417       (dke->next > 0x20)) {
1418     _w95_walkrgkn(prevkey,  
1419                   info->rgknbuffer + dke->next - 0x20,
1420                   info);
1421   }
1422
1423   return;
1424 }
1425
1426
1427 /******************************************************************************
1428  * _w95_loadreg [Internal]
1429  */
1430 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1431 {
1432         HFILE32         hfd;
1433         char            magic[5];
1434         unsigned long   where,version,rgdbsection,end;
1435         struct          _w95_info info;
1436         OFSTRUCT        ofs;
1437         BY_HANDLE_FILE_INFORMATION hfdinfo;
1438
1439         TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1440         hfd=OpenFile32(fn,&ofs,OF_READ);
1441         if (hfd==HFILE_ERROR32)
1442                 return;
1443         magic[4]=0;
1444         if (4!=_lread32(hfd,magic,4))
1445                 return;
1446         if (strcmp(magic,"CREG")) {
1447                 WARN(reg,"%s is not a w95 registry.\n",fn);
1448                 return;
1449         }
1450         if (4!=_lread32(hfd,&version,4))
1451                 return;
1452         if (4!=_lread32(hfd,&rgdbsection,4))
1453                 return;
1454         if (-1==_llseek32(hfd,0x20,SEEK_SET))
1455                 return;
1456         if (4!=_lread32(hfd,magic,4))
1457                 return;
1458         if (strcmp(magic,"RGKN")) {
1459                 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1460                 return;
1461         }
1462
1463         /* STEP 1: Keylink structures */
1464         if (-1==_llseek32(hfd,0x40,SEEK_SET))
1465                 return;
1466         where   = 0x40;
1467         end     = rgdbsection;
1468
1469         info.rgknsize = end - where;
1470         info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1471         if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1472                 return;
1473
1474         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1475                 return;
1476
1477         end = hfdinfo.nFileSizeLow;
1478         info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1479
1480         if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1481                 return;
1482
1483         info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1484         info.rgdbsize = end - rgdbsection;
1485
1486         if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1487                 return;
1488         _lclose32(hfd);
1489
1490         _w95_walkrgkn(lpkey, NULL, &info);
1491
1492         free (info.rgdbbuffer);
1493         free (info.rgknbuffer);
1494 }
1495
1496
1497 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1498
1499 /*
1500     reghack - windows 3.11 registry data format demo program.
1501
1502     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1503     a combined hash table and tree description, and finally a text table.
1504
1505     The header is obvious from the struct header. The taboff1 and taboff2
1506     fields are always 0x20, and their usage is unknown.
1507
1508     The 8-byte entry table has various entry types.
1509
1510     tabent[0] is a root index. The second word has the index of the root of
1511             the directory.
1512     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1513             the index of the key/value that has that hash. Data with the same
1514             hash value are on a circular list. The other three words in the
1515             hash entry are always zero.
1516     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1517             entry: dirent and keyent/valent. They are identified by context.
1518     tabent[freeidx] is the first free entry. The first word in a free entry
1519             is the index of the next free entry. The last has 0 as a link.
1520             The other three words in the free list are probably irrelevant.
1521
1522     Entries in text table are preceeded by a word at offset-2. This word
1523     has the value (2*index)+1, where index is the referring keyent/valent
1524     entry in the table. I have no suggestion for the 2* and the +1.
1525     Following the word, there are N bytes of data, as per the keyent/valent
1526     entry length. The offset of the keyent/valent entry is from the start
1527     of the text table to the first data byte.
1528
1529     This information is not available from Microsoft. The data format is
1530     deduced from the reg.dat file by me. Mistakes may
1531     have been made. I claim no rights and give no guarantees for this program.
1532
1533     Tor Sjøwall, tor@sn.no
1534 */
1535
1536 /* reg.dat header format */
1537 struct _w31_header {
1538         char            cookie[8];      /* 'SHCC3.10' */
1539         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1540         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1541         unsigned long   tabcnt;         /* number of entries in index table */
1542         unsigned long   textoff;        /* offset of text part */
1543         unsigned long   textsize;       /* byte size of text part */
1544         unsigned short  hashsize;       /* hash size */
1545         unsigned short  freeidx;        /* free index */
1546 };
1547
1548 /* generic format of table entries */
1549 struct _w31_tabent {
1550         unsigned short w0, w1, w2, w3;
1551 };
1552
1553 /* directory tabent: */
1554 struct _w31_dirent {
1555         unsigned short  sibling_idx;    /* table index of sibling dirent */
1556         unsigned short  child_idx;      /* table index of child dirent */
1557         unsigned short  key_idx;        /* table index of key keyent */
1558         unsigned short  value_idx;      /* table index of value valent */
1559 };
1560
1561 /* key tabent: */
1562 struct _w31_keyent {
1563         unsigned short  hash_idx;       /* hash chain index for string */
1564         unsigned short  refcnt;         /* reference count */
1565         unsigned short  length;         /* length of string */
1566         unsigned short  string_off;     /* offset of string in text table */
1567 };
1568
1569 /* value tabent: */
1570 struct _w31_valent {
1571         unsigned short  hash_idx;       /* hash chain index for string */
1572         unsigned short  refcnt;         /* reference count */
1573         unsigned short  length;         /* length of string */
1574         unsigned short  string_off;     /* offset of string in text table */
1575 };
1576
1577 /* recursive helper function to display a directory tree */
1578 void
1579 __w31_dumptree( unsigned short idx,
1580                 unsigned char *txt,
1581                 struct _w31_tabent *tab,
1582                 struct _w31_header *head,
1583                 LPKEYSTRUCT     lpkey,
1584                 time_t          lastmodified,
1585                 int             level
1586 ) {
1587         struct _w31_dirent      *dir;
1588         struct _w31_keyent      *key;
1589         struct _w31_valent      *val;
1590         LPKEYSTRUCT             xlpkey = NULL;
1591         LPWSTR                  name,value;
1592         static char             tail[400];
1593
1594         while (idx!=0) {
1595                 dir=(struct _w31_dirent*)&tab[idx];
1596
1597                 if (dir->key_idx) {
1598                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1599
1600                         memcpy(tail,&txt[key->string_off],key->length);
1601                         tail[key->length]='\0';
1602                         /* all toplevel entries AND the entries in the 
1603                          * toplevel subdirectory belong to \SOFTWARE\Classes
1604                          */
1605                         if (!level && !lstrcmp32A(tail,".classes")) {
1606                                 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1607                                 idx=dir->sibling_idx;
1608                                 continue;
1609                         }
1610                         name=strdupA2W(tail);
1611
1612                         xlpkey=_find_or_add_key(lpkey,name);
1613
1614                         /* only add if leaf node or valued node */
1615                         if (dir->value_idx!=0||dir->child_idx==0) {
1616                                 if (dir->value_idx) {
1617                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1618                                         memcpy(tail,&txt[val->string_off],val->length);
1619                                         tail[val->length]='\0';
1620                                         value=strdupA2W(tail);
1621                                         _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1622                                 }
1623                         }
1624                 } else {
1625                         TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1626                 }
1627                 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1628                 idx=dir->sibling_idx;
1629         }
1630 }
1631
1632
1633 /******************************************************************************
1634  * _w31_loadreg [Internal]
1635  */
1636 void _w31_loadreg(void) {
1637         HFILE32                 hf;
1638         struct _w31_header      head;
1639         struct _w31_tabent      *tab;
1640         unsigned char           *txt;
1641         int                     len;
1642         OFSTRUCT                ofs;
1643         BY_HANDLE_FILE_INFORMATION hfinfo;
1644         time_t                  lastmodified;
1645         LPKEYSTRUCT             lpkey;
1646
1647         TRACE(reg,"(void)\n");
1648
1649         hf = OpenFile32("reg.dat",&ofs,OF_READ);
1650         if (hf==HFILE_ERROR32)
1651                 return;
1652
1653         /* read & dump header */
1654         if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1655                 ERR(reg, "reg.dat is too short.\n");
1656                 _lclose32(hf);
1657                 return;
1658         }
1659         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1660                 ERR(reg, "reg.dat has bad signature.\n");
1661                 _lclose32(hf);
1662                 return;
1663         }
1664
1665         len = head.tabcnt * sizeof(struct _w31_tabent);
1666         /* read and dump index table */
1667         tab = xmalloc(len);
1668         if (len!=_lread32(hf,tab,len)) {
1669                 ERR(reg,"couldn't read %d bytes.\n",len); 
1670                 free(tab);
1671                 _lclose32(hf);
1672                 return;
1673         }
1674
1675         /* read text */
1676         txt = xmalloc(head.textsize);
1677         if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1678                 ERR(reg,"couldn't seek to textblock.\n"); 
1679                 free(tab);
1680                 free(txt);
1681                 _lclose32(hf);
1682                 return;
1683         }
1684         if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1685                 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize); 
1686                 free(tab);
1687                 free(txt);
1688                 _lclose32(hf);
1689                 return;
1690         }
1691
1692         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1693                 ERR(reg,"GetFileInformationByHandle failed?.\n"); 
1694                 free(tab);
1695                 free(txt);
1696                 _lclose32(hf);
1697                 return;
1698         }
1699         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1700         lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1701         __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1702         free(tab);
1703         free(txt);
1704         _lclose32(hf);
1705         return;
1706 }
1707
1708
1709 /**********************************************************************************
1710  * SHELL_LoadRegistry [Internal]
1711  */
1712 void SHELL_LoadRegistry( void )
1713 {
1714         char    *fn;
1715         struct  passwd  *pwd;
1716         LPKEYSTRUCT     lpkey;
1717         HKEY            hkey;
1718
1719         TRACE(reg,"(void)\n");
1720
1721         /* Load windows 3.1 entries */
1722         _w31_loadreg();
1723         /* Load windows 95 entries */
1724         _w95_loadreg("C:\\system.1st",  lookup_hkey(HKEY_LOCAL_MACHINE));
1725         _w95_loadreg("system.dat",      lookup_hkey(HKEY_LOCAL_MACHINE));
1726         _w95_loadreg("user.dat",        lookup_hkey(HKEY_USERS));
1727
1728         /* the global user default is loaded under HKEY_USERS\\.Default */
1729         RegCreateKey16(HKEY_USERS,".Default",&hkey);
1730         lpkey = lookup_hkey(hkey);
1731         if(!lpkey)
1732             WARN(reg,"Could not create global user default key\n");
1733         _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1734
1735         /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1736         _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1737         RegCloseKey(hkey);
1738
1739         /* the global machine defaults */
1740         _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1741
1742         /* load the user saved registries */
1743
1744         /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1745
1746         pwd=getpwuid(getuid());
1747         if (pwd!=NULL && pwd->pw_dir!=NULL) {
1748                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1749                 strcpy(fn,pwd->pw_dir);
1750                 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1751                 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1752                 free(fn);
1753                 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1754                 strcpy(fn,pwd->pw_dir);
1755                 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1756                 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1757                 free(fn);
1758         } else
1759                 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1760         if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1761                 DWORD   junk,type,len;
1762                 char    data[5];
1763
1764                 len=4;
1765                 if ((   RegQueryValueEx32A(
1766                                 hkey,
1767                                 VAL_SAVEUPDATED,
1768                                 &junk,
1769                                 &type,
1770                                 data,
1771                                 &len
1772                         )!=ERROR_SUCCESS) ||
1773                         type != REG_SZ
1774                 )
1775                         RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1776                 RegCloseKey(hkey);
1777         }
1778 }
1779
1780
1781 /********************* API FUNCTIONS ***************************************/
1782 /*
1783  * Open Keys.
1784  *
1785  * All functions are stubs to RegOpenKeyEx32W where all the
1786  * magic happens. 
1787  *
1788  * Callpath:
1789  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1790  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
1791  */
1792
1793
1794 /******************************************************************************
1795  * RegOpenKeyEx32W [ADVAPI32.150]
1796  * Opens the specified key
1797  *
1798  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1799  *
1800  * PARAMS
1801  *    hkey       [I] Handle of open key
1802  *    lpszSubKey [I] Name of subkey to open
1803  *    dwReserved [I] Reserved - must be zero
1804  *    samDesired [I] Security access mask
1805  *    retkey     [O] Address of handle of open key
1806  *
1807  * RETURNS
1808  *    Success: ERROR_SUCCESS
1809  *    Failure: Error code
1810  */
1811 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1812                               REGSAM samDesired, LPHKEY retkey )
1813 {
1814         LPKEYSTRUCT     lpNextKey,lpxkey;
1815         LPWSTR          *wps;
1816         int             wpc,i;
1817
1818     TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1819           samDesired,retkey);
1820
1821     lpNextKey = lookup_hkey( hkey );
1822     if (!lpNextKey)
1823         return ERROR_INVALID_HANDLE;
1824
1825     if (!lpszSubKey || !*lpszSubKey) {
1826         /* Either NULL or pointer to empty string, so return a new handle
1827            to the original hkey */
1828         currenthandle += 2;
1829         add_handle(currenthandle,lpNextKey,samDesired);
1830         *retkey=currenthandle;
1831         return ERROR_SUCCESS;
1832     }
1833
1834     if (lpszSubKey[0] == '\\') {
1835         WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1836         return ERROR_BAD_PATHNAME;
1837     }
1838
1839         split_keypath(lpszSubKey,&wps,&wpc);
1840         i = 0;
1841         while ((i<wpc) && (wps[i][0]=='\0')) i++;
1842         lpxkey = lpNextKey;
1843
1844     while (wps[i]) {
1845         lpxkey=lpNextKey->nextsub;
1846         while (lpxkey) {
1847             if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1848                 break;
1849             }
1850             lpxkey=lpxkey->next;
1851         }
1852
1853         if (!lpxkey) {
1854             TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1855             FREE_KEY_PATH;
1856             return ERROR_FILE_NOT_FOUND;
1857         }
1858         i++;
1859         lpNextKey = lpxkey;
1860     }
1861
1862     currenthandle += 2;
1863     add_handle(currenthandle,lpxkey,samDesired);
1864     *retkey = currenthandle;
1865     TRACE(reg,"  Returning %x\n", currenthandle);
1866     FREE_KEY_PATH;
1867     return ERROR_SUCCESS;
1868 }
1869
1870
1871 /******************************************************************************
1872  * RegOpenKeyEx32A [ADVAPI32.149]
1873  */
1874 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1875                               REGSAM samDesired, LPHKEY retkey )
1876 {
1877     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1878     DWORD ret;
1879
1880     TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1881           samDesired,retkey);
1882     ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1883     free(lpszSubKeyW);
1884     return ret;
1885 }
1886
1887
1888 /******************************************************************************
1889  * RegOpenKey32W [ADVAPI32.151]
1890  *
1891  * PARAMS
1892  *    hkey       [I] Handle of open key
1893  *    lpszSubKey [I] Address of name of subkey to open
1894  *    retkey     [O] Address of handle of open key
1895  *
1896  * RETURNS
1897  *    Success: ERROR_SUCCESS
1898  *    Failure: Error code
1899  */
1900 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1901 {
1902     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1903     return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1904 }
1905
1906
1907 /******************************************************************************
1908  * RegOpenKey32A [ADVAPI32.148]
1909  */
1910 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1911 {
1912     DWORD ret;
1913     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1914     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1915     ret =  RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1916     free(lpszSubKeyW);
1917     return ret;
1918 }
1919
1920
1921 /******************************************************************************
1922  * RegOpenKey16 [SHELL.1] [KERNEL.217]
1923  */
1924 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1925 {
1926     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1927     return RegOpenKey32A( hkey, lpszSubKey, retkey );
1928 }
1929
1930
1931 /* 
1932  * Create keys
1933  * 
1934  * All those functions convert their respective 
1935  * arguments and call RegCreateKeyExW at the end.
1936  *
1937  * We stay away from the Ex functions as long as possible because there are
1938  * differences in the return values
1939  *
1940  * Callpath:
1941  *                                      RegCreateKeyEx32A \
1942  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W   -> RegCreateKeyEx32W
1943  */
1944
1945
1946 /******************************************************************************
1947  * RegCreateKeyEx32W [ADVAPI32.131]
1948  *
1949  * PARAMS
1950  *    hkey         [I] Handle of an open key
1951  *    lpszSubKey   [I] Address of subkey name
1952  *    dwReserved   [I] Reserved - must be 0
1953  *    lpszClass    [I] Address of class string
1954  *    fdwOptions   [I] Special options flag
1955  *    samDesired   [I] Desired security access
1956  *    lpSecAttribs [I] Address of key security structure
1957  *    retkey       [O] Address of buffer for opened handle
1958  *    lpDispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1959  */
1960 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, 
1961                                 DWORD dwReserved, LPWSTR lpszClass, 
1962                                 DWORD fdwOptions, REGSAM samDesired,
1963                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
1964                                 LPHKEY retkey, LPDWORD lpDispos )
1965 {
1966         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
1967         LPWSTR          *wps;
1968         int             wpc,i;
1969
1970     TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1971                 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1972                 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1973
1974     lpNextKey = lookup_hkey(hkey);
1975     if (!lpNextKey)
1976         return ERROR_INVALID_HANDLE;
1977
1978     /* Check for valid options */
1979     switch(fdwOptions) {
1980         case REG_OPTION_NON_VOLATILE:
1981         case REG_OPTION_VOLATILE:
1982         case REG_OPTION_BACKUP_RESTORE:
1983             break;
1984         default:
1985             return ERROR_INVALID_PARAMETER;
1986     }
1987
1988     /* Sam has to be a combination of the following */
1989     if (!(samDesired & 
1990           (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY | 
1991            KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1992            KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1993         return ERROR_INVALID_PARAMETER;
1994
1995         if (!lpszSubKey || !*lpszSubKey) {
1996                 currenthandle += 2;
1997                 add_handle(currenthandle,lpNextKey,samDesired);
1998                 *retkey=currenthandle;
1999                 TRACE(reg, "Returning %x\n", currenthandle);
2000                 lpNextKey->flags|=REG_OPTION_TAINTED;
2001                 return ERROR_SUCCESS;
2002         }
2003
2004     if (lpszSubKey[0] == '\\') {
2005         WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2006         return ERROR_BAD_PATHNAME;
2007     }
2008
2009         split_keypath(lpszSubKey,&wps,&wpc);
2010         i       = 0;
2011         while ((i<wpc) && (wps[i][0]=='\0')) i++;
2012         lpxkey  = lpNextKey;
2013         while (wps[i]) {
2014                 lpxkey=lpNextKey->nextsub;
2015                 while (lpxkey) {
2016                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2017                                 break;
2018                         lpxkey=lpxkey->next;
2019                 }
2020                 if (!lpxkey)
2021                         break;
2022                 i++;
2023                 lpNextKey       = lpxkey;
2024         }
2025         if (lpxkey) {
2026                 currenthandle += 2;
2027                 add_handle(currenthandle,lpxkey,samDesired);
2028                 lpxkey->flags  |= REG_OPTION_TAINTED;
2029                 *retkey         = currenthandle;
2030                 TRACE(reg, "Returning %x\n", currenthandle);
2031                 if (lpDispos)
2032                         *lpDispos       = REG_OPENED_EXISTING_KEY;
2033                 FREE_KEY_PATH;
2034                 return ERROR_SUCCESS;
2035         }
2036
2037         /* Good.  Now the hard part */
2038         while (wps[i]) {
2039                 lplpPrevKey     = &(lpNextKey->nextsub);
2040                 lpxkey          = *lplpPrevKey;
2041                 while (lpxkey) {
2042                         lplpPrevKey     = &(lpxkey->next);
2043                         lpxkey          = *lplpPrevKey;
2044                 }
2045                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2046                 if (!*lplpPrevKey) {
2047                         FREE_KEY_PATH;
2048                         TRACE(reg, "Returning OUTOFMEMORY\n");
2049                         return ERROR_OUTOFMEMORY;
2050                 }
2051                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2052                 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2053                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2054                 (*lplpPrevKey)->next    = NULL;
2055                 (*lplpPrevKey)->nextsub = NULL;
2056                 (*lplpPrevKey)->values  = NULL;
2057                 (*lplpPrevKey)->nrofvalues = 0;
2058                 (*lplpPrevKey)->flags   = REG_OPTION_TAINTED;
2059                 if (lpszClass)
2060                         (*lplpPrevKey)->class = strdupW(lpszClass);
2061                 else
2062                         (*lplpPrevKey)->class = NULL;
2063                 lpNextKey       = *lplpPrevKey;
2064                 i++;
2065         }
2066         currenthandle += 2;
2067         add_handle(currenthandle,lpNextKey,samDesired);
2068
2069         /*FIXME: flag handling correct? */
2070         lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2071         if (lpszClass)
2072                 lpNextKey->class = strdupW(lpszClass);
2073         else
2074                 lpNextKey->class = NULL;
2075         *retkey         = currenthandle;
2076         TRACE(reg, "Returning %x\n", currenthandle);
2077         if (lpDispos)
2078                 *lpDispos       = REG_CREATED_NEW_KEY;
2079         FREE_KEY_PATH;
2080         return ERROR_SUCCESS;
2081 }
2082
2083
2084 /******************************************************************************
2085  * RegCreateKeyEx32A [ADVAPI32.130]
2086  */
2087 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2088                                 LPSTR lpszClass, DWORD fdwOptions, 
2089                                 REGSAM samDesired, 
2090                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
2091                                 LPHKEY retkey, LPDWORD lpDispos )
2092 {
2093     LPWSTR lpszSubKeyW, lpszClassW;
2094     DWORD  ret;
2095
2096     TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2097           dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2098           retkey,lpDispos);
2099
2100     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2101     lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2102
2103     ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW, 
2104                              fdwOptions, samDesired, lpSecAttribs, retkey, 
2105                              lpDispos );
2106
2107     if(lpszSubKeyW) free(lpszSubKeyW);
2108     if(lpszClassW) free(lpszClassW);
2109
2110     return ret;
2111 }
2112
2113
2114 /******************************************************************************
2115  * RegCreateKey32W [ADVAPI32.132]
2116  */
2117 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2118 {
2119     DWORD junk;
2120     LPKEYSTRUCT lpNextKey;
2121
2122     TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2123
2124     /* This check is here because the return value is different than the
2125        one from the Ex functions */
2126     lpNextKey = lookup_hkey(hkey);
2127     if (!lpNextKey)
2128         return ERROR_BADKEY;
2129
2130     return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL, 
2131                               REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2132                               retkey, &junk);
2133 }
2134
2135
2136 /******************************************************************************
2137  * RegCreateKey32A [ADVAPI32.129]
2138  */
2139 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2140 {
2141     DWORD ret;
2142     LPWSTR lpszSubKeyW;
2143
2144     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2145     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2146     ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2147     if(lpszSubKeyW) free(lpszSubKeyW);
2148     return ret;
2149 }
2150
2151
2152 /******************************************************************************
2153  * RegCreateKey16 [SHELL.2] [KERNEL.218]
2154  */
2155 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2156 {
2157     TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2158     return RegCreateKey32A( hkey, lpszSubKey, retkey );
2159 }
2160
2161
2162 /* 
2163  * Query Value Functions
2164  * Win32 differs between keynames and valuenames. 
2165  * multiple values may belong to one key, the special value
2166  * with name NULL is the default value used by the win31
2167  * compat functions.
2168  *
2169  * Callpath:
2170  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2171  *                                        RegQueryValue32W -> RegQueryValueEx32W
2172  */
2173
2174
2175 /******************************************************************************
2176  * RegQueryValueEx32W [ADVAPI32.158]
2177  * Retrieves type and data for a specified name associated with an open key
2178  *
2179  * PARAMS
2180  *    hkey          [I]   Handle of key to query
2181  *    lpValueName   [I]   Name of value to query
2182  *    lpdwReserved  [I]   Reserved - must be NULL
2183  *    lpdwType      [O]   Address of buffer for value type.  If NULL, the type
2184  *                        is not required.
2185  *    lpbData       [O]   Address of data buffer.  If NULL, the actual data is
2186  *                        not required.
2187  *    lpcbData      [I/O] Address of data buffer size
2188  *
2189  * RETURNS 
2190  *    ERROR_SUCCESS:   Success
2191  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2192  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
2193  */
2194 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2195                                  LPDWORD lpdwReserved, LPDWORD lpdwType,
2196                                  LPBYTE lpbData, LPDWORD lpcbData )
2197 {
2198         LPKEYSTRUCT     lpkey;
2199         int             i;
2200         DWORD           ret;
2201
2202         TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2203           lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2204
2205         lpkey = lookup_hkey(hkey);
2206
2207         if (!lpkey)
2208           return ERROR_INVALID_HANDLE;
2209
2210         if ((lpbData && ! lpcbData) || lpdwReserved)
2211           return ERROR_INVALID_PARAMETER;
2212
2213         /* An empty name string is equivalent to NULL */
2214         if (lpValueName && !*lpValueName)
2215           lpValueName = NULL;
2216
2217         if (lpValueName==NULL) 
2218         { /* Use key's unnamed or default value, if any */
2219           for (i=0;i<lpkey->nrofvalues;i++)
2220             if (lpkey->values[i].name==NULL)
2221               break;
2222         } 
2223         else 
2224         { /* Search for the key name */
2225           for (i=0;i<lpkey->nrofvalues;i++)
2226             if ( lpkey->values[i].name && !lstrcmpi32W(lpValueName,lpkey->values[i].name))
2227               break;
2228         }
2229
2230         if (i==lpkey->nrofvalues) 
2231         { TRACE(reg," Key not found\n");
2232           if (lpValueName==NULL) 
2233           { /* Empty keyname not found */
2234             if (lpbData) 
2235             { *(WCHAR*)lpbData = 0;
2236               *lpcbData = 2;
2237             }
2238             if (lpdwType)
2239               *lpdwType = REG_SZ;
2240             TRACE(reg, " Returning an empty string\n");
2241             return ERROR_SUCCESS;
2242           }
2243           return ERROR_FILE_NOT_FOUND;
2244         }
2245
2246         ret = ERROR_SUCCESS;
2247
2248         if (lpdwType)                                   /* type required ?*/
2249           *lpdwType = lpkey->values[i].type;
2250
2251         if (lpbData)                                    /* data required ?*/
2252         { if (*lpcbData >= lpkey->values[i].len)        /* buffer large enought ?*/
2253             memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2254           else
2255             ret = ERROR_MORE_DATA;
2256         }
2257
2258         if (lpcbData)                                   /* size required ?*/
2259         { *lpcbData = lpkey->values[i].len;
2260         }
2261
2262         debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
2263
2264         TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2265
2266         return ret;
2267 }
2268
2269
2270 /******************************************************************************
2271  * RegQueryValue32W [ADVAPI32.159]
2272  */
2273 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2274                                LPDWORD lpcbData )
2275 {
2276         HKEY    xhkey;
2277         DWORD   ret,lpdwType;
2278
2279     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2280           lpcbData?*lpcbData:0);
2281
2282     /* Only open subkey, if we really do descend */
2283     if (lpszSubKey && *lpszSubKey) {
2284         ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2285         if (ret != ERROR_SUCCESS) {
2286             WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2287             return ret;
2288         }
2289     } else
2290         xhkey = hkey;
2291
2292     lpdwType = REG_SZ;
2293     ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2294                               lpcbData );
2295     if (xhkey != hkey)
2296         RegCloseKey(xhkey);
2297     return ret;
2298 }
2299
2300
2301 /******************************************************************************
2302  * RegQueryValueEx32A [ADVAPI32.157]
2303  *
2304  * NOTES:
2305  * the documantation is wrong: if the buffer is to small it remains untouched 
2306  *
2307  * FIXME: check returnvalue (len) for an empty key
2308  */
2309 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2310                                  LPDWORD lpdwReserved, LPDWORD lpdwType,
2311                                  LPBYTE lpbData, LPDWORD lpcbData )
2312 {
2313         LPWSTR  lpszValueNameW;
2314         LPBYTE  mybuf = NULL;
2315         DWORD   ret, mytype, mylen = 0;
2316
2317         TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2318           lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2319
2320         if (!lpcbData && lpbData)                       /* buffer without size is illegal */
2321         {  return ERROR_INVALID_PARAMETER;
2322         }
2323
2324         lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;       
2325         
2326         /* get just the type first */
2327         ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2328         
2329         if ( ret != ERROR_SUCCESS )                     /* failed ?? */
2330         { if(lpszValueNameW) free(lpszValueNameW);
2331           return ret;
2332         }
2333         
2334         if (lpcbData)                                   /* at least length requested? */
2335         { if (UNICONVMASK & (1<<(mytype)))              /* string requested? */
2336           { if (lpbData )                               /* value requested? */
2337             { mylen = 2*( *lpcbData );
2338               mybuf = (LPBYTE)xmalloc( mylen );
2339             }
2340
2341             ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2342
2343             if (ret == ERROR_SUCCESS )
2344             { if ( lpbData )
2345               { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2346               }
2347             }
2348
2349             *lpcbData = mylen/2;                        /* size is in byte! */
2350           }
2351           else                                          /* no strings, call it straight */
2352           { ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2353           }
2354         }
2355         
2356         if (lpdwType)                                   /* type when requested */
2357         { *lpdwType = mytype;
2358         }
2359
2360         TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2361         
2362         if(mybuf) free(mybuf);
2363         if(lpszValueNameW) free(lpszValueNameW);
2364         return ret;
2365 }
2366
2367
2368 /******************************************************************************
2369  * RegQueryValueEx16 [KERNEL.225]
2370  */
2371 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2372                                 LPDWORD lpdwReserved, LPDWORD lpdwType,
2373                                 LPBYTE lpbData, LPDWORD lpcbData )
2374 {
2375     TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2376           lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2377     return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2378                                lpbData, lpcbData );
2379 }
2380
2381
2382 /******************************************************************************
2383  * RegQueryValue32A [ADVAPI32.156]
2384  */
2385 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2386                                LPDWORD lpcbData )
2387 {
2388     HKEY xhkey;
2389     DWORD ret, dwType;
2390
2391     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2392           lpcbData?*lpcbData:0);
2393
2394     if (lpszSubKey && *lpszSubKey) {
2395         ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2396         if( ret != ERROR_SUCCESS )
2397             return ret;
2398     } else
2399         xhkey = hkey;
2400
2401     dwType = REG_SZ;
2402     ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2403                               lpcbData );
2404     if( xhkey != hkey )
2405         RegCloseKey( xhkey );
2406     return ret;
2407 }
2408
2409
2410 /******************************************************************************
2411  * RegQueryValue16 [SHELL.6] [KERNEL.224]
2412  *
2413  * NOTES
2414  *    Is this HACK still applicable?
2415  *
2416  * HACK
2417  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2418  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
2419  *    Aldus FH4)
2420  */
2421 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2422                               LPDWORD lpcbData )
2423 {
2424     TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2425           lpcbData?*lpcbData:0);
2426
2427     if (lpcbData)
2428         *lpcbData &= 0xFFFF;
2429     return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2430 }
2431
2432
2433 /*
2434  * Setting values of Registry keys
2435  *
2436  * Callpath:
2437  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2438  *                                    RegSetValue32W   -> RegSetValueEx32W
2439  */
2440
2441
2442 /******************************************************************************
2443  * RegSetValueEx32W [ADVAPI32.170]
2444  * Sets the data and type of a value under a register key
2445  *
2446  * PARAMS
2447  *    hkey          [I] Handle of key to set value for
2448  *    lpszValueName [I] Name of value to set
2449  *    dwReserved    [I] Reserved - must be zero
2450  *    dwType        [I] Flag for value type
2451  *    lpbData       [I] Address of value data
2452  *    cbData        [I] Size of value data
2453  *
2454  * RETURNS
2455  *    Success: ERROR_SUCCESS
2456  *    Failure: Error code
2457  *
2458  * NOTES
2459  *   win95 does not care about cbData for REG_SZ and finds out the len by itself (js) 
2460  */
2461 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName, 
2462                                DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2463                                DWORD cbData)
2464 {
2465         LPKEYSTRUCT lpkey;
2466         int i;
2467
2468         TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2469           dwReserved, dwType, lpbData, cbData);
2470
2471         debug_print_value ( lpbData, dwType, cbData );
2472
2473         lpkey = lookup_hkey( hkey );
2474
2475         if (!lpkey)
2476           return ERROR_INVALID_HANDLE;
2477
2478         lpkey->flags |= REG_OPTION_TAINTED;
2479
2480         if (lpszValueName==NULL) {
2481              /* Sets type and name for key's unnamed or default value */
2482                 for (i=0;i<lpkey->nrofvalues;i++)
2483                         if (lpkey->values[i].name==NULL)
2484                                 break;
2485         } else {
2486                 for (i=0;i<lpkey->nrofvalues;i++)
2487                         if (    lpkey->values[i].name &&
2488                                 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2489                         )
2490                                 break;
2491         }
2492         if (i==lpkey->nrofvalues) {
2493                 lpkey->values = (LPKEYVALUE)xrealloc(
2494                                         lpkey->values,
2495                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2496                                 );
2497                 lpkey->nrofvalues++;
2498                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2499         }
2500         if (lpkey->values[i].name==NULL) {
2501                 if (lpszValueName)
2502                         lpkey->values[i].name = strdupW(lpszValueName);
2503                 else
2504                         lpkey->values[i].name = NULL;
2505         }
2506
2507         if (dwType == REG_SZ)
2508           cbData = 2 * (lstrlen32W ((LPCWSTR)lpbData) + 1);
2509           
2510         lpkey->values[i].len    = cbData;
2511         lpkey->values[i].type   = dwType;
2512         if (lpkey->values[i].data !=NULL)
2513                 free(lpkey->values[i].data);
2514         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
2515         lpkey->values[i].lastmodified = time(NULL);
2516         memcpy(lpkey->values[i].data,lpbData,cbData);
2517         return ERROR_SUCCESS;
2518 }
2519
2520
2521 /******************************************************************************
2522  * RegSetValueEx32A [ADVAPI32.169]
2523  *
2524  * NOTES
2525  *   win95 does not care about cbData for REG_SZ and finds out the len by itself (js) 
2526  */
2527 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2528                                DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2529                                DWORD cbData )
2530 {
2531         LPBYTE  buf;
2532         LPWSTR  lpszValueNameW;
2533         DWORD   ret;
2534
2535         if (!lpbData)
2536                 return (ERROR_INVALID_PARAMETER);
2537                 
2538         TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2539           dwReserved,dwType,lpbData,cbData);
2540
2541         if ((1<<dwType) & UNICONVMASK) 
2542         { if (dwType == REG_SZ)
2543             cbData = strlen ((LPCSTR)lpbData)+1;
2544
2545           buf = (LPBYTE)xmalloc( cbData *2 );
2546           lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2547           cbData=2*cbData;
2548         } 
2549         else
2550           buf=lpbData;
2551
2552         if (lpszValueName)
2553           lpszValueNameW = strdupA2W(lpszValueName);
2554         else
2555           lpszValueNameW = NULL;
2556
2557         ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2558
2559         if (lpszValueNameW)
2560           free(lpszValueNameW);
2561
2562         if (buf!=lpbData)
2563           free(buf);
2564
2565         return ret;
2566 }
2567
2568
2569 /******************************************************************************
2570  * RegSetValueEx16 [KERNEL.226]
2571  */
2572 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2573                               DWORD dwType, LPBYTE lpbData, DWORD cbData )
2574 {
2575     TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2576           dwReserved,dwType,lpbData,cbData);
2577     return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2578                              cbData );
2579 }
2580
2581
2582 /******************************************************************************
2583  * RegSetValue32W       [ADVAPI32.171]
2584  */
2585 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2586                              LPCWSTR lpszData, DWORD cbData )
2587 {
2588         HKEY    xhkey;
2589         DWORD   ret;
2590
2591         TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2592                 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2593         );
2594         if (lpszSubKey && *lpszSubKey) {
2595                 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2596                 if (ret!=ERROR_SUCCESS)
2597                         return ret;
2598         } else
2599                 xhkey=hkey;
2600         if (dwType!=REG_SZ) {
2601                 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2602                 dwType=REG_SZ;
2603         }
2604         if (cbData!=2*lstrlen32W(lpszData)+2) {
2605                 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2606                         cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2607                 );
2608                 cbData=2*lstrlen32W(lpszData)+2;
2609         }
2610         ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2611         if (hkey!=xhkey)
2612                 RegCloseKey(xhkey);
2613         return ret;
2614 }
2615
2616
2617 /******************************************************************************
2618  * RegSetValue32A [ADVAPI32.168]
2619  *
2620  */
2621 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2622                              LPCSTR lpszData, DWORD cbData )
2623 {
2624         DWORD   ret;
2625         HKEY    xhkey;
2626
2627         TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2628         if (lpszSubKey && *lpszSubKey) {
2629                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2630                 if (ret!=ERROR_SUCCESS)
2631                         return ret;
2632         } else
2633                 xhkey=hkey;
2634
2635         if (dwType!=REG_SZ) {
2636                 TRACE(reg,"dwType=%ld!\n",dwType);
2637                 dwType=REG_SZ;
2638         }
2639         if (cbData!=strlen(lpszData)+1)
2640                 cbData=strlen(lpszData)+1;
2641         ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2642         if (xhkey!=hkey)
2643                 RegCloseKey(xhkey);
2644         return ret;
2645 }
2646
2647
2648 /******************************************************************************
2649  * RegSetValue16 [KERNEL.221] [SHELL.5]
2650  */
2651 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2652                             LPCSTR lpszData, DWORD cbData )
2653 {
2654     TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2655           debugstr_a(lpszData),cbData);
2656     return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2657 }
2658
2659
2660 /* 
2661  * Key Enumeration
2662  *
2663  * Callpath:
2664  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2665  *                                  RegEnumKey32W   -> RegEnumKeyEx32W
2666  */
2667
2668
2669 /******************************************************************************
2670  * RegEnumKeyEx32W [ADVAPI32.139]
2671  *
2672  * PARAMS
2673  *    hkey         [I] Handle to key to enumerate
2674  *    iSubKey      [I] Index of subkey to enumerate
2675  *    lpszName     [O] Buffer for subkey name
2676  *    lpcchName    [O] Size of subkey buffer
2677  *    lpdwReserved [I] Reserved
2678  *    lpszClass    [O] Buffer for class string
2679  *    lpcchClass   [O] Size of class buffer
2680  *    ft           [O] Time key last written to
2681  */
2682 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2683                               LPDWORD lpcchName, LPDWORD lpdwReserved,
2684                               LPWSTR lpszClass, LPDWORD lpcchClass, 
2685                               FILETIME *ft )
2686 {
2687         LPKEYSTRUCT     lpkey,lpxkey;
2688
2689     TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2690           *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2691
2692     lpkey = lookup_hkey( hkey );
2693     if (!lpkey)
2694         return ERROR_INVALID_HANDLE;
2695
2696         if (!lpkey->nextsub)
2697                 return ERROR_NO_MORE_ITEMS;
2698         lpxkey=lpkey->nextsub;
2699
2700     /* Traverse the subkeys */
2701         while (iSubkey && lpxkey) {
2702                 iSubkey--;
2703                 lpxkey=lpxkey->next;
2704         }
2705
2706         if (iSubkey || !lpxkey)
2707                 return ERROR_NO_MORE_ITEMS;
2708         if (lstrlen32W(lpxkey->keyname)+1>*lpcchName)
2709                 return ERROR_MORE_DATA;
2710         memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2711
2712         if (*lpcchName)
2713             *lpcchName = lstrlen32W(lpszName);
2714
2715         if (lpszClass) {
2716                 /* FIXME: what should we write into it? */
2717                 *lpszClass      = 0;
2718                 *lpcchClass     = 2;
2719         }
2720         return ERROR_SUCCESS;
2721 }
2722
2723
2724 /******************************************************************************
2725  * RegEnumKey32W [ADVAPI32.140]
2726  */
2727 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, 
2728                             DWORD lpcchName )
2729 {
2730     FILETIME    ft;
2731
2732     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2733     return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2734 }
2735
2736
2737 /******************************************************************************
2738  * RegEnumKeyEx32A [ADVAPI32.138]
2739  */
2740 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2741                               LPDWORD lpcchName, LPDWORD lpdwReserved, 
2742                               LPSTR lpszClass, LPDWORD lpcchClass, 
2743                               FILETIME *ft )
2744 {
2745         DWORD   ret,lpcchNameW,lpcchClassW;
2746         LPWSTR  lpszNameW,lpszClassW;
2747
2748
2749         TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2750                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2751         );
2752         if (lpszName) {
2753                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
2754                 lpcchNameW      = *lpcchName;
2755         } else {
2756                 lpszNameW       = NULL;
2757                 lpcchNameW      = 0;
2758         }
2759         if (lpszClass) {
2760                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
2761                 lpcchClassW     = *lpcchClass;
2762         } else {
2763                 lpszClassW      =0;
2764                 lpcchClassW=0;
2765         }
2766         ret=RegEnumKeyEx32W(
2767                 hkey,
2768                 iSubkey,
2769                 lpszNameW,
2770                 &lpcchNameW,
2771                 lpdwReserved,
2772                 lpszClassW,
2773                 &lpcchClassW,
2774                 ft
2775         );
2776         if (ret==ERROR_SUCCESS) {
2777                 lstrcpyWtoA(lpszName,lpszNameW);
2778                 *lpcchName=strlen(lpszName);
2779                 if (lpszClassW) {
2780                         lstrcpyWtoA(lpszClass,lpszClassW);
2781                         *lpcchClass=strlen(lpszClass);
2782                 }
2783         }
2784         if (lpszNameW)
2785                 free(lpszNameW);
2786         if (lpszClassW)
2787                 free(lpszClassW);
2788         return ret;
2789 }
2790
2791
2792 /******************************************************************************
2793  * RegEnumKey32A [ADVAPI32.137]
2794  */
2795 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2796                             DWORD lpcchName )
2797 {
2798     FILETIME    ft;
2799
2800     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2801     return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL, 
2802                             NULL, &ft );
2803 }
2804
2805
2806 /******************************************************************************
2807  * RegEnumKey16 [SHELL.7] [KERNEL.216]
2808  */
2809 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2810                            DWORD lpcchName )
2811 {
2812     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2813     return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2814 }
2815
2816
2817 /* 
2818  * Enumerate Registry Values
2819  *
2820  * Callpath:
2821  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2822  */
2823
2824
2825 /******************************************************************************
2826  * RegEnumValue32W [ADVAPI32.142]
2827  *
2828  * PARAMS
2829  *    hkey        [I] Handle to key to query
2830  *    iValue      [I] Index of value to query
2831  *    lpszValue   [O] Value string
2832  *    lpcchValue  [I/O] Size of value buffer (in wchars)
2833  *    lpdReserved [I] Reserved
2834  *    lpdwType    [O] Type code
2835  *    lpbData     [O] Value data
2836  *    lpcbData    [I/O] Size of data buffer (in bytes)
2837  *
2838  * Note:  wide character functions that take and/or return "character counts"
2839  *  use TCHAR (that is unsigned short or char) not byte counts.
2840  */
2841 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2842                               LPDWORD lpcchValue, LPDWORD lpdReserved,
2843                               LPDWORD lpdwType, LPBYTE lpbData, 
2844                               LPDWORD lpcbData )
2845 {
2846         LPKEYSTRUCT     lpkey;
2847         LPKEYVALUE      val;
2848
2849         TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2850           lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2851
2852         lpkey = lookup_hkey( hkey );
2853         
2854         if (!lpcbData && lpbData)
2855                 return ERROR_INVALID_PARAMETER;
2856                 
2857         if (!lpkey)
2858                 return ERROR_INVALID_HANDLE;
2859
2860         if (lpkey->nrofvalues <= iValue)
2861                 return ERROR_NO_MORE_ITEMS;
2862
2863         val = &(lpkey->values[iValue]);
2864
2865         if (val->name) {
2866                 if (lstrlen32W(val->name)+1>*lpcchValue) {
2867                         *lpcchValue = lstrlen32W(val->name)+1;
2868                         return ERROR_MORE_DATA;
2869                 }
2870                 memcpy(lpszValue,val->name,2 * (lstrlen32W(val->name)+1) );
2871                 *lpcchValue=lstrlen32W(val->name);
2872         } else {
2873                 *lpszValue      = 0;
2874                 *lpcchValue     = 0;
2875         }
2876
2877         /* Can be NULL if the type code is not required */
2878         if (lpdwType)
2879                 *lpdwType = val->type;
2880
2881         if (lpbData) {
2882                 if (val->len>*lpcbData)
2883                         return ERROR_MORE_DATA;
2884                 memcpy(lpbData,val->data,val->len);
2885                 *lpcbData = val->len;
2886         }
2887
2888         debug_print_value ( val->data, val->type, val->len );
2889         return ERROR_SUCCESS;
2890 }
2891
2892
2893 /******************************************************************************
2894  * RegEnumValue32A [ADVAPI32.141]
2895  */
2896 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2897                               LPDWORD lpcchValue, LPDWORD lpdReserved,
2898                               LPDWORD lpdwType, LPBYTE lpbData, 
2899                               LPDWORD lpcbData )
2900 {
2901         LPWSTR  lpszValueW;
2902         LPBYTE  lpbDataW;
2903         DWORD   ret,lpcbDataW;
2904         DWORD dwType;
2905
2906         TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2907                 lpdReserved,lpdwType,lpbData,lpcbData);
2908
2909         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2910         if (lpbData) {
2911                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2912                 lpcbDataW = *lpcbData;
2913         } else
2914                 lpbDataW = NULL;
2915
2916         ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue, 
2917                                 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2918
2919         if (lpdwType)
2920                 *lpdwType = dwType;
2921
2922         if (ret==ERROR_SUCCESS) {
2923                 lstrcpyWtoA(lpszValue,lpszValueW);
2924                 if (lpbData) {
2925                         if ((1<<dwType) & UNICONVMASK) {
2926                                 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2927                         } else {
2928                                 if (lpcbDataW > *lpcbData)
2929                                         ret     = ERROR_MORE_DATA;
2930                                 else
2931                                         memcpy(lpbData,lpbDataW,lpcbDataW);
2932                         }
2933                         *lpcbData = lpcbDataW;
2934                 }
2935         }
2936     if (lpbDataW) free(lpbDataW);
2937     if (lpszValueW) free(lpszValueW);
2938     return ret;
2939 }
2940
2941
2942 /******************************************************************************
2943  * RegEnumValue16 [KERNEL.223]
2944  */
2945 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue, 
2946                              LPDWORD lpcchValue, LPDWORD lpdReserved, 
2947                              LPDWORD lpdwType, LPBYTE lpbData, 
2948                              LPDWORD lpcbData )
2949 {
2950     TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2951           lpdReserved,lpdwType,lpbData,lpcbData);
2952     return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved, 
2953                             lpdwType, lpbData, lpcbData );
2954 }
2955
2956
2957 /******************************************************************************
2958  * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2959  * Releases the handle of the specified key
2960  *
2961  * PARAMS
2962  *    hkey [I] Handle of key to close
2963  *
2964  * RETURNS
2965  *    Success: ERROR_SUCCESS
2966  *    Failure: Error code
2967  */
2968 DWORD WINAPI RegCloseKey( HKEY hkey )
2969 {
2970     TRACE(reg,"(%x)\n",hkey);
2971
2972     /* The standard handles are allowed to succeed, even though they are not
2973        closed */
2974     if (is_standard_hkey(hkey))
2975         return ERROR_SUCCESS;
2976
2977     return remove_handle(hkey);
2978 }
2979
2980
2981 /* 
2982  * Delete registry key
2983  *
2984  * Callpath:
2985  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2986  */
2987
2988
2989 /******************************************************************************
2990  * RegDeleteKey32W [ADVAPI32.134]
2991  *
2992  * PARAMS
2993  *    hkey       [I] Handle to open key
2994  *    lpszSubKey [I] Name of subkey to delete
2995  *
2996  * RETURNS
2997  *    Success: ERROR_SUCCESS
2998  *    Failure: Error code
2999  */
3000 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
3001 {
3002         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
3003         LPWSTR          *wps;
3004         int             wpc,i;
3005
3006     TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3007
3008     lpNextKey = lookup_hkey(hkey);
3009     if (!lpNextKey)
3010         return ERROR_INVALID_HANDLE;
3011
3012     /* Subkey param cannot be NULL */
3013     if (!lpszSubKey || !*lpszSubKey)
3014         return ERROR_BADKEY;
3015
3016     /* We need to know the previous key in the hier. */
3017         split_keypath(lpszSubKey,&wps,&wpc);
3018         i       = 0;
3019         lpxkey  = lpNextKey;
3020         while (i<wpc-1) {
3021                 lpxkey=lpNextKey->nextsub;
3022                 while (lpxkey) {
3023                         TRACE(reg, "  Scanning [%s]\n",
3024                                      debugstr_w(lpxkey->keyname));
3025                         if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3026                                 break;
3027                         lpxkey=lpxkey->next;
3028                 }
3029                 if (!lpxkey) {
3030                         FREE_KEY_PATH;
3031                         TRACE(reg, "  Not found.\n");
3032                         /* not found is success */
3033                         return ERROR_SUCCESS;
3034                 }
3035                 i++;
3036                 lpNextKey       = lpxkey;
3037         }
3038         lpxkey  = lpNextKey->nextsub;
3039         lplpPrevKey = &(lpNextKey->nextsub);
3040         while (lpxkey) {
3041                 TRACE(reg, "  Scanning [%s]\n",
3042                              debugstr_w(lpxkey->keyname));
3043                 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3044                         break;
3045                 lplpPrevKey     = &(lpxkey->next);
3046                 lpxkey          = lpxkey->next;
3047         }
3048
3049         if (!lpxkey) {
3050                 FREE_KEY_PATH;
3051                 WARN(reg , "  Not found.\n");
3052                 return ERROR_FILE_NOT_FOUND;
3053         }
3054
3055         if (lpxkey->nextsub) {
3056                 FREE_KEY_PATH;
3057                 WARN(reg , "  Not empty.\n");
3058                 return ERROR_CANTWRITE;
3059         }
3060         *lplpPrevKey    = lpxkey->next;
3061         free(lpxkey->keyname);
3062         if (lpxkey->class)
3063                 free(lpxkey->class);
3064         if (lpxkey->values)
3065                 free(lpxkey->values);
3066         free(lpxkey);
3067         FREE_KEY_PATH;
3068         TRACE(reg, "  Done.\n");
3069         return  ERROR_SUCCESS;
3070 }
3071
3072
3073 /******************************************************************************
3074  * RegDeleteKey32A [ADVAPI32.133]
3075  */
3076 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3077 {
3078     LPWSTR lpszSubKeyW;
3079     DWORD  ret;
3080
3081     TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3082     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3083     ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3084     if(lpszSubKeyW) free(lpszSubKeyW);
3085     return ret;
3086 }
3087
3088
3089 /******************************************************************************
3090  * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3091  */
3092 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3093 {
3094     TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3095     return RegDeleteKey32A( hkey, lpszSubKey );
3096 }
3097
3098
3099 /* 
3100  * Delete registry value
3101  *
3102  * Callpath:
3103  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3104  */
3105
3106
3107 /******************************************************************************
3108  * RegDeleteValue32W [ADVAPI32.136]
3109  *
3110  * PARAMS
3111  *    hkey      [I]
3112  *    lpszValue [I]
3113  *
3114  * RETURNS
3115  */
3116 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3117 {
3118         DWORD           i;
3119         LPKEYSTRUCT     lpkey;
3120         LPKEYVALUE      val;
3121
3122     TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3123
3124     lpkey = lookup_hkey( hkey );
3125     if (!lpkey)
3126         return ERROR_INVALID_HANDLE;
3127
3128         if (lpszValue) {
3129                 for (i=0;i<lpkey->nrofvalues;i++)
3130                         if (    lpkey->values[i].name &&
3131                                 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3132                         )
3133                                 break;
3134         } else {
3135                 for (i=0;i<lpkey->nrofvalues;i++)
3136                         if (lpkey->values[i].name==NULL)
3137                                 break;
3138         }
3139
3140     if (i == lpkey->nrofvalues)
3141         return ERROR_FILE_NOT_FOUND;
3142
3143         val     = lpkey->values+i;
3144         if (val->name) free(val->name);
3145         if (val->data) free(val->data);
3146         memcpy( 
3147                 lpkey->values+i,
3148                 lpkey->values+i+1,
3149                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3150         );
3151         lpkey->values   = (LPKEYVALUE)xrealloc(
3152                                 lpkey->values,
3153                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3154                         );
3155         lpkey->nrofvalues--;
3156         return ERROR_SUCCESS;
3157 }
3158
3159
3160 /******************************************************************************
3161  * RegDeleteValue32A [ADVAPI32.135]
3162  */
3163 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3164 {
3165     LPWSTR lpszValueW;
3166     DWORD  ret;
3167
3168     TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3169     lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3170     ret = RegDeleteValue32W( hkey, lpszValueW );
3171     if(lpszValueW) free(lpszValueW);
3172     return ret;
3173 }
3174
3175
3176 /******************************************************************************
3177  * RegDeleteValue16 [KERNEL.222]
3178  */
3179 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3180 {
3181     TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3182     return RegDeleteValue32A( hkey, lpszValue );
3183 }
3184
3185
3186 /******************************************************************************
3187  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3188  * Writes key to registry
3189  *
3190  * PARAMS
3191  *    hkey [I] Handle of key to write
3192  *
3193  * RETURNS
3194  *    Success: ERROR_SUCCESS
3195  *    Failure: Error code
3196  */
3197 DWORD WINAPI RegFlushKey( HKEY hkey )
3198 {
3199     LPKEYSTRUCT lpkey;
3200     BOOL32 ret;
3201
3202     TRACE(reg, "(%x)\n", hkey);
3203
3204     lpkey = lookup_hkey( hkey );
3205     if (!lpkey)
3206         return ERROR_INVALID_HANDLE;
3207
3208     ERR(reg, "What is the correct filename?\n");
3209
3210     ret = _savereg( lpkey, "foo.bar", TRUE);
3211
3212     if( ret ) {
3213         return ERROR_SUCCESS;
3214     } else
3215         return ERROR_UNKNOWN;  /* FIXME */
3216 }
3217
3218
3219 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3220
3221
3222 /******************************************************************************
3223  * RegQueryInfoKey32W [ADVAPI32.153]
3224  *
3225  * PARAMS
3226  *    hkey                   [I] Handle to key to query
3227  *    lpszClass              [O] Buffer for class string
3228  *    lpcchClass             [O] Size of class string buffer
3229  *    lpdwReserved           [I] Reserved
3230  *    lpcSubKeys             [I] Buffer for number of subkeys
3231  *    lpcchMaxSubKey         [O] Buffer for longest subkey name length
3232  *    lpcchMaxClass          [O] Buffer for longest class string length
3233  *    lpcValues              [O] Buffer for number of value entries
3234  *    lpcchMaxValueName      [O] Buffer for longest value name length
3235  *    lpccbMaxValueData      [O] Buffer for longest value data length
3236  *    lpcbSecurityDescriptor [O] Buffer for security descriptor length
3237  *    ft
3238  * - win95 allows lpszClass to be valid and lpcchClass to be NULL 
3239  * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3240  *   lpcchClass is NULL
3241  * - both allow lpszClass to be NULL and lpcchClass to be NULL 
3242  * (it's hard to test validity, so test !NULL instead)
3243  */
3244 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass, 
3245                                  LPDWORD lpcchClass, LPDWORD lpdwReserved,
3246                                  LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3247                                  LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3248                                  LPDWORD lpcchMaxValueName, 
3249                                  LPDWORD lpccbMaxValueData, 
3250                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3251 {
3252         LPKEYSTRUCT     lpkey,lpxkey;
3253         int             nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3254         int             i;
3255
3256         TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3257         lpkey = lookup_hkey(hkey);
3258         if (!lpkey)
3259                 return ERROR_INVALID_HANDLE;
3260         if (lpszClass) {
3261                 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3262                     return ERROR_INVALID_PARAMETER;
3263                 }
3264                 /* either lpcchClass is valid or this is win95 and lpcchClass
3265                    could be invalid */
3266                 if (lpkey->class) {
3267                         DWORD classLen = lstrlen32W(lpkey->class);
3268
3269                         if (lpcchClass && classLen+1>*lpcchClass) {
3270                                 *lpcchClass=classLen+1;
3271                                 return ERROR_MORE_DATA;
3272                         }
3273                         if (lpcchClass)
3274                             *lpcchClass=classLen;
3275                         memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3276                 } else {
3277                         *lpszClass      = 0;
3278                         if (lpcchClass)
3279                             *lpcchClass = 0;
3280                 }
3281         } else {
3282                 if (lpcchClass)
3283                         *lpcchClass     = lstrlen32W(lpkey->class);
3284         }
3285         lpxkey=lpkey->nextsub;
3286         nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3287         while (lpxkey) {
3288                 nrofkeys++;
3289                 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3290                         maxsubkey=lstrlen32W(lpxkey->keyname);
3291                 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3292                         maxclass=lstrlen32W(lpxkey->class);
3293                 lpxkey=lpxkey->next;
3294         }
3295         for (i=0;i<lpkey->nrofvalues;i++) {
3296                 LPKEYVALUE      val=lpkey->values+i;
3297
3298                 if (val->name && lstrlen32W(val->name)>maxvname)
3299                         maxvname=lstrlen32W(val->name);
3300                 if (val->len>maxvdata)
3301                         maxvdata=val->len;
3302         }
3303         if (!maxclass) maxclass = 1;
3304         if (!maxvname) maxvname = 1;
3305         if (lpcValues)
3306                 *lpcValues      = lpkey->nrofvalues;
3307         if (lpcSubKeys)
3308                 *lpcSubKeys     = nrofkeys;
3309         if (lpcchMaxSubkey)
3310                 *lpcchMaxSubkey = maxsubkey;
3311         if (lpcchMaxClass)
3312                 *lpcchMaxClass  = maxclass;
3313         if (lpcchMaxValueName)
3314                 *lpcchMaxValueName= maxvname;
3315         if (lpccbMaxValueData)
3316                 *lpccbMaxValueData= maxvdata;
3317         return ERROR_SUCCESS;
3318 }
3319
3320
3321 /******************************************************************************
3322  * RegQueryInfoKey32A [ADVAPI32.152]
3323  */
3324 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3325                                  LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3326                                  LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3327                                  LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3328                                  LPDWORD lpccbMaxValueData, 
3329                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3330 {
3331         LPWSTR          lpszClassW = NULL;
3332         DWORD           ret;
3333
3334         TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3335         if (lpszClass) {
3336                 if (lpcchClass) {
3337                     lpszClassW  = (LPWSTR)xmalloc((*lpcchClass) * 2);
3338                 } else if (VERSION_GetVersion() == WIN95) {
3339                     /* win95  allows lpcchClass to be null */
3340                     /* we don't know how big lpszClass is, would 
3341                        MAX_PATHNAME_LEN be the correct default? */
3342                     lpszClassW  = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2); 
3343                 }
3344
3345         } else
3346                 lpszClassW  = NULL;
3347         ret=RegQueryInfoKey32W(
3348                 hkey,
3349                 lpszClassW,
3350                 lpcchClass,
3351                 lpdwReserved,
3352                 lpcSubKeys,
3353                 lpcchMaxSubkey,
3354                 lpcchMaxClass,
3355                 lpcValues,
3356                 lpcchMaxValueName,
3357                 lpccbMaxValueData,
3358                 lpcbSecurityDescriptor,
3359                 ft
3360         );
3361         if (ret==ERROR_SUCCESS && lpszClass)
3362                 lstrcpyWtoA(lpszClass,lpszClassW);
3363         if (lpszClassW)
3364                 free(lpszClassW);
3365         return ret;
3366 }
3367
3368
3369 /******************************************************************************
3370  * RegConnectRegistry32W [ADVAPI32.128]
3371  *
3372  * PARAMS
3373  *    lpMachineName [I] Address of name of remote computer
3374  *    hHey          [I] Predefined registry handle
3375  *    phkResult     [I] Address of buffer for remote registry handle
3376  */
3377 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey, 
3378                                    LPHKEY phkResult )
3379 {
3380     TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3381
3382     if (!lpMachineName || !*lpMachineName) {
3383         /* Use the local machine name */
3384         return RegOpenKey16( hKey, "", phkResult );
3385     }
3386
3387     FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3388     return ERROR_BAD_NETPATH;
3389 }
3390
3391
3392 /******************************************************************************
3393  * RegConnectRegistry32A [ADVAPI32.127]
3394  */
3395 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3396 {
3397     DWORD ret;
3398     LPWSTR machineW = strdupA2W(machine);
3399     ret = RegConnectRegistry32W( machineW, hkey, reskey );
3400     free(machineW);
3401     return ret;
3402 }
3403
3404
3405 /******************************************************************************
3406  * RegGetKeySecurity [ADVAPI32.144]
3407  * Retrieves a copy of security descriptor protecting the registry key
3408  *
3409  * PARAMS
3410  *    hkey                   [I]   Open handle of key to set
3411  *    SecurityInformation    [I]   Descriptor contents
3412  *    pSecurityDescriptor    [O]   Address of descriptor for key
3413  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3414  *
3415  * RETURNS
3416  *    Success: ERROR_SUCCESS
3417  *    Failure: Error code
3418  */
3419 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
3420                                SECURITY_INFORMATION SecurityInformation,
3421                                LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3422                                LPDWORD lpcbSecurityDescriptor )
3423 {
3424     LPKEYSTRUCT lpkey;
3425
3426     TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3427           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3428
3429     lpkey = lookup_hkey( hkey );
3430     if (!lpkey)
3431         return ERROR_INVALID_HANDLE;
3432
3433     /* FIXME: Check for valid SecurityInformation values */
3434
3435     if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3436         return ERROR_INSUFFICIENT_BUFFER;
3437
3438     FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3439           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3440
3441     return ERROR_SUCCESS;
3442 }
3443
3444
3445 /******************************************************************************
3446  * RegLoadKey32W [ADVAPI32.???]
3447  *
3448  * PARAMS
3449  *    hkey       [I] Handle of open key
3450  *    lpszSubKey [I] Address of name of subkey
3451  *    lpszFile   [I] Address of filename for registry information
3452  */
3453 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3454 {
3455     LPKEYSTRUCT lpkey;
3456     TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3457
3458     /* Do this check before the hkey check */
3459     if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3460         return ERROR_INVALID_PARAMETER;
3461
3462     lpkey = lookup_hkey( hkey );
3463     if (!lpkey)
3464         return ERROR_INVALID_HANDLE;
3465
3466     FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3467           debugstr_w(lpszFile));
3468
3469     return ERROR_SUCCESS;
3470 }
3471
3472
3473 /******************************************************************************
3474  * RegLoadKey32A [ADVAPI32.???]
3475  */
3476 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3477 {
3478     LONG ret;
3479     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3480     LPWSTR lpszFileW = strdupA2W(lpszFile);
3481     ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3482     if(lpszFileW) free(lpszFileW);
3483     if(lpszSubKeyW) free(lpszSubKeyW);
3484     return ret;
3485 }
3486
3487
3488 /******************************************************************************
3489  * RegNotifyChangeKeyValue [ADVAPI32.???]
3490  *
3491  * PARAMS
3492  *    hkey            [I] Handle of key to watch
3493  *    fWatchSubTree   [I] Flag for subkey notification
3494  *    fdwNotifyFilter [I] Changes to be reported
3495  *    hEvent          [I] Handle of signaled event
3496  *    fAsync          [I] Flag for asynchronous reporting
3497  */
3498 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree, 
3499                                      DWORD fdwNotifyFilter, HANDLE32 hEvent,
3500                                      BOOL32 fAsync )
3501 {
3502     LPKEYSTRUCT lpkey;
3503     TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3504           hEvent,fAsync);
3505
3506     lpkey = lookup_hkey( hkey );
3507     if (!lpkey)
3508         return ERROR_INVALID_HANDLE;
3509
3510     FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3511           hEvent,fAsync);
3512
3513     return ERROR_SUCCESS;
3514 }
3515
3516
3517 /******************************************************************************
3518  * RegUnLoadKey32W [ADVAPI32.173]
3519  *
3520  * PARAMS
3521  *    hkey     [I] Handle of open key
3522  *    lpSubKey [I] Address of name of subkey to unload
3523  */
3524 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3525 {
3526     FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3527     return ERROR_SUCCESS;
3528 }
3529
3530
3531 /******************************************************************************
3532  * RegUnLoadKey32A [ADVAPI32.172]
3533  */
3534 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3535 {
3536     LONG ret;
3537     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3538     ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3539     if(lpSubKeyW) free(lpSubKeyW);
3540     return ret;
3541 }
3542
3543
3544 /******************************************************************************
3545  * RegSetKeySecurity [ADVAPI32.167]
3546  *
3547  * PARAMS
3548  *    hkey          [I] Open handle of key to set
3549  *    SecurityInfo  [I] Descriptor contents
3550  *    pSecurityDesc [I] Address of descriptor for key
3551  */
3552 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3553                                LPSECURITY_DESCRIPTOR pSecurityDesc )
3554 {
3555     LPKEYSTRUCT lpkey;
3556
3557     TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3558
3559     /* It seems to perform this check before the hkey check */
3560     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3561         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3562         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3563         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3564         /* Param OK */
3565     } else
3566         return ERROR_INVALID_PARAMETER;
3567
3568     if (!pSecurityDesc)
3569         return ERROR_INVALID_PARAMETER;
3570
3571     lpkey = lookup_hkey( hkey );
3572     if (!lpkey)
3573         return ERROR_INVALID_HANDLE;
3574
3575     FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3576
3577     return ERROR_SUCCESS;
3578 }
3579
3580
3581 /******************************************************************************
3582  * RegSaveKey32W [ADVAPI32.166]
3583  *
3584  * PARAMS
3585  *    hkey   [I] Handle of key where save begins
3586  *    lpFile [I] Address of filename to save to
3587  *    sa     [I] Address of security structure
3588  */
3589 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile, 
3590                            LPSECURITY_ATTRIBUTES sa )
3591 {
3592     LPKEYSTRUCT lpkey;
3593
3594     TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3595
3596     /* It appears to do this check before the hkey check */
3597     if (!lpFile || !*lpFile)
3598         return ERROR_INVALID_PARAMETER;
3599
3600     lpkey = lookup_hkey( hkey );
3601     if (!lpkey)
3602         return ERROR_INVALID_HANDLE;
3603
3604     FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3605
3606     return ERROR_SUCCESS;
3607 }
3608
3609
3610 /******************************************************************************
3611  * RegSaveKey32A [ADVAPI32.165]
3612  */
3613 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile, 
3614                            LPSECURITY_ATTRIBUTES sa )
3615 {
3616     LONG ret;
3617     LPWSTR lpFileW = strdupA2W(lpFile);
3618     ret = RegSaveKey32W( hkey, lpFileW, sa );
3619     free(lpFileW);
3620     return ret;
3621 }
3622
3623
3624 /******************************************************************************
3625  * RegRestoreKey32W [ADVAPI32.164]
3626  *
3627  * PARAMS
3628  *    hkey    [I] Handle of key where restore begins
3629  *    lpFile  [I] Address of filename containing saved tree
3630  *    dwFlags [I] Optional flags
3631  */
3632 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3633 {
3634     LPKEYSTRUCT lpkey;
3635
3636     TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3637
3638     /* It seems to do this check before the hkey check */
3639     if (!lpFile || !*lpFile)
3640         return ERROR_INVALID_PARAMETER;
3641
3642     lpkey = lookup_hkey( hkey );
3643     if (!lpkey)
3644         return ERROR_INVALID_HANDLE;
3645
3646     FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3647
3648     /* Check for file existence */
3649
3650     return ERROR_SUCCESS;
3651 }
3652
3653
3654 /******************************************************************************
3655  * RegRestoreKey32A [ADVAPI32.163]
3656  */
3657 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3658 {
3659     LONG ret;
3660     LPWSTR lpFileW = strdupA2W(lpFile);
3661     ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3662     if(lpFileW) free(lpFileW);
3663     return ret;
3664 }
3665
3666
3667 /******************************************************************************
3668  * RegReplaceKey32W [ADVAPI32.162]
3669  *
3670  * PARAMS
3671  *    hkey      [I] Handle of open key
3672  *    lpSubKey  [I] Address of name of subkey
3673  *    lpNewFile [I] Address of filename for file with new data
3674  *    lpOldFile [I] Address of filename for backup file
3675  */
3676 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3677                               LPCWSTR lpOldFile )
3678 {
3679     LPKEYSTRUCT lpkey;
3680
3681     TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3682           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3683
3684     lpkey = lookup_hkey( hkey );
3685     if (!lpkey)
3686         return ERROR_INVALID_HANDLE;
3687
3688     FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
3689           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3690
3691     return ERROR_SUCCESS;
3692 }
3693
3694
3695 /******************************************************************************
3696  * RegReplaceKey32A [ADVAPI32.161]
3697  */
3698 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3699                               LPCSTR lpOldFile )
3700 {
3701     LONG ret;
3702     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3703     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3704     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3705     ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3706     free(lpOldFileW);
3707     free(lpNewFileW);
3708     free(lpSubKeyW);
3709     return ret;
3710 }
3711