Made LoadHomeRegistryFiles default to TRUE.
[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;
622
623         if (!lpkey)
624                 return 0;
625         if (lpkey->flags & REG_OPTION_TAINTED)
626                 tainted = 1;
627         else
628                 tainted = 0;
629         while (lpkey) {
630                 if (_save_check_tainted(lpkey->nextsub)) {
631                         lpkey->flags |= REG_OPTION_TAINTED;
632                         tainted = 1;
633                 }
634                 lpkey   = lpkey->next;
635         }
636         return tainted;
637 }
638
639 /******************************************************************************
640  * _save_USTRING [Internal]
641  */
642 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
643 {
644         LPWSTR  s;
645         int     doescape;
646
647         if (wstr==NULL)
648                 return;
649         s=wstr;
650         while (*s) {
651                 doescape=0;
652                 if (*s>0x7f)
653                         doescape = 1;
654                 if (*s=='\n')
655                         doescape = 1;
656                 if (escapeeq && *s=='=')
657                         doescape = 1;
658                 if (*s=='\\')
659                         fputc(*s,F); /* if \\ then put it twice. */
660                 if (doescape)
661                         fprintf(F,"\\u%04x",*((unsigned short*)s));
662                 else
663                         fputc(*s,F);
664                 s++;
665         }
666 }
667
668 /******************************************************************************
669  * _savesubkey [Internal]
670  *
671  * NOTES
672  *  REG_MULTI_SZ is handled as binary (like in win95) (js)
673  */
674 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
675 {
676         LPKEYSTRUCT     lpxkey;
677         int             i,tabs,j;
678
679         lpxkey  = lpkey;
680         while (lpxkey) {
681                 if (    !(lpxkey->flags & REG_OPTION_VOLATILE) &&
682                         (all || (lpxkey->flags & REG_OPTION_TAINTED))
683                 ) {
684                         for (tabs=level;tabs--;)
685                                 fputc('\t',F);
686                         _save_USTRING(F,lpxkey->keyname,1);
687                         fputs("\n",F);
688                         for (i=0;i<lpxkey->nrofvalues;i++) {
689                                 LPKEYVALUE      val=lpxkey->values+i;
690
691                                 for (tabs=level+1;tabs--;)
692                                         fputc('\t',F);
693                                 _save_USTRING(F,val->name,0);
694                                 fputc('=',F);
695                                 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
696                                 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
697                                         _save_USTRING(F,(LPWSTR)val->data,0);
698                                 else
699                                         for (j=0;j<val->len;j++)
700                                                 fprintf(F,"%02x",*((unsigned char*)val->data+j));
701                                 fputs("\n",F);
702                         }
703                         /* descend recursively */
704                         if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
705                                 return 0;
706                 }
707                 lpxkey=lpxkey->next;
708         }
709         return 1;
710 }
711
712
713 /******************************************************************************
714  * _savesubreg [Internal]
715  */
716 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
717 {
718         fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
719         _save_check_tainted(lpkey->nextsub);
720         return _savesubkey(F,lpkey->nextsub,0,all);
721 }
722
723
724 /******************************************************************************
725  * _savereg [Internal]
726  */
727 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
728 {
729         FILE    *F;
730
731         F=fopen(fn,"w");
732         if (F==NULL) {
733                 WARN_(reg)("Couldn't open %s for writing: %s\n",
734                         fn,strerror(errno)
735                 );
736                 return FALSE;
737         }
738         if (!_savesubreg(F,lpkey,all)) {
739                 fclose(F);
740                 unlink(fn);
741                 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
742                 return FALSE;
743         }
744         fclose(F);
745         return TRUE;
746 }
747
748
749 /******************************************************************************
750  * SHELL_SaveRegistryBranch [Internal]
751  *
752  * Saves main registry branch specified by hkey.
753  */
754 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
755 {
756     char   *fn, *home, *tmp;
757
758     /* Find out what to save to, get from config file */
759     BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
760     BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
761
762     /* FIXME: does this check apply to all keys written below ? */
763     if (!(home = getenv( "HOME" )))
764         ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
765
766     /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
767     if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
768
769     switch (hkey)
770     {
771     case HKEY_CURRENT_USER:
772         fn = xmalloc( MAX_PATHNAME_LEN ); 
773         if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
774                                                     fn, MAX_PATHNAME_LEN - 1))
775             _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
776         free (fn);
777
778         if (home && writeToHome)
779         {
780             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
781                                strlen(SAVE_CURRENT_USER) + 2 );
782             strcpy(fn,home);
783             strcat(fn,WINE_PREFIX);
784   
785             /* create the directory. don't care about errorcodes. */
786             mkdir(fn,0755); /* drwxr-xr-x */
787             strcat(fn,"/"SAVE_CURRENT_USER);
788
789             tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
790             strcpy(tmp,fn);
791             strcat(tmp,".tmp");
792   
793             if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
794                 if (-1==rename(tmp,fn)) {
795                     perror("rename tmp registry");
796                     unlink(tmp);
797                 }
798             }
799             free(tmp);
800             free(fn);
801         }
802         break;
803     case HKEY_LOCAL_MACHINE:
804         /* Try first saving according to the defined location in .winerc */
805         fn = xmalloc ( MAX_PATHNAME_LEN);
806         if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "", 
807                                                     fn, MAX_PATHNAME_LEN - 1))
808             _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
809         free (fn);
810
811         if (home && writeToHome)
812         {
813             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
814                                strlen(SAVE_LOCAL_MACHINE) + 2);
815             strcpy(fn,home);
816             strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
817
818             tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
819             strcpy(tmp,fn);
820             strcat(tmp,".tmp");
821
822             if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
823                 if (-1==rename(tmp,fn)) {
824                     perror("rename tmp registry");
825                     unlink(tmp);
826                 }
827             }
828             free(tmp);
829             free(fn);
830         }
831         break;
832     case HKEY_USERS:
833         fn = xmalloc( MAX_PATHNAME_LEN );
834         if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "", 
835                                                     fn, MAX_PATHNAME_LEN - 1))
836             _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
837         free (fn);
838
839         if (home && writeToHome)
840         {
841             fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
842                                strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
843             strcpy(fn,home);
844             strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
845
846             tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
847             strcpy(tmp,fn);
848             strcat(tmp,".tmp");
849             if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
850                 if (-1==rename(tmp,fn)) {
851                     perror("rename tmp registry");
852                     unlink(tmp);
853                 }
854             }
855             free(tmp);
856             free(fn);
857         }
858         break;
859     default:
860         ERR_(reg)("unknown/invalid key handle !\n");
861         break;
862     }
863 }
864
865
866 /******************************************************************************
867  * SHELL_SaveRegistry [Internal]
868  */
869 void SHELL_SaveRegistry( void )
870 {
871     char   buf[4];
872     HKEY   hkey;
873     int    all;
874
875     TRACE_(reg)("(void)\n");
876
877     all=0;
878     if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) 
879     {
880         strcpy(buf,"yes");
881     } 
882     else 
883     {
884         DWORD len,junk,type;
885
886         len=4;
887         if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
888                                               VAL_SAVEUPDATED,
889                                               &junk,
890                                               &type,
891                                               buf,
892                                               &len)) || (type!=REG_SZ))
893         {
894             strcpy(buf,"yes");
895         }
896         RegCloseKey(hkey);
897 }
898
899     if (lstrcmpiA(buf,"yes"))
900                 all = 1;
901
902         SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
903         SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
904         SHELL_SaveRegistryBranch(HKEY_USERS, all);
905 }
906
907
908 /************************ LOAD Registry Function ****************************/
909
910
911
912 /******************************************************************************
913  * _find_or_add_key [Internal]
914  */
915 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
916 {
917         LPKEYSTRUCT     lpxkey,*lplpkey;
918
919         if ((!keyname) || (keyname[0]==0)) {
920                 free(keyname);
921                 return lpkey;
922         }
923         lplpkey= &(lpkey->nextsub);
924         lpxkey  = *lplpkey;
925         while (lpxkey) {
926                 if (    tolower(lpxkey->keyname[0])==tolower(keyname[0]) && 
927                         !lstrcmpiW(lpxkey->keyname,keyname)
928                 )
929                         break;
930                 lplpkey = &(lpxkey->next);
931                 lpxkey  = *lplpkey;
932         }
933         if (lpxkey==NULL) {
934                 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
935                 lpxkey  = *lplpkey;
936                 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
937                 lpxkey->keyname = keyname;
938         } else
939                 free(keyname);
940         return lpxkey;
941 }
942
943 /******************************************************************************
944  * _find_or_add_value [Internal]
945  */
946 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
947                                 LPBYTE data, DWORD len, DWORD lastmodified )
948 {
949         LPKEYVALUE      val=NULL;
950         int             i;
951
952         if (name && !*name) {/* empty string equals default (NULL) value */
953                 free(name);
954                 name = NULL;
955         }
956
957         for (i=0;i<lpkey->nrofvalues;i++) {
958                 val=lpkey->values+i;
959                 if (name==NULL) {
960                         if (val->name==NULL)
961                                 break;
962                 } else {
963                         if (    val->name!=NULL &&
964                                 tolower(val->name[0])==tolower(name[0]) &&
965                                 !lstrcmpiW(val->name,name)
966                         )
967                                 break;
968                 }
969         }
970         if (i==lpkey->nrofvalues) {
971                 lpkey->values = xrealloc(
972                         lpkey->values,
973                         (++lpkey->nrofvalues)*sizeof(KEYVALUE)
974                 );
975                 val=lpkey->values+i;
976                 memset(val,'\0',sizeof(KEYVALUE));
977                 val->name = name;
978         } else {
979                 if (name)
980                         free(name);
981         }
982         if (val->lastmodified<lastmodified) {
983                 val->lastmodified=lastmodified;
984                 val->type = type;
985
986                 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
987
988                     data=xmalloc(sizeof(WCHAR));
989                     memset(data,0,sizeof(WCHAR));
990                     len =sizeof(WCHAR);
991                 }
992
993                 val->len  = len;
994                 if (val->data) 
995                         free(val->data);
996                 val->data = data;
997         } else
998                 free(data);
999 }
1000
1001
1002 /******************************************************************************
1003  * _wine_read_line [Internal]
1004  *
1005  * reads a line including dynamically enlarging the readbuffer and throwing
1006  * away comments
1007  */
1008 static int _wine_read_line( FILE *F, char **buf, int *len )
1009 {
1010         char    *s,*curread;
1011         int     mylen,curoff;
1012
1013         curread = *buf;
1014         mylen   = *len;
1015         **buf   = '\0';
1016         while (1) {
1017                 while (1) {
1018                         s=fgets(curread,mylen,F);
1019                         if (s==NULL)
1020                                 return 0; /* EOF */
1021                         if (NULL==(s=strchr(curread,'\n'))) {
1022                                 /* buffer wasn't large enough */
1023                                 curoff  = strlen(*buf);
1024                                 *buf    = xrealloc(*buf,*len*2);
1025                                 curread = *buf + curoff;
1026                                 mylen   = *len; /* we filled up the buffer and 
1027                                                  * got new '*len' bytes to fill
1028                                                  */
1029                                 *len    = *len * 2;
1030                         } else {
1031                                 *s='\0';
1032                                 break;
1033                         }
1034                 }
1035                 /* throw away comments */
1036                 if (**buf=='#' || **buf==';') {
1037                         curread = *buf;
1038                         mylen   = *len;
1039                         continue;
1040                 }
1041                 if (s)  /* got end of line */
1042                         break;
1043         }
1044         return 1;
1045 }
1046
1047
1048 /******************************************************************************
1049  * _wine_read_USTRING [Internal]
1050  *
1051  * converts a char* into a UNICODE string (up to a special char)
1052  * and returns the position exactly after that string
1053  */
1054 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1055 {
1056         char    *s;
1057         LPWSTR  ws;
1058
1059         /* read up to "=" or "\0" or "\n" */
1060         s       = buf;
1061         if (*s == '=') {
1062                 /* empty string is the win3.1 default value(NULL)*/
1063                 *str    = NULL;
1064                 return s;
1065         }
1066         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
1067         ws      = *str;
1068         while (*s && (*s!='\n') && (*s!='=')) {
1069                 if (*s!='\\')
1070                         *ws++=*((unsigned char*)s++);
1071                 else {
1072                         s++;
1073                         if (!*s) {
1074                                 /* Dangling \ ... may only happen if a registry
1075                                  * write was short. FIXME: What do to?
1076                                  */
1077                                  break;
1078                         }
1079                         if (*s=='\\') {
1080                                 *ws++='\\';
1081                                 s++;
1082                                 continue;
1083                         }
1084                         if (*s!='u') {
1085                                 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1086                                 *ws++='\\';
1087                                 *ws++=*s++;
1088                         } else {
1089                                 char    xbuf[5];
1090                                 int     wc;
1091
1092                                 s++;
1093                                 memcpy(xbuf,s,4);xbuf[4]='\0';
1094                                 if (!sscanf(xbuf,"%x",&wc))
1095                                         WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1096                                 s+=4;
1097                                 *ws++   =(unsigned short)wc;
1098                         }
1099                 }
1100         }
1101         *ws     = 0;
1102         ws      = *str;
1103         if (*ws)
1104                 *str    = strdupW(*str);
1105         else
1106                 *str    = NULL;
1107         free(ws);
1108         return s;
1109 }
1110
1111
1112 /******************************************************************************
1113  * _wine_loadsubkey [Internal]
1114  *
1115  * NOTES
1116  *    It seems like this is returning a boolean.  Should it?
1117  *
1118  * RETURNS
1119  *    Success: 1
1120  *    Failure: 0
1121  */
1122 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1123                              int *buflen, DWORD optflag )
1124 {
1125         LPKEYSTRUCT     lpxkey;
1126         int             i;
1127         char            *s;
1128         LPWSTR          name;
1129
1130     TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1131           *buflen, optflag);
1132
1133     lpkey->flags |= optflag;
1134
1135     /* Good.  We already got a line here ... so parse it */
1136     lpxkey = NULL;
1137     while (1) {
1138         i=0;s=*buf;
1139         while (*s=='\t') {
1140             s++;
1141             i++;
1142         }
1143         if (i>level) {
1144             if (lpxkey==NULL) {
1145                 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1146                 return 0;
1147             }
1148             _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1149             continue;
1150         }
1151
1152                 /* let the caller handle this line */
1153                 if (i<level || **buf=='\0')
1154                         return 1;
1155
1156                 /* it can be: a value or a keyname. Parse the name first */
1157                 s=_wine_read_USTRING(s,&name);
1158
1159                 /* switch() default: hack to avoid gotos */
1160                 switch (0) {
1161                 default:
1162                         if (*s=='\0') {
1163                                 lpxkey=_find_or_add_key(lpkey,name);
1164                         } else {
1165                                 LPBYTE          data;
1166                                 int             len,lastmodified,type;
1167
1168                                 if (*s!='=') {
1169                                         WARN_(reg)("Unexpected character: %c\n",*s);
1170                                         break;
1171                                 }
1172                                 s++;
1173                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1174                                         WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1175                                         break;
1176                                 }
1177                                 /* skip the 2 , */
1178                                 s=strchr(s,',');s++;
1179                                 s=strchr(s,',');s++;
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,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3026           *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
3027
3028     lpkey = lookup_hkey( hkey );
3029     if (!lpkey)
3030         return ERROR_INVALID_HANDLE;
3031
3032         if (!lpkey->nextsub)
3033                 return ERROR_NO_MORE_ITEMS;
3034         lpxkey=lpkey->nextsub;
3035
3036     /* Traverse the subkeys */
3037         while (iSubkey && lpxkey) {
3038                 iSubkey--;
3039                 lpxkey=lpxkey->next;
3040         }
3041
3042         if (iSubkey || !lpxkey)
3043                 return ERROR_NO_MORE_ITEMS;
3044         if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3045                 *lpcchName = lstrlenW(lpxkey->keyname)+1;
3046                 return ERROR_MORE_DATA;
3047         }
3048         memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3049
3050         if (*lpcchName)
3051             *lpcchName = lstrlenW(lpszName);
3052
3053         if (lpszClass) {
3054                 /* FIXME: what should we write into it? */
3055                 *lpszClass      = 0;
3056                 *lpcchClass     = 2;
3057         }
3058         return ERROR_SUCCESS;
3059 }
3060
3061
3062 /******************************************************************************
3063  * RegEnumKey32W [ADVAPI32.140]
3064  */
3065 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, 
3066                             DWORD lpcchName )
3067 {
3068     FILETIME    ft;
3069
3070     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3071     return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3072 }
3073
3074
3075 /******************************************************************************
3076  * RegEnumKeyEx32A [ADVAPI32.138]
3077  */
3078 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3079                               LPDWORD lpcchName, LPDWORD lpdwReserved, 
3080                               LPSTR lpszClass, LPDWORD lpcchClass, 
3081                               FILETIME *ft )
3082 {
3083         DWORD   ret,lpcchNameW,lpcchClassW;
3084         LPWSTR  lpszNameW,lpszClassW;
3085
3086
3087         TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3088                 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3089         );
3090         if (lpszName) {
3091                 lpszNameW       = (LPWSTR)xmalloc(*lpcchName*2);
3092                 lpcchNameW      = *lpcchName;
3093         } else {
3094                 lpszNameW       = NULL;
3095                 lpcchNameW      = 0;
3096         }
3097         if (lpszClass) {
3098                 lpszClassW              = (LPWSTR)xmalloc(*lpcchClass*2);
3099                 lpcchClassW     = *lpcchClass;
3100         } else {
3101                 lpszClassW      =0;
3102                 lpcchClassW=0;
3103         }
3104         ret=RegEnumKeyExW(
3105                 hkey,
3106                 iSubkey,
3107                 lpszNameW,
3108                 &lpcchNameW,
3109                 lpdwReserved,
3110                 lpszClassW,
3111                 &lpcchClassW,
3112                 ft
3113         );
3114         if (ret==ERROR_SUCCESS) {
3115                 lstrcpyWtoA(lpszName,lpszNameW);
3116                 *lpcchName=strlen(lpszName);
3117                 if (lpszClassW) {
3118                         lstrcpyWtoA(lpszClass,lpszClassW);
3119                         *lpcchClass=strlen(lpszClass);
3120                 }
3121         }
3122         if (lpszNameW)
3123                 free(lpszNameW);
3124         if (lpszClassW)
3125                 free(lpszClassW);
3126         return ret;
3127 }
3128
3129
3130 /******************************************************************************
3131  * RegEnumKey32A [ADVAPI32.137]
3132  */
3133 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3134                             DWORD lpcchName )
3135 {
3136     FILETIME    ft;
3137
3138     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3139     return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL, 
3140                             NULL, &ft );
3141 }
3142
3143
3144 /******************************************************************************
3145  * RegEnumKey16 [SHELL.7] [KERNEL.216]
3146  */
3147 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3148                            DWORD lpcchName )
3149 {
3150     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3151     return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3152 }
3153
3154
3155 /* 
3156  * Enumerate Registry Values
3157  *
3158  * Callpath:
3159  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3160  */
3161
3162
3163 /******************************************************************************
3164  * RegEnumValue32W [ADVAPI32.142]
3165  *
3166  * PARAMS
3167  *    hkey        [I] Handle to key to query
3168  *    iValue      [I] Index of value to query
3169  *    lpszValue   [O] Value string
3170  *    lpcchValue  [I/O] Size of value buffer (in wchars)
3171  *    lpdReserved [I] Reserved
3172  *    lpdwType    [O] Type code
3173  *    lpbData     [O] Value data
3174  *    lpcbData    [I/O] Size of data buffer (in bytes)
3175  *
3176  * Note:  wide character functions that take and/or return "character counts"
3177  *  use TCHAR (that is unsigned short or char) not byte counts.
3178  */
3179 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3180                               LPDWORD lpcchValue, LPDWORD lpdReserved,
3181                               LPDWORD lpdwType, LPBYTE lpbData, 
3182                               LPDWORD lpcbData )
3183 {
3184         LPKEYSTRUCT     lpkey;
3185         LPKEYVALUE      val;
3186
3187         TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3188           lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3189
3190         lpkey = lookup_hkey( hkey );
3191         
3192         if (!lpcbData && lpbData)
3193                 return ERROR_INVALID_PARAMETER;
3194                 
3195         if (!lpkey)
3196                 return ERROR_INVALID_HANDLE;
3197
3198         if (lpkey->nrofvalues <= iValue)
3199                 return ERROR_NO_MORE_ITEMS;
3200
3201         val = &(lpkey->values[iValue]);
3202
3203         if (val->name) {
3204                 if (lstrlenW(val->name)+1>*lpcchValue) {
3205                         *lpcchValue = lstrlenW(val->name)+1;
3206                         return ERROR_MORE_DATA;
3207                 }
3208                 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3209                 *lpcchValue=lstrlenW(val->name);
3210         } else {
3211                 *lpszValue      = 0;
3212                 *lpcchValue     = 0;
3213         }
3214
3215         /* Can be NULL if the type code is not required */
3216         if (lpdwType)
3217                 *lpdwType = val->type;
3218
3219         if (lpbData) {
3220                 if (val->len>*lpcbData) {
3221                         *lpcbData = val->len;
3222                         return ERROR_MORE_DATA;
3223                 }
3224                 memcpy(lpbData,val->data,val->len);
3225                 *lpcbData = val->len;
3226         }
3227
3228         debug_print_value ( val->data, val );
3229         return ERROR_SUCCESS;
3230 }
3231
3232
3233 /******************************************************************************
3234  * RegEnumValue32A [ADVAPI32.141]
3235  */
3236 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3237                               LPDWORD lpcchValue, LPDWORD lpdReserved,
3238                               LPDWORD lpdwType, LPBYTE lpbData, 
3239                               LPDWORD lpcbData )
3240 {
3241         LPWSTR  lpszValueW;
3242         LPBYTE  lpbDataW;
3243         DWORD   ret,lpcbDataW;
3244         DWORD dwType;
3245
3246         TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3247                 lpdReserved,lpdwType,lpbData,lpcbData);
3248
3249         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3250         if (lpbData) {
3251                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3252                 lpcbDataW = *lpcbData;
3253         } else
3254                 lpbDataW = NULL;
3255
3256         ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue, 
3257                                 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3258
3259         if (lpdwType)
3260                 *lpdwType = dwType;
3261
3262         if (ret==ERROR_SUCCESS) {
3263                 lstrcpyWtoA(lpszValue,lpszValueW);
3264                 if (lpbData) {
3265                         if ((1<<dwType) & UNICONVMASK) {
3266                                 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3267                         } else {
3268                                 if (lpcbDataW > *lpcbData) {
3269                                         *lpcbData = lpcbDataW;
3270                                         ret     = ERROR_MORE_DATA;
3271                                 } else
3272                                         memcpy(lpbData,lpbDataW,lpcbDataW);
3273                         }
3274                         *lpcbData = lpcbDataW;
3275                 }
3276         }
3277     if (lpbDataW) free(lpbDataW);
3278     if (lpszValueW) free(lpszValueW);
3279     return ret;
3280 }
3281
3282
3283 /******************************************************************************
3284  * RegEnumValue16 [KERNEL.223]
3285  */
3286 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue, 
3287                              LPDWORD lpcchValue, LPDWORD lpdReserved, 
3288                              LPDWORD lpdwType, LPBYTE lpbData, 
3289                              LPDWORD lpcbData )
3290 {
3291     TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3292           lpdReserved,lpdwType,lpbData,lpcbData);
3293     return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved, 
3294                             lpdwType, lpbData, lpcbData );
3295 }
3296
3297
3298 /******************************************************************************
3299  * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3300  * Releases the handle of the specified key
3301  *
3302  * PARAMS
3303  *    hkey [I] Handle of key to close
3304  *
3305  * RETURNS
3306  *    Success: ERROR_SUCCESS
3307  *    Failure: Error code
3308  */
3309 DWORD WINAPI RegCloseKey( HKEY hkey )
3310 {
3311     TRACE_(reg)("(%x)\n",hkey);
3312
3313     /* The standard handles are allowed to succeed, even though they are not
3314        closed */
3315     if (is_standard_hkey(hkey))
3316         return ERROR_SUCCESS;
3317
3318     return remove_handle(hkey);
3319 }
3320
3321
3322 /* 
3323  * Delete registry key
3324  *
3325  * Callpath:
3326  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3327  */
3328
3329
3330 /******************************************************************************
3331  * RegDeleteKey32W [ADVAPI32.134]
3332  *
3333  * PARAMS
3334  *    hkey       [I] Handle to open key
3335  *    lpszSubKey [I] Name of subkey to delete
3336  *
3337  * RETURNS
3338  *    Success: ERROR_SUCCESS
3339  *    Failure: Error code
3340  */
3341 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3342 {
3343         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
3344         LPWSTR          *wps;
3345         int             wpc,i;
3346
3347     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3348
3349     lpNextKey = lookup_hkey(hkey);
3350     if (!lpNextKey)
3351         return ERROR_INVALID_HANDLE;
3352
3353     /* Subkey param cannot be NULL */
3354     if (!lpszSubKey || !*lpszSubKey)
3355         return ERROR_BADKEY;
3356
3357     /* We need to know the previous key in the hier. */
3358         split_keypath(lpszSubKey,&wps,&wpc);
3359         i       = 0;
3360         lpxkey  = lpNextKey;
3361         while (i<wpc-1) {
3362                 lpxkey=lpNextKey->nextsub;
3363                 while (lpxkey) {
3364                         TRACE_(reg)("  Scanning [%s]\n",
3365                                      debugstr_w(lpxkey->keyname));
3366                         if (!lstrcmpiW(wps[i],lpxkey->keyname))
3367                                 break;
3368                         lpxkey=lpxkey->next;
3369                 }
3370                 if (!lpxkey) {
3371                         FREE_KEY_PATH;
3372                         TRACE_(reg)("  Not found.\n");
3373                         /* not found is success */
3374                         return ERROR_SUCCESS;
3375                 }
3376                 i++;
3377                 lpNextKey       = lpxkey;
3378         }
3379         lpxkey  = lpNextKey->nextsub;
3380         lplpPrevKey = &(lpNextKey->nextsub);
3381         while (lpxkey) {
3382                 TRACE_(reg)("  Scanning [%s]\n",
3383                              debugstr_w(lpxkey->keyname));
3384                 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3385                         break;
3386                 lplpPrevKey     = &(lpxkey->next);
3387                 lpxkey          = lpxkey->next;
3388         }
3389
3390         if (!lpxkey) {
3391                 FREE_KEY_PATH;
3392                 WARN_(reg)("  Not found.\n");
3393                 return ERROR_FILE_NOT_FOUND;
3394         }
3395
3396         if (lpxkey->nextsub) {
3397                 FREE_KEY_PATH;
3398                 WARN_(reg)("  Not empty.\n");
3399                 return ERROR_CANTWRITE;
3400         }
3401         *lplpPrevKey    = lpxkey->next;
3402         free(lpxkey->keyname);
3403         if (lpxkey->class)
3404                 free(lpxkey->class);
3405         if (lpxkey->values)
3406                 free(lpxkey->values);
3407         free(lpxkey);
3408         FREE_KEY_PATH;
3409         TRACE_(reg)("  Done.\n");
3410         return  ERROR_SUCCESS;
3411 }
3412
3413
3414 /******************************************************************************
3415  * RegDeleteKey32A [ADVAPI32.133]
3416  */
3417 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3418 {
3419     LPWSTR lpszSubKeyW;
3420     DWORD  ret;
3421
3422     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3423     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3424     ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3425     if(lpszSubKeyW) free(lpszSubKeyW);
3426     return ret;
3427 }
3428
3429
3430 /******************************************************************************
3431  * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3432  */
3433 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3434 {
3435     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3436     return RegDeleteKeyA( hkey, lpszSubKey );
3437 }
3438
3439
3440 /* 
3441  * Delete registry value
3442  *
3443  * Callpath:
3444  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3445  */
3446
3447
3448 /******************************************************************************
3449  * RegDeleteValue32W [ADVAPI32.136]
3450  *
3451  * PARAMS
3452  *    hkey      [I]
3453  *    lpszValue [I]
3454  *
3455  * RETURNS
3456  */
3457 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3458 {
3459         DWORD           i;
3460         LPKEYSTRUCT     lpkey;
3461         LPKEYVALUE      val;
3462
3463     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3464
3465     lpkey = lookup_hkey( hkey );
3466     if (!lpkey)
3467         return ERROR_INVALID_HANDLE;
3468
3469         if (lpszValue) {
3470                 for (i=0;i<lpkey->nrofvalues;i++)
3471                         if (    lpkey->values[i].name &&
3472                                 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3473                         )
3474                                 break;
3475         } else {
3476                 for (i=0;i<lpkey->nrofvalues;i++)
3477                         if (lpkey->values[i].name==NULL)
3478                                 break;
3479         }
3480
3481     if (i == lpkey->nrofvalues)
3482         return ERROR_FILE_NOT_FOUND;
3483
3484         val     = lpkey->values+i;
3485         if (val->name) free(val->name);
3486         if (val->data) free(val->data);
3487         memcpy( 
3488                 lpkey->values+i,
3489                 lpkey->values+i+1,
3490                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3491         );
3492         lpkey->values   = (LPKEYVALUE)xrealloc(
3493                                 lpkey->values,
3494                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3495                         );
3496         lpkey->nrofvalues--;
3497         return ERROR_SUCCESS;
3498 }
3499
3500
3501 /******************************************************************************
3502  * RegDeleteValue32A [ADVAPI32.135]
3503  */
3504 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3505 {
3506     LPWSTR lpszValueW;
3507     DWORD  ret;
3508
3509     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3510     lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3511     ret = RegDeleteValueW( hkey, lpszValueW );
3512     if(lpszValueW) free(lpszValueW);
3513     return ret;
3514 }
3515
3516
3517 /******************************************************************************
3518  * RegDeleteValue16 [KERNEL.222]
3519  */
3520 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3521 {
3522     TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3523     return RegDeleteValueA( hkey, lpszValue );
3524 }
3525
3526
3527 /******************************************************************************
3528  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3529  * Immediately writes key to registry.
3530  * Only returns after data has been written to disk.
3531  *
3532  * FIXME: does it really wait until data is written ?
3533  *
3534  * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3535  * written if this function really works (and only if !).
3536  *
3537  * PARAMS
3538  *    hkey [I] Handle of key to write
3539  *
3540  * RETURNS
3541  *    Success: ERROR_SUCCESS
3542  *    Failure: Error code
3543  */
3544 DWORD WINAPI RegFlushKey( HKEY hkey )
3545 {
3546     LPKEYSTRUCT lpkey;
3547
3548     TRACE_(reg)("(%x)\n", hkey);
3549
3550     lpkey = lookup_hkey( hkey );
3551     if (!lpkey)
3552         return ERROR_BADKEY;
3553
3554         SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3555         return ERROR_SUCCESS;
3556 }
3557
3558
3559 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3560
3561
3562 /******************************************************************************
3563  * RegQueryInfoKey32W [ADVAPI32.153]
3564  *
3565  * PARAMS
3566  *    hkey                   [I] Handle to key to query
3567  *    lpszClass              [O] Buffer for class string
3568  *    lpcchClass             [O] Size of class string buffer
3569  *    lpdwReserved           [I] Reserved
3570  *    lpcSubKeys             [I] Buffer for number of subkeys
3571  *    lpcchMaxSubKey         [O] Buffer for longest subkey name length
3572  *    lpcchMaxClass          [O] Buffer for longest class string length
3573  *    lpcValues              [O] Buffer for number of value entries
3574  *    lpcchMaxValueName      [O] Buffer for longest value name length
3575  *    lpccbMaxValueData      [O] Buffer for longest value data length
3576  *    lpcbSecurityDescriptor [O] Buffer for security descriptor length
3577  *    ft
3578  * - win95 allows lpszClass to be valid and lpcchClass to be NULL 
3579  * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3580  *   lpcchClass is NULL
3581  * - both allow lpszClass to be NULL and lpcchClass to be NULL 
3582  * (it's hard to test validity, so test !NULL instead)
3583  */
3584 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass, 
3585                                  LPDWORD lpcchClass, LPDWORD lpdwReserved,
3586                                  LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3587                                  LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3588                                  LPDWORD lpcchMaxValueName, 
3589                                  LPDWORD lpccbMaxValueData, 
3590                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3591 {
3592         LPKEYSTRUCT     lpkey,lpxkey;
3593         int             nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3594         int             i;
3595
3596         TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3597                 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3598                 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3599                 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3600         );
3601         lpkey = lookup_hkey(hkey);
3602         if (!lpkey)
3603                 return ERROR_INVALID_HANDLE;
3604         if (lpszClass) {
3605                 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3606                     return ERROR_INVALID_PARAMETER;
3607                 }
3608                 /* either lpcchClass is valid or this is win95 and lpcchClass
3609                    could be invalid */
3610                 if (lpkey->class) {
3611                         DWORD classLen = lstrlenW(lpkey->class);
3612
3613                         if (lpcchClass && classLen+1>*lpcchClass) {
3614                                 *lpcchClass=classLen+1;
3615                                 return ERROR_MORE_DATA;
3616                         }
3617                         if (lpcchClass)
3618                             *lpcchClass=classLen;
3619                         memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3620                 } else {
3621                         *lpszClass      = 0;
3622                         if (lpcchClass)
3623                             *lpcchClass = 0;
3624                 }
3625         } else {
3626                 if (lpcchClass)
3627                         *lpcchClass     = lstrlenW(lpkey->class);
3628         }
3629         lpxkey=lpkey->nextsub;
3630         nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3631         while (lpxkey) {
3632                 nrofkeys++;
3633                 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3634                         maxsubkey=lstrlenW(lpxkey->keyname);
3635                 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3636                         maxclass=lstrlenW(lpxkey->class);
3637                 lpxkey=lpxkey->next;
3638         }
3639         for (i=0;i<lpkey->nrofvalues;i++) {
3640                 LPKEYVALUE      val=lpkey->values+i;
3641
3642                 if (val->name && lstrlenW(val->name)>maxvname)
3643                         maxvname=lstrlenW(val->name);
3644                 if (val->len>maxvdata)
3645                         maxvdata=val->len;
3646         }
3647         if (!maxclass) maxclass = 1;
3648         if (!maxvname) maxvname = 1;
3649         if (lpcValues)
3650                 *lpcValues      = lpkey->nrofvalues;
3651         if (lpcSubKeys)
3652                 *lpcSubKeys     = nrofkeys;
3653         if (lpcchMaxSubkey)
3654                 *lpcchMaxSubkey = maxsubkey;
3655         if (lpcchMaxClass)
3656                 *lpcchMaxClass  = maxclass;
3657         if (lpcchMaxValueName)
3658                 *lpcchMaxValueName= maxvname;
3659         if (lpccbMaxValueData)
3660                 *lpccbMaxValueData= maxvdata;
3661         return ERROR_SUCCESS;
3662 }
3663
3664
3665 /******************************************************************************
3666  * RegQueryInfoKey32A [ADVAPI32.152]
3667  */
3668 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3669                                  LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3670                                  LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3671                                  LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3672                                  LPDWORD lpccbMaxValueData, 
3673                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3674 {
3675         LPWSTR          lpszClassW = NULL;
3676         DWORD           ret;
3677
3678         TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3679                 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3680                 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3681                 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3682         );
3683         if (lpszClass) {
3684                 if (lpcchClass) {
3685                     lpszClassW  = (LPWSTR)xmalloc((*lpcchClass) * 2);
3686                 } else if (VERSION_GetVersion() == WIN95) {
3687                     /* win95  allows lpcchClass to be null */
3688                     /* we don't know how big lpszClass is, would 
3689                        MAX_PATHNAME_LEN be the correct default? */
3690                     lpszClassW  = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2); 
3691                 }
3692
3693         } else
3694                 lpszClassW  = NULL;
3695         ret=RegQueryInfoKeyW(
3696                 hkey,
3697                 lpszClassW,
3698                 lpcchClass,
3699                 lpdwReserved,
3700                 lpcSubKeys,
3701                 lpcchMaxSubkey,
3702                 lpcchMaxClass,
3703                 lpcValues,
3704                 lpcchMaxValueName,
3705                 lpccbMaxValueData,
3706                 lpcbSecurityDescriptor,
3707                 ft
3708         );
3709         if (ret==ERROR_SUCCESS && lpszClass)
3710                 lstrcpyWtoA(lpszClass,lpszClassW);
3711         if (lpszClassW)
3712                 free(lpszClassW);
3713         return ret;
3714 }
3715
3716
3717 /******************************************************************************
3718  * RegConnectRegistry32W [ADVAPI32.128]
3719  *
3720  * PARAMS
3721  *    lpMachineName [I] Address of name of remote computer
3722  *    hHey          [I] Predefined registry handle
3723  *    phkResult     [I] Address of buffer for remote registry handle
3724  */
3725 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
3726                                    LPHKEY phkResult )
3727 {
3728     TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3729
3730     if (!lpMachineName || !*lpMachineName) {
3731         /* Use the local machine name */
3732         return RegOpenKey16( hKey, "", phkResult );
3733     }
3734
3735     FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3736     return ERROR_BAD_NETPATH;
3737 }
3738
3739
3740 /******************************************************************************
3741  * RegConnectRegistry32A [ADVAPI32.127]
3742  */
3743 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3744 {
3745     DWORD ret;
3746     LPWSTR machineW = strdupA2W(machine);
3747     ret = RegConnectRegistryW( machineW, hkey, reskey );
3748     free(machineW);
3749     return ret;
3750 }
3751
3752
3753 /******************************************************************************
3754  * RegGetKeySecurity [ADVAPI32.144]
3755  * Retrieves a copy of security descriptor protecting the registry key
3756  *
3757  * PARAMS
3758  *    hkey                   [I]   Open handle of key to set
3759  *    SecurityInformation    [I]   Descriptor contents
3760  *    pSecurityDescriptor    [O]   Address of descriptor for key
3761  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3762  *
3763  * RETURNS
3764  *    Success: ERROR_SUCCESS
3765  *    Failure: Error code
3766  */
3767 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
3768                                SECURITY_INFORMATION SecurityInformation,
3769                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
3770                                LPDWORD lpcbSecurityDescriptor )
3771 {
3772     LPKEYSTRUCT lpkey;
3773
3774     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3775           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3776
3777     lpkey = lookup_hkey( hkey );
3778     if (!lpkey)
3779         return ERROR_INVALID_HANDLE;
3780
3781     /* FIXME: Check for valid SecurityInformation values */
3782
3783     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3784         return ERROR_INSUFFICIENT_BUFFER;
3785
3786     FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3787           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3788
3789     return ERROR_SUCCESS;
3790 }
3791
3792
3793 /******************************************************************************
3794  * RegLoadKey32W [ADVAPI32.???]
3795  *
3796  * PARAMS
3797  *    hkey       [I] Handle of open key
3798  *    lpszSubKey [I] Address of name of subkey
3799  *    lpszFile   [I] Address of filename for registry information
3800  */
3801 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3802 {
3803     LPKEYSTRUCT lpkey;
3804     TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3805
3806     /* Do this check before the hkey check */
3807     if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3808         return ERROR_INVALID_PARAMETER;
3809
3810     lpkey = lookup_hkey( hkey );
3811     if (!lpkey)
3812         return ERROR_INVALID_HANDLE;
3813
3814     FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3815           debugstr_w(lpszFile));
3816
3817     return ERROR_SUCCESS;
3818 }
3819
3820
3821 /******************************************************************************
3822  * RegLoadKey32A [ADVAPI32.???]
3823  */
3824 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3825 {
3826     LONG ret;
3827     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3828     LPWSTR lpszFileW = strdupA2W(lpszFile);
3829     ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3830     if(lpszFileW) free(lpszFileW);
3831     if(lpszSubKeyW) free(lpszSubKeyW);
3832     return ret;
3833 }
3834
3835
3836 /******************************************************************************
3837  * RegNotifyChangeKeyValue [ADVAPI32.???]
3838  *
3839  * PARAMS
3840  *    hkey            [I] Handle of key to watch
3841  *    fWatchSubTree   [I] Flag for subkey notification
3842  *    fdwNotifyFilter [I] Changes to be reported
3843  *    hEvent          [I] Handle of signaled event
3844  *    fAsync          [I] Flag for asynchronous reporting
3845  */
3846 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
3847                                      DWORD fdwNotifyFilter, HANDLE hEvent,
3848                                      BOOL fAsync )
3849 {
3850     LPKEYSTRUCT lpkey;
3851     TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3852           hEvent,fAsync);
3853
3854     lpkey = lookup_hkey( hkey );
3855     if (!lpkey)
3856         return ERROR_INVALID_HANDLE;
3857
3858     FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3859           hEvent,fAsync);
3860
3861     return ERROR_SUCCESS;
3862 }
3863
3864
3865 /******************************************************************************
3866  * RegUnLoadKey32W [ADVAPI32.173]
3867  *
3868  * PARAMS
3869  *    hkey     [I] Handle of open key
3870  *    lpSubKey [I] Address of name of subkey to unload
3871  */
3872 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3873 {
3874     FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3875     return ERROR_SUCCESS;
3876 }
3877
3878
3879 /******************************************************************************
3880  * RegUnLoadKey32A [ADVAPI32.172]
3881  */
3882 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3883 {
3884     LONG ret;
3885     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3886     ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3887     if(lpSubKeyW) free(lpSubKeyW);
3888     return ret;
3889 }
3890
3891
3892 /******************************************************************************
3893  * RegSetKeySecurity [ADVAPI32.167]
3894  *
3895  * PARAMS
3896  *    hkey          [I] Open handle of key to set
3897  *    SecurityInfo  [I] Descriptor contents
3898  *    pSecurityDesc [I] Address of descriptor for key
3899  */
3900 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3901                                PSECURITY_DESCRIPTOR pSecurityDesc )
3902 {
3903     LPKEYSTRUCT lpkey;
3904
3905     TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3906
3907     /* It seems to perform this check before the hkey check */
3908     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3909         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3910         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3911         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3912         /* Param OK */
3913     } else
3914         return ERROR_INVALID_PARAMETER;
3915
3916     if (!pSecurityDesc)
3917         return ERROR_INVALID_PARAMETER;
3918
3919     lpkey = lookup_hkey( hkey );
3920     if (!lpkey)
3921         return ERROR_INVALID_HANDLE;
3922
3923     FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3924
3925     return ERROR_SUCCESS;
3926 }
3927
3928
3929 /******************************************************************************
3930  * RegSaveKey32W [ADVAPI32.166]
3931  *
3932  * PARAMS
3933  *    hkey   [I] Handle of key where save begins
3934  *    lpFile [I] Address of filename to save to
3935  *    sa     [I] Address of security structure
3936  */
3937 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile, 
3938                            LPSECURITY_ATTRIBUTES sa )
3939 {
3940     LPKEYSTRUCT lpkey;
3941
3942     TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3943
3944     /* It appears to do this check before the hkey check */
3945     if (!lpFile || !*lpFile)
3946         return ERROR_INVALID_PARAMETER;
3947
3948     lpkey = lookup_hkey( hkey );
3949     if (!lpkey)
3950         return ERROR_INVALID_HANDLE;
3951
3952     FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3953
3954     return ERROR_SUCCESS;
3955 }
3956
3957
3958 /******************************************************************************
3959  * RegSaveKey32A [ADVAPI32.165]
3960  */
3961 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile, 
3962                            LPSECURITY_ATTRIBUTES sa )
3963 {
3964     LONG ret;
3965     LPWSTR lpFileW = strdupA2W(lpFile);
3966     ret = RegSaveKeyW( hkey, lpFileW, sa );
3967     free(lpFileW);
3968     return ret;
3969 }
3970
3971
3972 /******************************************************************************
3973  * RegRestoreKey32W [ADVAPI32.164]
3974  *
3975  * PARAMS
3976  *    hkey    [I] Handle of key where restore begins
3977  *    lpFile  [I] Address of filename containing saved tree
3978  *    dwFlags [I] Optional flags
3979  */
3980 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3981 {
3982     LPKEYSTRUCT lpkey;
3983
3984     TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3985
3986     /* It seems to do this check before the hkey check */
3987     if (!lpFile || !*lpFile)
3988         return ERROR_INVALID_PARAMETER;
3989
3990     lpkey = lookup_hkey( hkey );
3991     if (!lpkey)
3992         return ERROR_INVALID_HANDLE;
3993
3994     FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3995
3996     /* Check for file existence */
3997
3998     return ERROR_SUCCESS;
3999 }
4000
4001
4002 /******************************************************************************
4003  * RegRestoreKey32A [ADVAPI32.163]
4004  */
4005 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4006 {
4007     LONG ret;
4008     LPWSTR lpFileW = strdupA2W(lpFile);
4009     ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4010     if(lpFileW) free(lpFileW);
4011     return ret;
4012 }
4013
4014
4015 /******************************************************************************
4016  * RegReplaceKey32W [ADVAPI32.162]
4017  *
4018  * PARAMS
4019  *    hkey      [I] Handle of open key
4020  *    lpSubKey  [I] Address of name of subkey
4021  *    lpNewFile [I] Address of filename for file with new data
4022  *    lpOldFile [I] Address of filename for backup file
4023  */
4024 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4025                               LPCWSTR lpOldFile )
4026 {
4027     LPKEYSTRUCT lpkey;
4028
4029     TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4030           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4031
4032     lpkey = lookup_hkey( hkey );
4033     if (!lpkey)
4034         return ERROR_INVALID_HANDLE;
4035
4036     FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
4037           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4038
4039     return ERROR_SUCCESS;
4040 }
4041
4042
4043 /******************************************************************************
4044  * RegReplaceKey32A [ADVAPI32.161]
4045  */
4046 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4047                               LPCSTR lpOldFile )
4048 {
4049     LONG ret;
4050     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4051     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4052     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4053     ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4054     free(lpOldFileW);
4055     free(lpNewFileW);
4056     free(lpSubKeyW);
4057     return ret;
4058 }
4059