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