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