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