Enable safe reading of registry file, even if file is broken.
[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             if (!_wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag))
1149                if (!_wine_read_line(F,buf,buflen))
1150                   return 1;
1151             continue;
1152         }
1153
1154                 /* let the caller handle this line */
1155                 if (i<level || **buf=='\0')
1156                         return 1;
1157
1158                 /* it can be: a value or a keyname. Parse the name first */
1159                 s=_wine_read_USTRING(s,&name);
1160
1161                 /* switch() default: hack to avoid gotos */
1162                 switch (0) {
1163                 default:
1164                         if (*s=='\0') {
1165                                 lpxkey=_find_or_add_key(lpkey,name);
1166                         } else {
1167                                 LPBYTE          data;
1168                                 int             len,lastmodified,type;
1169
1170                                 if (*s!='=') {
1171                                         WARN_(reg)("Unexpected character: %c\n",*s);
1172                                         break;
1173                                 }
1174                                 s++;
1175                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1176                                         WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1177                                         break;
1178                                 }
1179                                 /* skip the 2 , */
1180                                 s=strchr(s,',');s++;
1181                                 s=strchr(s,',');
1182                                 if (!s++) {
1183                                         WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1184                                         break;
1185                                 }
1186                                 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1187                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
1188                                         if (data)
1189                                                 len = lstrlenW((LPWSTR)data)*2+2;
1190                                         else    
1191                                                 len = 0;
1192                                 } else {
1193                                         len=strlen(s)/2;
1194                                         data = (LPBYTE)xmalloc(len+1);
1195                                         for (i=0;i<len;i++) {
1196                                                 data[i]=0;
1197                                                 if (*s>='0' && *s<='9')
1198                                                         data[i]=(*s-'0')<<4;
1199                                                 if (*s>='a' && *s<='f')
1200                                                         data[i]=(*s-'a'+'\xa')<<4;
1201                                                 if (*s>='A' && *s<='F')
1202                                                         data[i]=(*s-'A'+'\xa')<<4;
1203                                                 s++;
1204                                                 if (*s>='0' && *s<='9')
1205                                                         data[i]|=*s-'0';
1206                                                 if (*s>='a' && *s<='f')
1207                                                         data[i]|=*s-'a'+'\xa';
1208                                                 if (*s>='A' && *s<='F')
1209                                                         data[i]|=*s-'A'+'\xa';
1210                                                 s++;
1211                                         }
1212                                 }
1213                                 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1214                         }
1215                 }
1216                 /* read the next line */
1217                 if (!_wine_read_line(F,buf,buflen))
1218                         return 1;
1219     }
1220     return 1;
1221 }
1222
1223
1224 /******************************************************************************
1225  * _wine_loadsubreg [Internal]
1226  */
1227 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1228 {
1229         int     ver;
1230         char    *buf;
1231         int     buflen;
1232
1233         buf=xmalloc(10);buflen=10;
1234         if (!_wine_read_line(F,&buf,&buflen)) {
1235                 free(buf);
1236                 return 0;
1237         }
1238         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1239                 free(buf);
1240                 return 0;
1241         }
1242         if (ver!=REGISTRY_SAVE_VERSION) {
1243                 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1244                 free(buf);
1245                 return 0;
1246         }
1247         if (!_wine_read_line(F,&buf,&buflen)) {
1248                 free(buf);
1249                 return 0;
1250         }
1251         if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1252                 free(buf);
1253                 return 0;
1254         }
1255         free(buf);
1256         return 1;
1257 }
1258
1259
1260 /******************************************************************************
1261  * _wine_loadreg [Internal]
1262  */
1263 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1264 {
1265     FILE *F;
1266
1267     TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1268
1269     F = fopen(fn,"rb");
1270     if (F==NULL) {
1271         WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1272         return;
1273     }
1274     if (!_wine_loadsubreg(F,lpkey,optflag)) {
1275         fclose(F);
1276         unlink(fn);
1277         return;
1278     }
1279     fclose(F);
1280 }
1281
1282 /******************************************************************************
1283  * _flush_registry [Internal]
1284  * 
1285  * This function allow to flush section of the internal registry.  It is mainly
1286  * implements to fix a problem with the global HKU and the local HKU.
1287  * Those two files are read to build the HKU\.Default branch to finaly copy
1288  * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is, 
1289  * all the global HKU are saved onto the user's personal version of HKU hive.
1290  * which is bad...
1291  */
1292
1293  /* Forward declaration of recusive agent */
1294 static void _flush_reg(LPKEYSTRUCT from);
1295
1296 static void _flush_registry( LPKEYSTRUCT from )
1297 {
1298   /* make sure we have something... */
1299   if (from == NULL)
1300     return;
1301
1302   /* Launch the recusive agent on sub branches */
1303   _flush_reg( from->nextsub );
1304   _flush_reg( from->next );
1305
1306   /* Initialize pointers */
1307   from->nextsub = NULL;
1308   from->next    = NULL;
1309 }
1310 static void _flush_reg( LPKEYSTRUCT from )
1311 {
1312         int     j;
1313
1314   /* make sure we have something... */
1315   if (from == NULL)
1316     return;
1317
1318   /* 
1319    * do the same for the child keys 
1320    */
1321   if (from->nextsub != NULL)
1322     _flush_reg(from->nextsub);
1323
1324   /* 
1325    * do the same for the sibling keys 
1326    */
1327   if (from->next != NULL)
1328     _flush_reg(from->next);
1329
1330   /*
1331    * iterate through this key's values and delete them
1332    */
1333   for (j=0;j<from->nrofvalues;j++) 
1334   {
1335     free( (from->values+j)->name);
1336     free( (from->values+j)->data);
1337   }
1338
1339   /*
1340    * free the structure
1341    */
1342   if ( from != NULL )
1343     free(from);
1344 }
1345
1346
1347 /******************************************************************************
1348  * _copy_registry [Internal]
1349  */
1350 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1351 {
1352         LPKEYSTRUCT     lpxkey;
1353         int             j;
1354         LPKEYVALUE      valfrom;
1355
1356         from=from->nextsub;
1357         while (from) {
1358                 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1359
1360                 for (j=0;j<from->nrofvalues;j++) {
1361                         LPWSTR  name;
1362                         LPBYTE  data;
1363
1364                         valfrom = from->values+j;
1365                         name=valfrom->name;
1366                         if (name) name=strdupW(name);
1367                         data=(LPBYTE)xmalloc(valfrom->len);
1368                         memcpy(data,valfrom->data,valfrom->len);
1369
1370                         _find_or_add_value(
1371                                 lpxkey,
1372                                 name,
1373                                 valfrom->type,
1374                                 data,
1375                                 valfrom->len,
1376                                 valfrom->lastmodified
1377                         );
1378                 }
1379                 _copy_registry(from,lpxkey);
1380                 from = from->next;
1381         }
1382 }
1383
1384
1385 /* WINDOWS 95 REGISTRY LOADER */
1386 /* 
1387  * Structure of a win95 registry database.
1388  * main header:
1389  * 0 :  "CREG"  - magic
1390  * 4 :  DWORD version
1391  * 8 :  DWORD offset_of_RGDB_part
1392  * 0C..0F:      ? (someone fill in please)
1393  * 10:  WORD    number of RGDB blocks
1394  * 12:  WORD    ?
1395  * 14:  WORD    always 0000?
1396  * 16:  WORD    always 0001?
1397  * 18..1F:      ? (someone fill in please)
1398  *
1399  * 20: RGKN_section:
1400  *   header:
1401  *      0 :             "RGKN"  - magic
1402  *      4 : DWORD       offset to first RGDB section
1403  *      8 : DWORD       offset to the root record
1404  *      C..0x1B:        ? (fill in)
1405  *      0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1406  *
1407  *   Disk Key Entry Structure:
1408  *      00: DWORD       - Free entry indicator(?)
1409  *      04: DWORD       - Hash = sum of bytes of keyname
1410  *      08: DWORD       - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1411  *      0C: DWORD       - disk address of PreviousLevel Key.
1412  *      10: DWORD       - disk address of Next Sublevel Key.
1413  *      14: DWORD       - disk address of Next Key (on same level).
1414  * DKEP>18: WORD        - Nr, Low Significant part.
1415  *      1A: WORD        - Nr, High Significant part.
1416  *
1417  * The disk address always points to the nr part of the previous key entry 
1418  * of the referenced key. Don't ask me why, or even if I got this correct
1419  * from staring at 1kg of hexdumps. (DKEP)
1420  *
1421  * The High significant part of the structure seems to equal the number
1422  * of the RGDB section. The low significant part is a unique ID within
1423  * that RGDB section
1424  *
1425  * There are two minor corrections to the position of that structure.
1426  * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND 
1427  *    the DKE reread from there.
1428  * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1429  * CPS - I have not experienced the above phenomenon in my registry files
1430  *
1431  * RGDB_section:
1432  *      00:             "RGDB"  - magic
1433  *      04: DWORD       offset to next RGDB section
1434  *      08: DWORD       ?
1435  *      0C: WORD        always 000d?
1436  *      0E: WORD        RGDB block number
1437  *      10:     DWORD   ? (equals value at offset 4 - value at offset 8)
1438  *      14..1F:         ?
1439  *      20.....:        disk keys
1440  *
1441  * disk key:
1442  *      00:     DWORD   nextkeyoffset   - offset to the next disk key structure
1443  *      08:     WORD    nrLS            - low significant part of NR
1444  *      0A:     WORD    nrHS            - high significant part of NR
1445  *      0C:     DWORD   bytesused       - bytes used in this structure.
1446  *      10:     WORD    name_len        - length of name in bytes. without \0
1447  *      12:     WORD    nr_of_values    - number of values.
1448  *      14:     char    name[name_len]  - name string. No \0.
1449  *      14+name_len: disk values
1450  *      nextkeyoffset: ... next disk key
1451  *
1452  * disk value:
1453  *      00:     DWORD   type            - value type (hmm, could be WORD too)
1454  *      04:     DWORD                   - unknown, usually 0
1455  *      08:     WORD    namelen         - length of Name. 0 means name=NULL
1456  *      0C:     WORD    datalen         - length of Data.
1457  *      10:     char    name[namelen]   - name, no \0
1458  *      10+namelen: BYTE        data[datalen] - data, without \0 if string
1459  *      10+namelen+datalen: next values or disk key
1460  *
1461  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1462  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1463  * structure) and reading another RGDB_section.
1464  * repeat until end of file.
1465  *
1466  * An interesting relationship exists in RGDB_section. The value at offset
1467  * 10 equals the value at offset 4 minus the value at offset 8. I have no
1468  * idea at the moment what this means.  (Kevin Cozens)
1469  *
1470  * FIXME: this description needs some serious help, yes.
1471  */
1472
1473 struct  _w95keyvalue {
1474         unsigned long           type;
1475         unsigned short          datalen;
1476         char                    *name;
1477         unsigned char           *data;
1478         unsigned long           x1;
1479         int                     lastmodified;
1480 };
1481
1482 struct  _w95key {
1483         char                    *name;
1484         int                     nrofvals;
1485         struct  _w95keyvalue    *values;
1486         struct _w95key          *prevlvl;
1487         struct _w95key          *nextsub;
1488         struct _w95key          *next;
1489 };
1490
1491
1492 struct _w95_info {
1493   char *rgknbuffer;
1494   int  rgknsize;
1495   char *rgdbbuffer;
1496   int  rgdbsize;
1497   int  depth;
1498   int  lastmodified;
1499 };
1500
1501
1502 /******************************************************************************
1503  * _w95_processKey [Internal]
1504  */
1505 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey, 
1506                                    int nrLS, int nrMS, struct _w95_info *info )
1507
1508 {
1509   /* Disk Key Header structure (RGDB part) */
1510         struct  dkh {
1511                 unsigned long           nextkeyoff; 
1512                 unsigned short          nrLS;
1513                 unsigned short          nrMS;
1514                 unsigned long           bytesused;
1515                 unsigned short          keynamelen;
1516                 unsigned short          values;
1517                 unsigned long           xx1;
1518                 /* keyname */
1519                 /* disk key values or nothing */
1520         };
1521         /* Disk Key Value structure */
1522         struct  dkv {
1523                 unsigned long           type;
1524                 unsigned long           x1;
1525                 unsigned short          valnamelen;
1526                 unsigned short          valdatalen;
1527                 /* valname, valdata */
1528         };
1529
1530         
1531         struct  dkh dkh;
1532         int     bytesread = 0;
1533         char    *rgdbdata = info->rgdbbuffer;
1534         int     nbytes = info->rgdbsize;
1535         char    *curdata = rgdbdata;
1536         char    *end = rgdbdata + nbytes;
1537         int     off_next_rgdb;
1538         char    *next = rgdbdata;
1539         int     nrgdb, i;
1540         LPKEYSTRUCT     lpxkey;
1541         
1542         do {
1543           curdata = next;
1544           if (strncmp(curdata, "RGDB", 4)) return (NULL);
1545             
1546           memcpy(&off_next_rgdb,curdata+4,4);
1547           next = curdata + off_next_rgdb;
1548           nrgdb = (int) *((short *)curdata + 7);
1549
1550         } while (nrgdb != nrMS && (next < end));
1551
1552         /* curdata now points to the start of the right RGDB section */
1553         curdata += 0x20;
1554
1555 #define XREAD(whereto,len) \
1556         if ((curdata + len) <= end) {\
1557                 memcpy(whereto,curdata,len);\
1558                 curdata+=len;\
1559                 bytesread+=len;\
1560         }
1561
1562         while (curdata < next) {
1563           struct        dkh *xdkh = (struct dkh*)curdata;
1564
1565           bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1566           if (xdkh->nrLS == nrLS) {
1567                 memcpy(&dkh,xdkh,sizeof(dkh));
1568                 curdata += sizeof(dkh);
1569                 break;
1570           }
1571           curdata += xdkh->nextkeyoff;
1572         };
1573
1574         if (dkh.nrLS != nrLS) return (NULL);
1575
1576         if (nrgdb != dkh.nrMS)
1577           return (NULL);
1578
1579         assert((dkh.keynamelen<2) || curdata[0]);
1580         lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1581         curdata += dkh.keynamelen;
1582
1583         for (i=0;i< dkh.values; i++) {
1584           struct dkv dkv;
1585           LPBYTE data;
1586           int len;
1587           LPWSTR name;
1588
1589           XREAD(&dkv,sizeof(dkv));
1590
1591           name = strcvtA2W(curdata, dkv.valnamelen);
1592           curdata += dkv.valnamelen;
1593
1594           if ((1 << dkv.type) & UNICONVMASK) {
1595             data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1596             len = 2*(dkv.valdatalen + 1);
1597           } else {
1598             /* I don't think we want to NULL terminate all data */
1599             data = xmalloc(dkv.valdatalen);
1600             memcpy (data, curdata, dkv.valdatalen);
1601             len = dkv.valdatalen;
1602           }
1603
1604           curdata += dkv.valdatalen;
1605           
1606           _find_or_add_value(
1607                              lpxkey,
1608                              name,
1609                              dkv.type,
1610                              data,
1611                              len,
1612                              info->lastmodified
1613                              );
1614         }
1615         return (lpxkey);
1616 }
1617
1618 /******************************************************************************
1619  * _w95_walkrgkn [Internal]
1620  */
1621 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off, 
1622                            struct _w95_info *info )
1623
1624 {
1625   /* Disk Key Entry structure (RGKN part) */
1626   struct        dke {
1627     unsigned long               x1;
1628     unsigned long               x2;
1629     unsigned long               x3;/*usually 0xFFFFFFFF */
1630     unsigned long               prevlvl;
1631     unsigned long               nextsub;
1632     unsigned long               next;
1633     unsigned short              nrLS;
1634     unsigned short              nrMS;
1635   } *dke = (struct dke *)off;
1636   LPKEYSTRUCT  lpxkey;
1637
1638   if (dke == NULL) {
1639     dke = (struct dke *) ((char *)info->rgknbuffer);
1640   }
1641
1642   lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1643   /* XXX <-- This is a hack*/
1644   if (!lpxkey) {
1645     lpxkey = prevkey;
1646   }
1647
1648   if (dke->nextsub != -1 && 
1649       ((dke->nextsub - 0x20) < info->rgknsize) 
1650       && (dke->nextsub > 0x20)) {
1651     
1652     _w95_walkrgkn(lpxkey, 
1653                   info->rgknbuffer + dke->nextsub - 0x20, 
1654                   info);
1655   }
1656   
1657   if (dke->next != -1 && 
1658       ((dke->next - 0x20) < info->rgknsize) && 
1659       (dke->next > 0x20)) {
1660     _w95_walkrgkn(prevkey,  
1661                   info->rgknbuffer + dke->next - 0x20,
1662                   info);
1663   }
1664
1665   return;
1666 }
1667
1668
1669 /******************************************************************************
1670  * _w95_loadreg [Internal]
1671  */
1672 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1673 {
1674         HFILE           hfd;
1675         char            magic[5];
1676         unsigned long   where,version,rgdbsection,end;
1677         struct          _w95_info info;
1678         OFSTRUCT        ofs;
1679         BY_HANDLE_FILE_INFORMATION hfdinfo;
1680
1681         TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1682         hfd=OpenFile(fn,&ofs,OF_READ);
1683         if (hfd==HFILE_ERROR)
1684                 return;
1685         magic[4]=0;
1686         if (4!=_lread(hfd,magic,4))
1687                 return;
1688         if (strcmp(magic,"CREG")) {
1689                 WARN_(reg)("%s is not a w95 registry.\n",fn);
1690                 return;
1691         }
1692         if (4!=_lread(hfd,&version,4))
1693                 return;
1694         if (4!=_lread(hfd,&rgdbsection,4))
1695                 return;
1696         if (-1==_llseek(hfd,0x20,SEEK_SET))
1697                 return;
1698         if (4!=_lread(hfd,magic,4))
1699                 return;
1700         if (strcmp(magic,"RGKN")) {
1701                 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1702                 return;
1703         }
1704
1705         /* STEP 1: Keylink structures */
1706         if (-1==_llseek(hfd,0x40,SEEK_SET))
1707                 return;
1708         where   = 0x40;
1709         end     = rgdbsection;
1710
1711         info.rgknsize = end - where;
1712         info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1713         if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1714                 return;
1715
1716         if (!GetFileInformationByHandle(hfd,&hfdinfo))
1717                 return;
1718
1719         end = hfdinfo.nFileSizeLow;
1720         info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1721
1722         if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1723                 return;
1724
1725         info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1726         info.rgdbsize = end - rgdbsection;
1727
1728         if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1729                 return;
1730         _lclose(hfd);
1731
1732         _w95_walkrgkn(lpkey, NULL, &info);
1733
1734         free (info.rgdbbuffer);
1735         free (info.rgknbuffer);
1736 }
1737
1738
1739 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1740
1741 /*
1742     reghack - windows 3.11 registry data format demo program.
1743
1744     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1745     a combined hash table and tree description, and finally a text table.
1746
1747     The header is obvious from the struct header. The taboff1 and taboff2
1748     fields are always 0x20, and their usage is unknown.
1749
1750     The 8-byte entry table has various entry types.
1751
1752     tabent[0] is a root index. The second word has the index of the root of
1753             the directory.
1754     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1755             the index of the key/value that has that hash. Data with the same
1756             hash value are on a circular list. The other three words in the
1757             hash entry are always zero.
1758     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1759             entry: dirent and keyent/valent. They are identified by context.
1760     tabent[freeidx] is the first free entry. The first word in a free entry
1761             is the index of the next free entry. The last has 0 as a link.
1762             The other three words in the free list are probably irrelevant.
1763
1764     Entries in text table are preceeded by a word at offset-2. This word
1765     has the value (2*index)+1, where index is the referring keyent/valent
1766     entry in the table. I have no suggestion for the 2* and the +1.
1767     Following the word, there are N bytes of data, as per the keyent/valent
1768     entry length. The offset of the keyent/valent entry is from the start
1769     of the text table to the first data byte.
1770
1771     This information is not available from Microsoft. The data format is
1772     deduced from the reg.dat file by me. Mistakes may
1773     have been made. I claim no rights and give no guarantees for this program.
1774
1775     Tor Sjøwall, tor@sn.no
1776 */
1777
1778 /* reg.dat header format */
1779 struct _w31_header {
1780         char            cookie[8];      /* 'SHCC3.10' */
1781         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1782         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1783         unsigned long   tabcnt;         /* number of entries in index table */
1784         unsigned long   textoff;        /* offset of text part */
1785         unsigned long   textsize;       /* byte size of text part */
1786         unsigned short  hashsize;       /* hash size */
1787         unsigned short  freeidx;        /* free index */
1788 };
1789
1790 /* generic format of table entries */
1791 struct _w31_tabent {
1792         unsigned short w0, w1, w2, w3;
1793 };
1794
1795 /* directory tabent: */
1796 struct _w31_dirent {
1797         unsigned short  sibling_idx;    /* table index of sibling dirent */
1798         unsigned short  child_idx;      /* table index of child dirent */
1799         unsigned short  key_idx;        /* table index of key keyent */
1800         unsigned short  value_idx;      /* table index of value valent */
1801 };
1802
1803 /* key tabent: */
1804 struct _w31_keyent {
1805         unsigned short  hash_idx;       /* hash chain index for string */
1806         unsigned short  refcnt;         /* reference count */
1807         unsigned short  length;         /* length of string */
1808         unsigned short  string_off;     /* offset of string in text table */
1809 };
1810
1811 /* value tabent: */
1812 struct _w31_valent {
1813         unsigned short  hash_idx;       /* hash chain index for string */
1814         unsigned short  refcnt;         /* reference count */
1815         unsigned short  length;         /* length of string */
1816         unsigned short  string_off;     /* offset of string in text table */
1817 };
1818
1819 /* recursive helper function to display a directory tree */
1820 void
1821 __w31_dumptree( unsigned short idx,
1822                 unsigned char *txt,
1823                 struct _w31_tabent *tab,
1824                 struct _w31_header *head,
1825                 LPKEYSTRUCT     lpkey,
1826                 time_t          lastmodified,
1827                 int             level
1828 ) {
1829         struct _w31_dirent      *dir;
1830         struct _w31_keyent      *key;
1831         struct _w31_valent      *val;
1832         LPKEYSTRUCT             xlpkey = NULL;
1833         LPWSTR                  name,value;
1834         static char             tail[400];
1835
1836         while (idx!=0) {
1837                 dir=(struct _w31_dirent*)&tab[idx];
1838
1839                 if (dir->key_idx) {
1840                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1841
1842                         memcpy(tail,&txt[key->string_off],key->length);
1843                         tail[key->length]='\0';
1844                         /* all toplevel entries AND the entries in the 
1845                          * toplevel subdirectory belong to \SOFTWARE\Classes
1846                          */
1847                         if (!level && !lstrcmpA(tail,".classes")) {
1848                                 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1849                                 idx=dir->sibling_idx;
1850                                 continue;
1851                         }
1852                         name=strdupA2W(tail);
1853
1854                         xlpkey=_find_or_add_key(lpkey,name);
1855
1856                         /* only add if leaf node or valued node */
1857                         if (dir->value_idx!=0||dir->child_idx==0) {
1858                                 if (dir->value_idx) {
1859                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1860                                         memcpy(tail,&txt[val->string_off],val->length);
1861                                         tail[val->length]='\0';
1862                                         value=strdupA2W(tail);
1863                                         _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1864                                 }
1865                         }
1866                 } else {
1867                         TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1868                 }
1869                 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1870                 idx=dir->sibling_idx;
1871         }
1872 }
1873
1874
1875 /******************************************************************************
1876  * _w31_loadreg [Internal]
1877  */
1878 void _w31_loadreg(void) {
1879         HFILE                   hf;
1880         struct _w31_header      head;
1881         struct _w31_tabent      *tab;
1882         unsigned char           *txt;
1883         int                     len;
1884         OFSTRUCT                ofs;
1885         BY_HANDLE_FILE_INFORMATION hfinfo;
1886         time_t                  lastmodified;
1887         LPKEYSTRUCT             lpkey;
1888
1889         TRACE_(reg)("(void)\n");
1890
1891         hf = OpenFile("reg.dat",&ofs,OF_READ);
1892         if (hf==HFILE_ERROR)
1893                 return;
1894
1895         /* read & dump header */
1896         if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1897                 ERR_(reg)("reg.dat is too short.\n");
1898                 _lclose(hf);
1899                 return;
1900         }
1901         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1902                 ERR_(reg)("reg.dat has bad signature.\n");
1903                 _lclose(hf);
1904                 return;
1905         }
1906
1907         len = head.tabcnt * sizeof(struct _w31_tabent);
1908         /* read and dump index table */
1909         tab = xmalloc(len);
1910         if (len!=_lread(hf,tab,len)) {
1911                 ERR_(reg)("couldn't read %d bytes.\n",len); 
1912                 free(tab);
1913                 _lclose(hf);
1914                 return;
1915         }
1916
1917         /* read text */
1918         txt = xmalloc(head.textsize);
1919         if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1920                 ERR_(reg)("couldn't seek to textblock.\n"); 
1921                 free(tab);
1922                 free(txt);
1923                 _lclose(hf);
1924                 return;
1925         }
1926         if (head.textsize!=_lread(hf,txt,head.textsize)) {
1927                 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize); 
1928                 free(tab);
1929                 free(txt);
1930                 _lclose(hf);
1931                 return;
1932         }
1933
1934         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1935                 ERR_(reg)("GetFileInformationByHandle failed?.\n"); 
1936                 free(tab);
1937                 free(txt);
1938                 _lclose(hf);
1939                 return;
1940         }
1941         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1942         lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1943         __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1944         free(tab);
1945         free(txt);
1946         _lclose(hf);
1947         return;
1948 }
1949
1950
1951 /**********************************************************************************
1952  * SHELL_LoadRegistry [Internal]
1953  */
1954 void SHELL_LoadRegistry( void )
1955 {
1956   char        *fn, *home;
1957   LPKEYSTRUCT   lpkey, HKCU, HKU, HKLM;
1958   HKEY              hkey;
1959
1960   TRACE_(reg)("(void)\n");
1961
1962   HKCU = lookup_hkey(HKEY_CURRENT_USER);
1963   HKU  = lookup_hkey(HKEY_USERS);
1964   HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1965
1966   if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1)) 
1967   { 
1968       /* Load windows 3.1 entries */
1969       _w31_loadreg();
1970       /* Load windows 95 entries */
1971       _w95_loadreg("C:\\system.1st",    HKLM);
1972       _w95_loadreg("system.dat",        HKLM);
1973       _w95_loadreg("user.dat",  HKU);
1974   }
1975
1976   if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1977   {
1978       /* 
1979        * Load the global HKU hive directly from sysconfdir
1980        */ 
1981       _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1982
1983       /* 
1984        * Load the global machine defaults directly form sysconfdir
1985        */
1986       _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1987   }
1988
1989   /*
1990    * Load the user saved registries 
1991    */
1992   if (!(home = getenv( "HOME" )))
1993       WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1994   else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1995   {
1996       /* 
1997        * Load user's personal versions of global HKU/.Default keys
1998        */
1999       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
2000                          strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2001       strcpy(fn, home);
2002       strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2003       _wine_loadreg(HKU, fn, REG_OPTION_TAINTED); 
2004       free(fn);
2005
2006       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
2007       strcpy(fn, home);
2008       strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2009       _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2010       free(fn);
2011
2012       /* 
2013        * Load HKLM, attempt to get the registry location from the config 
2014        * file first, if exist, load and keep going.
2015        */
2016       fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
2017       strcpy(fn,home);
2018       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2019       _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2020       free(fn);
2021   }
2022   
2023   /* 
2024    * Load HKCU, get the registry location from the config 
2025    * file, if exist, load and keep going.
2026    */      
2027   if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
2028   {
2029       fn = xmalloc( MAX_PATHNAME_LEN ); 
2030       if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", 
2031                                      fn, MAX_PATHNAME_LEN - 1)) 
2032        {
2033          _wine_loadreg(HKCU,fn,REG_OPTION_TAINTED);
2034        }
2035       free (fn);
2036       /*
2037        * Load HKU, get the registry location from the config
2038        * file, if exist, load and keep going.
2039        */
2040       fn = xmalloc ( MAX_PATHNAME_LEN );
2041       if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
2042                                       fn, MAX_PATHNAME_LEN - 1))
2043        {
2044          _wine_loadreg(HKU,fn,REG_OPTION_TAINTED);
2045        }
2046       free (fn);
2047       /*
2048        * Load HKLM, get the registry location from the config
2049        * file, if exist, load and keep going.
2050        */
2051       fn = xmalloc ( MAX_PATHNAME_LEN );
2052       if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
2053                                      fn, MAX_PATHNAME_LEN - 1))
2054        {
2055          _wine_loadreg(HKLM,fn,REG_OPTION_TAINTED); 
2056        }
2057       free (fn);
2058     }
2059   
2060   /* 
2061    * Obtain the handle of the HKU\.Default key.
2062    * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER 
2063    */
2064   RegCreateKey16(HKEY_USERS,".Default",&hkey);
2065   lpkey = lookup_hkey(hkey);
2066   if(!lpkey){
2067      WARN_(reg)("Could not create global user default key\n");
2068   } else {
2069     _copy_registry(lpkey, HKCU );
2070   }
2071
2072   RegCloseKey(hkey);
2073
2074   /* 
2075    * Since HKU is built from the global HKU and the local user HKU file we must
2076    * flush the HKU tree we have built at this point otherwise the part brought
2077    * in from the global HKU is saved into the local HKU.  To avoid this 
2078    * useless dupplication of HKU keys we reread the local HKU key.
2079    */
2080
2081   /* Allways flush the HKU hive and reload it only with user's personal HKU */
2082   _flush_registry(HKU); 
2083
2084   /* Reload user's local HKU hive */
2085   if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
2086   {
2087       fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2088                          + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2089       
2090       strcpy(fn,home);
2091       strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2092
2093       _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2094
2095       free(fn);
2096   }
2097
2098   /* 
2099    * Make sure the update mode is there
2100    */
2101   if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) 
2102   {
2103     DWORD       junk,type,len;
2104     char        data[5];
2105
2106     len=4;
2107     if ((       RegQueryValueExA(
2108             hkey,
2109             VAL_SAVEUPDATED,
2110             &junk,
2111             &type,
2112             data,
2113             &len) != ERROR_SUCCESS) || (type != REG_SZ))
2114     {
2115       RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2116     }
2117
2118     RegCloseKey(hkey);
2119   }
2120 }
2121
2122
2123 /********************* API FUNCTIONS ***************************************/
2124 /*
2125  * Open Keys.
2126  *
2127  * All functions are stubs to RegOpenKeyEx32W where all the
2128  * magic happens. 
2129  *
2130  * Callpath:
2131  * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2132  *                                  RegOpenKey32W   -> RegOpenKeyEx32W 
2133  */
2134
2135
2136 /******************************************************************************
2137  * RegOpenKeyEx32W [ADVAPI32.150]
2138  * Opens the specified key
2139  *
2140  * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2141  *
2142  * PARAMS
2143  *    hkey       [I] Handle of open key
2144  *    lpszSubKey [I] Name of subkey to open
2145  *    dwReserved [I] Reserved - must be zero
2146  *    samDesired [I] Security access mask
2147  *    retkey     [O] Address of handle of open key
2148  *
2149  * RETURNS
2150  *    Success: ERROR_SUCCESS
2151  *    Failure: Error code
2152  */
2153 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2154                               REGSAM samDesired, LPHKEY retkey )
2155 {
2156         LPKEYSTRUCT     lpNextKey,lpxkey;
2157         LPWSTR          *wps;
2158         int             wpc,i;
2159
2160     TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2161           samDesired,retkey);
2162
2163     lpNextKey = lookup_hkey( hkey );
2164     if (!lpNextKey)
2165         return ERROR_INVALID_HANDLE;
2166
2167     if (!lpszSubKey || !*lpszSubKey) {
2168         /* Either NULL or pointer to empty string, so return a new handle
2169            to the original hkey */
2170         currenthandle += 2;
2171         add_handle(currenthandle,lpNextKey,samDesired);
2172         *retkey=currenthandle;
2173         return ERROR_SUCCESS;
2174     }
2175
2176     if (lpszSubKey[0] == '\\') {
2177         WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2178         return ERROR_BAD_PATHNAME;
2179     }
2180
2181         split_keypath(lpszSubKey,&wps,&wpc);
2182         i = 0;
2183         while ((i<wpc) && (wps[i][0]=='\0')) i++;
2184         lpxkey = lpNextKey;
2185
2186     while (wps[i]) {
2187         lpxkey=lpNextKey->nextsub;
2188         while (lpxkey) {
2189             if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2190                 break;
2191             }
2192             lpxkey=lpxkey->next;
2193         }
2194
2195         if (!lpxkey) {
2196             TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2197             FREE_KEY_PATH;
2198             return ERROR_FILE_NOT_FOUND;
2199         }
2200         i++;
2201         lpNextKey = lpxkey;
2202     }
2203
2204     currenthandle += 2;
2205     add_handle(currenthandle,lpxkey,samDesired);
2206     *retkey = currenthandle;
2207     TRACE_(reg)("  Returning %x\n", currenthandle);
2208     FREE_KEY_PATH;
2209     return ERROR_SUCCESS;
2210 }
2211
2212
2213 /******************************************************************************
2214  * RegOpenKeyEx32A [ADVAPI32.149]
2215  */
2216 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2217                               REGSAM samDesired, LPHKEY retkey )
2218 {
2219     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2220     DWORD ret;
2221
2222     TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2223           samDesired,retkey);
2224     ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2225     free(lpszSubKeyW);
2226     return ret;
2227 }
2228
2229
2230 /******************************************************************************
2231  * RegOpenKey32W [ADVAPI32.151]
2232  *
2233  * PARAMS
2234  *    hkey       [I] Handle of open key
2235  *    lpszSubKey [I] Address of name of subkey to open
2236  *    retkey     [O] Address of handle of open key
2237  *
2238  * RETURNS
2239  *    Success: ERROR_SUCCESS
2240  *    Failure: Error code
2241  */
2242 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2243 {
2244     TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2245     return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2246 }
2247
2248
2249 /******************************************************************************
2250  * RegOpenKey32A [ADVAPI32.148]
2251  */
2252 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2253 {
2254     DWORD ret;
2255     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2256     TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2257     ret =  RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2258     free(lpszSubKeyW);
2259     return ret;
2260 }
2261
2262
2263 /******************************************************************************
2264  * RegOpenKey16 [SHELL.1] [KERNEL.217]
2265  */
2266 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2267 {
2268     TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2269     return RegOpenKeyA( hkey, lpszSubKey, retkey );
2270 }
2271
2272
2273 /* 
2274  * Create keys
2275  * 
2276  * All those functions convert their respective 
2277  * arguments and call RegCreateKeyExW at the end.
2278  *
2279  * We stay away from the Ex functions as long as possible because there are
2280  * differences in the return values
2281  *
2282  * Callpath:
2283  *                                      RegCreateKeyEx32A \
2284  * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W   -> RegCreateKeyEx32W
2285  */
2286
2287
2288 /******************************************************************************
2289  * RegCreateKeyEx32W [ADVAPI32.131]
2290  *
2291  * PARAMS
2292  *    hkey         [I] Handle of an open key
2293  *    lpszSubKey   [I] Address of subkey name
2294  *    dwReserved   [I] Reserved - must be 0
2295  *    lpszClass    [I] Address of class string
2296  *    fdwOptions   [I] Special options flag
2297  *    samDesired   [I] Desired security access
2298  *    lpSecAttribs [I] Address of key security structure
2299  *    retkey       [O] Address of buffer for opened handle
2300  *    lpDispos     [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2301  */
2302 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey, 
2303                                 DWORD dwReserved, LPWSTR lpszClass, 
2304                                 DWORD fdwOptions, REGSAM samDesired,
2305                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
2306                                 LPHKEY retkey, LPDWORD lpDispos )
2307 {
2308         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
2309         LPWSTR          *wps;
2310         int             wpc,i;
2311
2312     TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2313                 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2314                 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2315
2316     lpNextKey = lookup_hkey(hkey);
2317     if (!lpNextKey)
2318         return ERROR_INVALID_HANDLE;
2319
2320     /* Check for valid options */
2321     switch(fdwOptions) {
2322         case REG_OPTION_NON_VOLATILE:
2323         case REG_OPTION_VOLATILE:
2324         case REG_OPTION_BACKUP_RESTORE:
2325             break;
2326         default:
2327             return ERROR_INVALID_PARAMETER;
2328     }
2329
2330     /* Sam has to be a combination of the following */
2331     if (!(samDesired & 
2332           (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY | 
2333            KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2334            KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2335         return ERROR_INVALID_PARAMETER;
2336
2337         if (!lpszSubKey || !*lpszSubKey) {
2338                 currenthandle += 2;
2339                 add_handle(currenthandle,lpNextKey,samDesired);
2340                 *retkey=currenthandle;
2341                 TRACE_(reg)("Returning %x\n", currenthandle);
2342                 lpNextKey->flags|=REG_OPTION_TAINTED;
2343                 return ERROR_SUCCESS;
2344         }
2345
2346     if (lpszSubKey[0] == '\\') {
2347         WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2348         return ERROR_BAD_PATHNAME;
2349     }
2350
2351         split_keypath(lpszSubKey,&wps,&wpc);
2352         i       = 0;
2353         while ((i<wpc) && (wps[i][0]=='\0')) i++;
2354         lpxkey  = lpNextKey;
2355         while (wps[i]) {
2356                 lpxkey=lpNextKey->nextsub;
2357                 while (lpxkey) {
2358                         if (!lstrcmpiW(wps[i],lpxkey->keyname))
2359                                 break;
2360                         lpxkey=lpxkey->next;
2361                 }
2362                 if (!lpxkey)
2363                         break;
2364                 i++;
2365                 lpNextKey       = lpxkey;
2366         }
2367         if (lpxkey) {
2368                 currenthandle += 2;
2369                 add_handle(currenthandle,lpxkey,samDesired);
2370                 lpxkey->flags  |= REG_OPTION_TAINTED;
2371                 *retkey         = currenthandle;
2372                 TRACE_(reg)("Returning %x\n", currenthandle);
2373                 if (lpDispos)
2374                         *lpDispos       = REG_OPENED_EXISTING_KEY;
2375                 FREE_KEY_PATH;
2376                 return ERROR_SUCCESS;
2377         }
2378
2379         /* Good.  Now the hard part */
2380         while (wps[i]) {
2381                 lplpPrevKey     = &(lpNextKey->nextsub);
2382                 lpxkey          = *lplpPrevKey;
2383                 while (lpxkey) {
2384                         lplpPrevKey     = &(lpxkey->next);
2385                         lpxkey          = *lplpPrevKey;
2386                 }
2387                 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2388                 if (!*lplpPrevKey) {
2389                         FREE_KEY_PATH;
2390                         TRACE_(reg)("Returning OUTOFMEMORY\n");
2391                         return ERROR_OUTOFMEMORY;
2392                 }
2393                 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2394                 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2395                 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2396                 (*lplpPrevKey)->next    = NULL;
2397                 (*lplpPrevKey)->nextsub = NULL;
2398                 (*lplpPrevKey)->values  = NULL;
2399                 (*lplpPrevKey)->nrofvalues = 0;
2400                 (*lplpPrevKey)->flags   = REG_OPTION_TAINTED;
2401                 if (lpszClass)
2402                         (*lplpPrevKey)->class = strdupW(lpszClass);
2403                 else
2404                         (*lplpPrevKey)->class = NULL;
2405                 lpNextKey       = *lplpPrevKey;
2406                 i++;
2407         }
2408         currenthandle += 2;
2409         add_handle(currenthandle,lpNextKey,samDesired);
2410
2411         /*FIXME: flag handling correct? */
2412         lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2413         if (lpszClass)
2414                 lpNextKey->class = strdupW(lpszClass);
2415         else
2416                 lpNextKey->class = NULL;
2417         *retkey         = currenthandle;
2418         TRACE_(reg)("Returning %x\n", currenthandle);
2419         if (lpDispos)
2420                 *lpDispos       = REG_CREATED_NEW_KEY;
2421         FREE_KEY_PATH;
2422         return ERROR_SUCCESS;
2423 }
2424
2425
2426 /******************************************************************************
2427  * RegCreateKeyEx32A [ADVAPI32.130]
2428  */
2429 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2430                                 LPSTR lpszClass, DWORD fdwOptions, 
2431                                 REGSAM samDesired, 
2432                                 LPSECURITY_ATTRIBUTES lpSecAttribs, 
2433                                 LPHKEY retkey, LPDWORD lpDispos )
2434 {
2435     LPWSTR lpszSubKeyW, lpszClassW;
2436     DWORD  ret;
2437
2438     TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2439           dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2440           retkey,lpDispos);
2441
2442     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2443     lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2444
2445     ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW, 
2446                              fdwOptions, samDesired, lpSecAttribs, retkey, 
2447                              lpDispos );
2448
2449     if(lpszSubKeyW) free(lpszSubKeyW);
2450     if(lpszClassW) free(lpszClassW);
2451
2452     return ret;
2453 }
2454
2455
2456 /******************************************************************************
2457  * RegCreateKey32W [ADVAPI32.132]
2458  */
2459 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2460 {
2461     DWORD junk;
2462     LPKEYSTRUCT lpNextKey;
2463
2464     TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2465
2466     /* This check is here because the return value is different than the
2467        one from the Ex functions */
2468     lpNextKey = lookup_hkey(hkey);
2469     if (!lpNextKey)
2470         return ERROR_BADKEY;
2471
2472     return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL, 
2473                               REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2474                               retkey, &junk);
2475 }
2476
2477
2478 /******************************************************************************
2479  * RegCreateKey32A [ADVAPI32.129]
2480  */
2481 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2482 {
2483     DWORD ret;
2484     LPWSTR lpszSubKeyW;
2485
2486     TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2487     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2488     ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2489     if(lpszSubKeyW) free(lpszSubKeyW);
2490     return ret;
2491 }
2492
2493
2494 /******************************************************************************
2495  * RegCreateKey16 [SHELL.2] [KERNEL.218]
2496  */
2497 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2498 {
2499     TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2500     return RegCreateKeyA( hkey, lpszSubKey, retkey );
2501 }
2502
2503
2504 /* 
2505  * Query Value Functions
2506  * Win32 differs between keynames and valuenames. 
2507  * multiple values may belong to one key, the special value
2508  * with name NULL is the default value used by the win31
2509  * compat functions.
2510  *
2511  * Callpath:
2512  * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2513  *                                        RegQueryValue32W -> RegQueryValueEx32W
2514  */
2515
2516
2517 /******************************************************************************
2518  * RegQueryValueEx32W [ADVAPI32.158]
2519  * Retrieves type and data for a specified name associated with an open key
2520  *
2521  * PARAMS
2522  *    hkey          [I]   Handle of key to query
2523  *    lpValueName   [I]   Name of value to query
2524  *    lpdwReserved  [I]   Reserved - must be NULL
2525  *    lpdwType      [O]   Address of buffer for value type.  If NULL, the type
2526  *                        is not required.
2527  *    lpbData       [O]   Address of data buffer.  If NULL, the actual data is
2528  *                        not required.
2529  *    lpcbData      [I/O] Address of data buffer size
2530  *
2531  * RETURNS 
2532  *    ERROR_SUCCESS:   Success
2533  *    ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2534  *                     buffer is left untouched. The MS-documentation is wrong (js) !!!
2535  */
2536 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2537                                LPDWORD lpdwReserved, LPDWORD lpdwType,
2538                                LPBYTE lpbData, LPDWORD lpcbData )
2539 {
2540         LPKEYSTRUCT     lpkey;
2541         int             i;
2542         DWORD           ret;
2543
2544         TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2545           lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2546
2547         lpkey = lookup_hkey(hkey);
2548
2549         if (!lpkey)
2550           return ERROR_INVALID_HANDLE;
2551
2552         if ((lpbData && ! lpcbData) || lpdwReserved)
2553           return ERROR_INVALID_PARAMETER;
2554
2555         /* An empty name string is equivalent to NULL */
2556         if (lpValueName && !*lpValueName)
2557           lpValueName = NULL;
2558
2559         if (lpValueName==NULL) 
2560         { /* Use key's unnamed or default value, if any */
2561           for (i=0;i<lpkey->nrofvalues;i++)
2562             if (lpkey->values[i].name==NULL)
2563               break;
2564         } 
2565         else 
2566         { /* Search for the key name */
2567           for (i=0;i<lpkey->nrofvalues;i++)
2568             if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2569               break;
2570         }
2571
2572         if (i==lpkey->nrofvalues) 
2573         { TRACE_(reg)(" Key not found\n");
2574           if (lpValueName==NULL) 
2575           { /* Empty keyname not found */
2576             if (lpbData) 
2577             { *(WCHAR*)lpbData = 0;
2578               *lpcbData = 2;
2579             }
2580             if (lpdwType)
2581               *lpdwType = REG_SZ;
2582             TRACE_(reg)(" Returning an empty string\n");
2583             return ERROR_SUCCESS;
2584           }
2585           return ERROR_FILE_NOT_FOUND;
2586         }
2587
2588         ret = ERROR_SUCCESS;
2589
2590         if (lpdwType)                                   /* type required ?*/
2591           *lpdwType = lpkey->values[i].type;
2592
2593         if (lpbData)                                    /* data required ?*/
2594         { if (*lpcbData >= lpkey->values[i].len)        /* buffer large enought ?*/
2595             memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2596           else {
2597             *lpcbData = lpkey->values[i].len;
2598             ret = ERROR_MORE_DATA;
2599           }
2600         }
2601
2602         if (lpcbData)                                   /* size required ?*/
2603         { *lpcbData = lpkey->values[i].len;
2604         }
2605
2606         debug_print_value ( lpbData, &lpkey->values[i]);
2607
2608         TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2609
2610         return ret;
2611 }
2612
2613
2614 /******************************************************************************
2615  * RegQueryValue32W [ADVAPI32.159]
2616  */
2617 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2618                                LPLONG lpcbData )
2619 {
2620         HKEY    xhkey;
2621         DWORD   ret,lpdwType;
2622
2623     TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2624           lpcbData?*lpcbData:0);
2625
2626     /* Only open subkey, if we really do descend */
2627     if (lpszSubKey && *lpszSubKey) {
2628         ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2629         if (ret != ERROR_SUCCESS) {
2630             WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2631             return ret;
2632         }
2633     } else
2634         xhkey = hkey;
2635
2636     lpdwType = REG_SZ;
2637     ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2638                               lpcbData );
2639     if (xhkey != hkey)
2640         RegCloseKey(xhkey);
2641     return ret;
2642 }
2643
2644
2645 /******************************************************************************
2646  * RegQueryValueEx32A [ADVAPI32.157]
2647  *
2648  * NOTES:
2649  * the documantation is wrong: if the buffer is to small it remains untouched 
2650  *
2651  * FIXME: check returnvalue (len) for an empty key
2652  */
2653 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2654                                LPDWORD lpdwReserved, LPDWORD lpdwType,
2655                                LPBYTE lpbData, LPDWORD lpcbData )
2656 {
2657         LPWSTR  lpszValueNameW;
2658         LPBYTE  mybuf = NULL;
2659         DWORD   ret, mytype, mylen = 0;
2660
2661         TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2662           lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2663
2664         if (!lpcbData && lpbData)                       /* buffer without size is illegal */
2665         {  return ERROR_INVALID_PARAMETER;
2666         }
2667
2668         lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;       
2669         
2670         /* get just the type first */
2671         ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2672         
2673         if ( ret != ERROR_SUCCESS )                     /* failed ?? */
2674         { if(lpszValueNameW) free(lpszValueNameW);
2675           return ret;
2676         }
2677         
2678         if (lpcbData)                                   /* at least length requested? */
2679         { if (UNICONVMASK & (1<<(mytype)))              /* string requested? */
2680           { if (lpbData )                               /* value requested? */
2681             { mylen = 2*( *lpcbData );
2682               mybuf = (LPBYTE)xmalloc( mylen );
2683             }
2684
2685             ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2686
2687             if (ret == ERROR_SUCCESS )
2688             { if ( lpbData )
2689               { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2690               }
2691             }
2692
2693             *lpcbData = mylen/2;                        /* size is in byte! */
2694           }
2695           else                                          /* no strings, call it straight */
2696           { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2697           }
2698         }
2699         
2700         if (lpdwType)                                   /* type when requested */
2701         { *lpdwType = mytype;
2702         }
2703
2704         TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2705         
2706         if(mybuf) free(mybuf);
2707         if(lpszValueNameW) free(lpszValueNameW);
2708         return ret;
2709 }
2710
2711
2712 /******************************************************************************
2713  * RegQueryValueEx16 [KERNEL.225]
2714  */
2715 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2716                                 LPDWORD lpdwReserved, LPDWORD lpdwType,
2717                                 LPBYTE lpbData, LPDWORD lpcbData )
2718 {
2719     TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2720           lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2721     return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2722                                lpbData, lpcbData );
2723 }
2724
2725
2726 /******************************************************************************
2727  * RegQueryValue32A [ADVAPI32.156]
2728  */
2729 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2730                                LPLONG lpcbData )
2731 {
2732     HKEY xhkey;
2733     DWORD ret, dwType;
2734
2735     TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2736           lpcbData?*lpcbData:0);
2737
2738     if (lpszSubKey && *lpszSubKey) {
2739         ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2740         if( ret != ERROR_SUCCESS )
2741             return ret;
2742     } else
2743         xhkey = hkey;
2744
2745     dwType = REG_SZ;
2746     ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2747                               lpcbData );
2748     if( xhkey != hkey )
2749         RegCloseKey( xhkey );
2750     return ret;
2751 }
2752
2753
2754 /******************************************************************************
2755  * RegQueryValue16 [SHELL.6] [KERNEL.224]
2756  *
2757  * NOTES
2758  *    Is this HACK still applicable?
2759  *
2760  * HACK
2761  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2762  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
2763  *    Aldus FH4)
2764  */
2765 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2766                               LPDWORD lpcbData )
2767 {
2768     TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2769           lpcbData?*lpcbData:0);
2770
2771     if (lpcbData)
2772         *lpcbData &= 0xFFFF;
2773     return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2774 }
2775
2776
2777 /*
2778  * Setting values of Registry keys
2779  *
2780  * Callpath:
2781  * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2782  *                                    RegSetValue32W   -> RegSetValueEx32W
2783  */
2784
2785
2786 /******************************************************************************
2787  * RegSetValueEx32W [ADVAPI32.170]
2788  * Sets the data and type of a value under a register key
2789  *
2790  * PARAMS
2791  *    hkey          [I] Handle of key to set value for
2792  *    lpszValueName [I] Name of value to set
2793  *    dwReserved    [I] Reserved - must be zero
2794  *    dwType        [I] Flag for value type
2795  *    lpbData       [I] Address of value data
2796  *    cbData        [I] Size of value data
2797  *
2798  * RETURNS
2799  *    Success: ERROR_SUCCESS
2800  *    Failure: Error code
2801  *
2802  * NOTES
2803  *   win95 does not care about cbData for REG_SZ and finds out the len by itself (js) 
2804  */
2805 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName, 
2806                              DWORD dwReserved, DWORD dwType,
2807                              CONST BYTE *lpbData, DWORD cbData)
2808 {
2809         LPKEYSTRUCT lpkey;
2810         int i;
2811
2812         TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2813           dwReserved, dwType, lpbData, cbData);
2814
2815         lpkey = lookup_hkey( hkey );
2816
2817         if (!lpkey)
2818           return ERROR_INVALID_HANDLE;
2819
2820         lpkey->flags |= REG_OPTION_TAINTED;
2821
2822         if (lpszValueName==NULL) {
2823              /* Sets type and name for key's unnamed or default value */
2824                 for (i=0;i<lpkey->nrofvalues;i++)
2825                         if (lpkey->values[i].name==NULL)
2826                                 break;
2827         } else {
2828                 for (i=0;i<lpkey->nrofvalues;i++)
2829                         if (    lpkey->values[i].name &&
2830                                 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2831                         )
2832                                 break;
2833         }
2834         if (i==lpkey->nrofvalues) {
2835                 lpkey->values = (LPKEYVALUE)xrealloc(
2836                                         lpkey->values,
2837                                         (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2838                                 );
2839                 lpkey->nrofvalues++;
2840                 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2841         }
2842         if (lpkey->values[i].name==NULL) {
2843                 if (lpszValueName)
2844                         lpkey->values[i].name = strdupW(lpszValueName);
2845                 else
2846                         lpkey->values[i].name = NULL;
2847         }
2848
2849         if (dwType == REG_SZ)
2850           cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2851           
2852         lpkey->values[i].len    = cbData;
2853         lpkey->values[i].type   = dwType;
2854         if (lpkey->values[i].data !=NULL)
2855                 free(lpkey->values[i].data);
2856         lpkey->values[i].data   = (LPBYTE)xmalloc(cbData);
2857         lpkey->values[i].lastmodified = time(NULL);
2858         memcpy(lpkey->values[i].data,lpbData,cbData);
2859         return ERROR_SUCCESS;
2860 }
2861
2862
2863 /******************************************************************************
2864  * RegSetValueEx32A [ADVAPI32.169]
2865  *
2866  * NOTES
2867  *   win95 does not care about cbData for REG_SZ and finds out the len by itself (js) 
2868  */
2869 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2870                              DWORD dwReserved, DWORD dwType,
2871                              CONST BYTE *lpbData, DWORD cbData )
2872 {
2873         LPBYTE  buf;
2874         LPWSTR  lpszValueNameW;
2875         DWORD   ret;
2876
2877         if (!lpbData)
2878                 return (ERROR_INVALID_PARAMETER);
2879                 
2880         TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2881           dwReserved,dwType,lpbData,cbData);
2882
2883         if ((1<<dwType) & UNICONVMASK) 
2884         { if (dwType == REG_SZ)
2885             cbData = strlen ((LPCSTR)lpbData)+1;
2886
2887           buf = (LPBYTE)xmalloc( cbData *2 );
2888           lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2889           cbData=2*cbData;
2890         } 
2891         else
2892           buf=(LPBYTE)lpbData;
2893
2894         if (lpszValueName)
2895           lpszValueNameW = strdupA2W(lpszValueName);
2896         else
2897           lpszValueNameW = NULL;
2898
2899         ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2900
2901         if (lpszValueNameW)
2902           free(lpszValueNameW);
2903
2904         if (buf!=lpbData)
2905           free(buf);
2906
2907         return ret;
2908 }
2909
2910
2911 /******************************************************************************
2912  * RegSetValueEx16 [KERNEL.226]
2913  */
2914 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2915                               DWORD dwType, LPBYTE lpbData, DWORD cbData )
2916 {
2917     TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2918           dwReserved,dwType,lpbData,cbData);
2919     return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2920                              cbData );
2921 }
2922
2923
2924 /******************************************************************************
2925  * RegSetValue32W       [ADVAPI32.171]
2926  */
2927 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2928                              LPCWSTR lpszData, DWORD cbData )
2929 {
2930         HKEY    xhkey;
2931         DWORD   ret;
2932
2933         TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2934                 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2935         );
2936         if (lpszSubKey && *lpszSubKey) {
2937                 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2938                 if (ret!=ERROR_SUCCESS)
2939                         return ret;
2940         } else
2941                 xhkey=hkey;
2942         if (dwType!=REG_SZ) {
2943                 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2944                 dwType=REG_SZ;
2945         }
2946         if (cbData!=2*lstrlenW(lpszData)+2) {
2947                 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2948                         cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2949                 );
2950                 cbData=2*lstrlenW(lpszData)+2;
2951         }
2952         ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2953         if (hkey!=xhkey)
2954                 RegCloseKey(xhkey);
2955         return ret;
2956 }
2957
2958
2959 /******************************************************************************
2960  * RegSetValue32A [ADVAPI32.168]
2961  *
2962  */
2963 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2964                              LPCSTR lpszData, DWORD cbData )
2965 {
2966         DWORD   ret;
2967         HKEY    xhkey;
2968
2969         TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2970         if (lpszSubKey && *lpszSubKey) {
2971                 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2972                 if (ret!=ERROR_SUCCESS)
2973                         return ret;
2974         } else
2975                 xhkey=hkey;
2976
2977         if (dwType!=REG_SZ) {
2978                 TRACE_(reg)("dwType=%ld!\n",dwType);
2979                 dwType=REG_SZ;
2980         }
2981         if (cbData!=strlen(lpszData)+1)
2982                 cbData=strlen(lpszData)+1;
2983         ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2984         if (xhkey!=hkey)
2985                 RegCloseKey(xhkey);
2986         return ret;
2987 }
2988
2989
2990 /******************************************************************************
2991  * RegSetValue16 [KERNEL.221] [SHELL.5]
2992  */
2993 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2994                             LPCSTR lpszData, DWORD cbData )
2995 {
2996     TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2997           debugstr_a(lpszData),cbData);
2998     return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2999 }
3000
3001
3002 /* 
3003  * Key Enumeration
3004  *
3005  * Callpath:
3006  * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
3007  *                                  RegEnumKey32W   -> RegEnumKeyEx32W
3008  */
3009
3010
3011 /******************************************************************************
3012  * RegEnumKeyEx32W [ADVAPI32.139]
3013  *
3014  * PARAMS
3015  *    hkey         [I] Handle to key to enumerate
3016  *    iSubKey      [I] Index of subkey to enumerate
3017  *    lpszName     [O] Buffer for subkey name
3018  *    lpcchName    [O] Size of subkey buffer
3019  *    lpdwReserved [I] Reserved
3020  *    lpszClass    [O] Buffer for class string
3021  *    lpcchClass   [O] Size of class buffer
3022  *    ft           [O] Time key last written to
3023  */
3024 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3025                               LPDWORD lpcchName, LPDWORD lpdwReserved,
3026                               LPWSTR lpszClass, LPDWORD lpcchClass, 
3027                               FILETIME *ft )
3028 {
3029     LPKEYSTRUCT lpkey,lpxkey;
3030
3031     TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3032                 lpcchName,lpcchName? *lpcchName : -1,lpdwReserved,lpszClass,
3033                 lpcchClass,ft);
3034
3035     lpkey = lookup_hkey( hkey );
3036     if (!lpkey)
3037         return ERROR_INVALID_HANDLE;
3038
3039     if (!lpcchName)
3040         return ERROR_INVALID_PARAMETER;
3041
3042     if (!lpkey->nextsub)
3043         return ERROR_NO_MORE_ITEMS;
3044     lpxkey=lpkey->nextsub;
3045
3046     /* Traverse the subkeys */
3047     while (iSubkey && lpxkey) {
3048         iSubkey--;
3049         lpxkey=lpxkey->next;
3050     }
3051
3052     if (iSubkey || !lpxkey)
3053         return ERROR_NO_MORE_ITEMS;
3054     if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3055         *lpcchName = lstrlenW(lpxkey->keyname);
3056         return ERROR_MORE_DATA;
3057     }
3058     memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3059     *lpcchName = lstrlenW(lpszName);
3060
3061     if (lpszClass) {
3062         /* FIXME: what should we write into it? */
3063       *lpszClass        = 0;
3064       *lpcchClass       = 2;
3065     }
3066     return ERROR_SUCCESS;
3067 }
3068
3069
3070 /******************************************************************************
3071  * RegEnumKeyW [ADVAPI32.140]
3072  */
3073 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, 
3074                             DWORD lpcchName )
3075 {
3076     DWORD ret;
3077     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3078     ret = RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,NULL);
3079
3080     /* If lpszName is NULL then we have a slightly different behaviour than
3081        RegEnumKeyExW */
3082     if(lpszName == NULL && ret == ERROR_MORE_DATA)
3083         ret = ERROR_SUCCESS;
3084
3085     return ret;
3086 }
3087
3088
3089 /******************************************************************************
3090  * RegEnumKeyEx32A [ADVAPI32.138]
3091  */
3092 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3093                               LPDWORD lpcchName, LPDWORD lpdwReserved, 
3094                               LPSTR lpszClass, LPDWORD lpcchClass, 
3095                               FILETIME *ft )
3096 {
3097     DWORD       ret;
3098     LPWSTR      lpszNameW, lpszClassW;
3099
3100     TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",
3101                 hkey,iSubkey,lpszName,lpcchName,lpcchName? *lpcchName : -1,
3102                 lpdwReserved,lpszClass,lpcchClass,ft);
3103
3104     lpszNameW = lpszName ? (LPWSTR)xmalloc(*lpcchName * 2) : NULL;
3105     lpszClassW = lpszClass ? (LPWSTR)xmalloc(*lpcchClass * 2) : NULL;
3106
3107     ret = RegEnumKeyExW(hkey, iSubkey, lpszNameW, lpcchName, lpdwReserved,
3108                         lpszClassW, lpcchClass, ft);
3109
3110     if (ret == ERROR_SUCCESS) {
3111         lstrcpyWtoA(lpszName,lpszNameW);
3112         if (lpszClassW)
3113             lstrcpyWtoA(lpszClass,lpszClassW);
3114     }
3115     if (lpszNameW)
3116         free(lpszNameW);
3117     if (lpszClassW)
3118         free(lpszClassW);
3119     return ret;
3120 }
3121
3122
3123 /******************************************************************************
3124  * RegEnumKeyA [ADVAPI32.137]
3125  */
3126 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3127                             DWORD lpcchName )
3128 {
3129     DWORD ret;
3130     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3131     ret = RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL, 
3132                          NULL, NULL );
3133
3134     /* If lpszName is NULL then we have a slightly different behaviour than
3135        RegEnumKeyExA */
3136     if(lpszName == NULL && ret == ERROR_MORE_DATA)
3137         ret = ERROR_SUCCESS;
3138
3139     return ret;
3140 }
3141
3142
3143 /******************************************************************************
3144  * RegEnumKey16 [SHELL.7] [KERNEL.216]
3145  */
3146 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3147                            DWORD lpcchName )
3148 {
3149     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3150     return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3151 }
3152
3153
3154 /* 
3155  * Enumerate Registry Values
3156  *
3157  * Callpath:
3158  * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3159  */
3160
3161
3162 /******************************************************************************
3163  * RegEnumValue32W [ADVAPI32.142]
3164  *
3165  * PARAMS
3166  *    hkey        [I] Handle to key to query
3167  *    iValue      [I] Index of value to query
3168  *    lpszValue   [O] Value string
3169  *    lpcchValue  [I/O] Size of value buffer (in wchars)
3170  *    lpdReserved [I] Reserved
3171  *    lpdwType    [O] Type code
3172  *    lpbData     [O] Value data
3173  *    lpcbData    [I/O] Size of data buffer (in bytes)
3174  *
3175  * Note:  wide character functions that take and/or return "character counts"
3176  *  use TCHAR (that is unsigned short or char) not byte counts.
3177  */
3178 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3179                               LPDWORD lpcchValue, LPDWORD lpdReserved,
3180                               LPDWORD lpdwType, LPBYTE lpbData, 
3181                               LPDWORD lpcbData )
3182 {
3183         LPKEYSTRUCT     lpkey;
3184         LPKEYVALUE      val;
3185
3186         TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3187           lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3188
3189         lpkey = lookup_hkey( hkey );
3190         
3191         if (!lpcbData && lpbData)
3192                 return ERROR_INVALID_PARAMETER;
3193                 
3194         if (!lpkey)
3195                 return ERROR_INVALID_HANDLE;
3196
3197         if (lpkey->nrofvalues <= iValue)
3198                 return ERROR_NO_MORE_ITEMS;
3199
3200         val = &(lpkey->values[iValue]);
3201
3202         if (val->name) {
3203                 if (lstrlenW(val->name)+1>*lpcchValue) {
3204                         *lpcchValue = lstrlenW(val->name)+1;
3205                         return ERROR_MORE_DATA;
3206                 }
3207                 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3208                 *lpcchValue=lstrlenW(val->name);
3209         } else {
3210                 *lpszValue      = 0;
3211                 *lpcchValue     = 0;
3212         }
3213
3214         /* Can be NULL if the type code is not required */
3215         if (lpdwType)
3216                 *lpdwType = val->type;
3217
3218         if (lpbData) {
3219                 if (val->len>*lpcbData) {
3220                         *lpcbData = val->len;
3221                         return ERROR_MORE_DATA;
3222                 }
3223                 memcpy(lpbData,val->data,val->len);
3224                 *lpcbData = val->len;
3225         }
3226
3227         debug_print_value ( val->data, val );
3228         return ERROR_SUCCESS;
3229 }
3230
3231
3232 /******************************************************************************
3233  * RegEnumValue32A [ADVAPI32.141]
3234  */
3235 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3236                               LPDWORD lpcchValue, LPDWORD lpdReserved,
3237                               LPDWORD lpdwType, LPBYTE lpbData, 
3238                               LPDWORD lpcbData )
3239 {
3240         LPWSTR  lpszValueW;
3241         LPBYTE  lpbDataW;
3242         DWORD   ret,lpcbDataW;
3243         DWORD dwType;
3244
3245         TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3246                 lpdReserved,lpdwType,lpbData,lpcbData);
3247
3248         lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3249         if (lpbData) {
3250                 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3251                 lpcbDataW = *lpcbData;
3252         } else
3253                 lpbDataW = NULL;
3254
3255         ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue, 
3256                                 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3257
3258         if (lpdwType)
3259                 *lpdwType = dwType;
3260
3261         if (ret==ERROR_SUCCESS) {
3262                 lstrcpyWtoA(lpszValue,lpszValueW);
3263                 if (lpbData) {
3264                         if ((1<<dwType) & UNICONVMASK) {
3265                                 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3266                         } else {
3267                                 if (lpcbDataW > *lpcbData) {
3268                                         *lpcbData = lpcbDataW;
3269                                         ret     = ERROR_MORE_DATA;
3270                                 } else
3271                                         memcpy(lpbData,lpbDataW,lpcbDataW);
3272                         }
3273                         *lpcbData = lpcbDataW;
3274                 }
3275         }
3276     if (lpbDataW) free(lpbDataW);
3277     if (lpszValueW) free(lpszValueW);
3278     return ret;
3279 }
3280
3281
3282 /******************************************************************************
3283  * RegEnumValue16 [KERNEL.223]
3284  */
3285 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue, 
3286                              LPDWORD lpcchValue, LPDWORD lpdReserved, 
3287                              LPDWORD lpdwType, LPBYTE lpbData, 
3288                              LPDWORD lpcbData )
3289 {
3290     TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3291           lpdReserved,lpdwType,lpbData,lpcbData);
3292     return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved, 
3293                             lpdwType, lpbData, lpcbData );
3294 }
3295
3296
3297 /******************************************************************************
3298  * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3299  * Releases the handle of the specified key
3300  *
3301  * PARAMS
3302  *    hkey [I] Handle of key to close
3303  *
3304  * RETURNS
3305  *    Success: ERROR_SUCCESS
3306  *    Failure: Error code
3307  */
3308 DWORD WINAPI RegCloseKey( HKEY hkey )
3309 {
3310     TRACE_(reg)("(%x)\n",hkey);
3311
3312     /* The standard handles are allowed to succeed, even though they are not
3313        closed */
3314     if (is_standard_hkey(hkey))
3315         return ERROR_SUCCESS;
3316
3317     return remove_handle(hkey);
3318 }
3319
3320
3321 /* 
3322  * Delete registry key
3323  *
3324  * Callpath:
3325  * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3326  */
3327
3328
3329 /******************************************************************************
3330  * RegDeleteKey32W [ADVAPI32.134]
3331  *
3332  * PARAMS
3333  *    hkey       [I] Handle to open key
3334  *    lpszSubKey [I] Name of subkey to delete
3335  *
3336  * RETURNS
3337  *    Success: ERROR_SUCCESS
3338  *    Failure: Error code
3339  */
3340 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3341 {
3342         LPKEYSTRUCT     *lplpPrevKey,lpNextKey,lpxkey;
3343         LPWSTR          *wps;
3344         int             wpc,i;
3345
3346     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3347
3348     lpNextKey = lookup_hkey(hkey);
3349     if (!lpNextKey)
3350         return ERROR_INVALID_HANDLE;
3351
3352     /* Subkey param cannot be NULL */
3353     if (!lpszSubKey || !*lpszSubKey)
3354         return ERROR_BADKEY;
3355
3356     /* We need to know the previous key in the hier. */
3357         split_keypath(lpszSubKey,&wps,&wpc);
3358         i       = 0;
3359         lpxkey  = lpNextKey;
3360         while (i<wpc-1) {
3361                 lpxkey=lpNextKey->nextsub;
3362                 while (lpxkey) {
3363                         TRACE_(reg)("  Scanning [%s]\n",
3364                                      debugstr_w(lpxkey->keyname));
3365                         if (!lstrcmpiW(wps[i],lpxkey->keyname))
3366                                 break;
3367                         lpxkey=lpxkey->next;
3368                 }
3369                 if (!lpxkey) {
3370                         FREE_KEY_PATH;
3371                         TRACE_(reg)("  Not found.\n");
3372                         /* not found is success */
3373                         return ERROR_SUCCESS;
3374                 }
3375                 i++;
3376                 lpNextKey       = lpxkey;
3377         }
3378         lpxkey  = lpNextKey->nextsub;
3379         lplpPrevKey = &(lpNextKey->nextsub);
3380         while (lpxkey) {
3381                 TRACE_(reg)("  Scanning [%s]\n",
3382                              debugstr_w(lpxkey->keyname));
3383                 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3384                         break;
3385                 lplpPrevKey     = &(lpxkey->next);
3386                 lpxkey          = lpxkey->next;
3387         }
3388
3389         if (!lpxkey) {
3390                 FREE_KEY_PATH;
3391                 WARN_(reg)("  Not found.\n");
3392                 return ERROR_FILE_NOT_FOUND;
3393         }
3394
3395         if (lpxkey->nextsub) {
3396                 FREE_KEY_PATH;
3397                 WARN_(reg)("  Not empty.\n");
3398                 return ERROR_CANTWRITE;
3399         }
3400         *lplpPrevKey    = lpxkey->next;
3401         free(lpxkey->keyname);
3402         if (lpxkey->class)
3403                 free(lpxkey->class);
3404         if (lpxkey->values)
3405                 free(lpxkey->values);
3406         free(lpxkey);
3407         FREE_KEY_PATH;
3408         TRACE_(reg)("  Done.\n");
3409         return  ERROR_SUCCESS;
3410 }
3411
3412
3413 /******************************************************************************
3414  * RegDeleteKey32A [ADVAPI32.133]
3415  */
3416 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3417 {
3418     LPWSTR lpszSubKeyW;
3419     DWORD  ret;
3420
3421     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3422     lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3423     ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3424     if(lpszSubKeyW) free(lpszSubKeyW);
3425     return ret;
3426 }
3427
3428
3429 /******************************************************************************
3430  * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3431  */
3432 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3433 {
3434     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3435     return RegDeleteKeyA( hkey, lpszSubKey );
3436 }
3437
3438
3439 /* 
3440  * Delete registry value
3441  *
3442  * Callpath:
3443  * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3444  */
3445
3446
3447 /******************************************************************************
3448  * RegDeleteValue32W [ADVAPI32.136]
3449  *
3450  * PARAMS
3451  *    hkey      [I]
3452  *    lpszValue [I]
3453  *
3454  * RETURNS
3455  */
3456 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3457 {
3458         DWORD           i;
3459         LPKEYSTRUCT     lpkey;
3460         LPKEYVALUE      val;
3461
3462     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3463
3464     lpkey = lookup_hkey( hkey );
3465     if (!lpkey)
3466         return ERROR_INVALID_HANDLE;
3467
3468         if (lpszValue) {
3469                 for (i=0;i<lpkey->nrofvalues;i++)
3470                         if (    lpkey->values[i].name &&
3471                                 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3472                         )
3473                                 break;
3474         } else {
3475                 for (i=0;i<lpkey->nrofvalues;i++)
3476                         if (lpkey->values[i].name==NULL)
3477                                 break;
3478         }
3479
3480     if (i == lpkey->nrofvalues)
3481         return ERROR_FILE_NOT_FOUND;
3482
3483         val     = lpkey->values+i;
3484         if (val->name) free(val->name);
3485         if (val->data) free(val->data);
3486         memcpy( 
3487                 lpkey->values+i,
3488                 lpkey->values+i+1,
3489                 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3490         );
3491         lpkey->values   = (LPKEYVALUE)xrealloc(
3492                                 lpkey->values,
3493                                 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3494                         );
3495         lpkey->nrofvalues--;
3496         return ERROR_SUCCESS;
3497 }
3498
3499
3500 /******************************************************************************
3501  * RegDeleteValue32A [ADVAPI32.135]
3502  */
3503 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3504 {
3505     LPWSTR lpszValueW;
3506     DWORD  ret;
3507
3508     TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3509     lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3510     ret = RegDeleteValueW( hkey, lpszValueW );
3511     if(lpszValueW) free(lpszValueW);
3512     return ret;
3513 }
3514
3515
3516 /******************************************************************************
3517  * RegDeleteValue16 [KERNEL.222]
3518  */
3519 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3520 {
3521     TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3522     return RegDeleteValueA( hkey, lpszValue );
3523 }
3524
3525
3526 /******************************************************************************
3527  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3528  * Immediately writes key to registry.
3529  * Only returns after data has been written to disk.
3530  *
3531  * FIXME: does it really wait until data is written ?
3532  *
3533  * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3534  * written if this function really works (and only if !).
3535  *
3536  * PARAMS
3537  *    hkey [I] Handle of key to write
3538  *
3539  * RETURNS
3540  *    Success: ERROR_SUCCESS
3541  *    Failure: Error code
3542  */
3543 DWORD WINAPI RegFlushKey( HKEY hkey )
3544 {
3545     LPKEYSTRUCT lpkey;
3546
3547     TRACE_(reg)("(%x)\n", hkey);
3548
3549     lpkey = lookup_hkey( hkey );
3550     if (!lpkey)
3551         return ERROR_BADKEY;
3552
3553         SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3554         return ERROR_SUCCESS;
3555 }
3556
3557
3558 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3559
3560
3561 /******************************************************************************
3562  * RegQueryInfoKey32W [ADVAPI32.153]
3563  *
3564  * PARAMS
3565  *    hkey                   [I] Handle to key to query
3566  *    lpszClass              [O] Buffer for class string
3567  *    lpcchClass             [O] Size of class string buffer
3568  *    lpdwReserved           [I] Reserved
3569  *    lpcSubKeys             [I] Buffer for number of subkeys
3570  *    lpcchMaxSubKey         [O] Buffer for longest subkey name length
3571  *    lpcchMaxClass          [O] Buffer for longest class string length
3572  *    lpcValues              [O] Buffer for number of value entries
3573  *    lpcchMaxValueName      [O] Buffer for longest value name length
3574  *    lpccbMaxValueData      [O] Buffer for longest value data length
3575  *    lpcbSecurityDescriptor [O] Buffer for security descriptor length
3576  *    ft
3577  * - win95 allows lpszClass to be valid and lpcchClass to be NULL 
3578  * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3579  *   lpcchClass is NULL
3580  * - both allow lpszClass to be NULL and lpcchClass to be NULL 
3581  * (it's hard to test validity, so test !NULL instead)
3582  */
3583 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass, 
3584                                  LPDWORD lpcchClass, LPDWORD lpdwReserved,
3585                                  LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3586                                  LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3587                                  LPDWORD lpcchMaxValueName, 
3588                                  LPDWORD lpccbMaxValueData, 
3589                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3590 {
3591         LPKEYSTRUCT     lpkey,lpxkey;
3592         int             nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3593         int             i;
3594
3595         TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3596                 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3597                 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3598                 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3599         );
3600         lpkey = lookup_hkey(hkey);
3601         if (!lpkey)
3602                 return ERROR_INVALID_HANDLE;
3603         if (lpszClass) {
3604                 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3605                     return ERROR_INVALID_PARAMETER;
3606                 }
3607                 /* either lpcchClass is valid or this is win95 and lpcchClass
3608                    could be invalid */
3609                 if (lpkey->class) {
3610                         DWORD classLen = lstrlenW(lpkey->class);
3611
3612                         if (lpcchClass && classLen+1>*lpcchClass) {
3613                                 *lpcchClass=classLen+1;
3614                                 return ERROR_MORE_DATA;
3615                         }
3616                         if (lpcchClass)
3617                             *lpcchClass=classLen;
3618                         memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3619                 } else {
3620                         *lpszClass      = 0;
3621                         if (lpcchClass)
3622                             *lpcchClass = 0;
3623                 }
3624         } else {
3625                 if (lpcchClass)
3626                         *lpcchClass     = lstrlenW(lpkey->class);
3627         }
3628         lpxkey=lpkey->nextsub;
3629         nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3630         while (lpxkey) {
3631                 nrofkeys++;
3632                 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3633                         maxsubkey=lstrlenW(lpxkey->keyname);
3634                 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3635                         maxclass=lstrlenW(lpxkey->class);
3636                 lpxkey=lpxkey->next;
3637         }
3638         for (i=0;i<lpkey->nrofvalues;i++) {
3639                 LPKEYVALUE      val=lpkey->values+i;
3640
3641                 if (val->name && lstrlenW(val->name)>maxvname)
3642                         maxvname=lstrlenW(val->name);
3643                 if (val->len>maxvdata)
3644                         maxvdata=val->len;
3645         }
3646         if (!maxclass) maxclass = 1;
3647         if (!maxvname) maxvname = 1;
3648         if (lpcValues)
3649                 *lpcValues      = lpkey->nrofvalues;
3650         if (lpcSubKeys)
3651                 *lpcSubKeys     = nrofkeys;
3652         if (lpcchMaxSubkey)
3653                 *lpcchMaxSubkey = maxsubkey;
3654         if (lpcchMaxClass)
3655                 *lpcchMaxClass  = maxclass;
3656         if (lpcchMaxValueName)
3657                 *lpcchMaxValueName= maxvname;
3658         if (lpccbMaxValueData)
3659                 *lpccbMaxValueData= maxvdata;
3660         return ERROR_SUCCESS;
3661 }
3662
3663
3664 /******************************************************************************
3665  * RegQueryInfoKey32A [ADVAPI32.152]
3666  */
3667 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3668                                  LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3669                                  LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3670                                  LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3671                                  LPDWORD lpccbMaxValueData, 
3672                                  LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3673 {
3674         LPWSTR          lpszClassW = NULL;
3675         DWORD           ret;
3676
3677         TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3678                 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3679                 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3680                 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3681         );
3682         if (lpszClass) {
3683                 if (lpcchClass) {
3684                     lpszClassW  = (LPWSTR)xmalloc((*lpcchClass) * 2);
3685                 } else if (VERSION_GetVersion() == WIN95) {
3686                     /* win95  allows lpcchClass to be null */
3687                     /* we don't know how big lpszClass is, would 
3688                        MAX_PATHNAME_LEN be the correct default? */
3689                     lpszClassW  = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2); 
3690                 }
3691
3692         } else
3693                 lpszClassW  = NULL;
3694         ret=RegQueryInfoKeyW(
3695                 hkey,
3696                 lpszClassW,
3697                 lpcchClass,
3698                 lpdwReserved,
3699                 lpcSubKeys,
3700                 lpcchMaxSubkey,
3701                 lpcchMaxClass,
3702                 lpcValues,
3703                 lpcchMaxValueName,
3704                 lpccbMaxValueData,
3705                 lpcbSecurityDescriptor,
3706                 ft
3707         );
3708         if (ret==ERROR_SUCCESS && lpszClass)
3709                 lstrcpyWtoA(lpszClass,lpszClassW);
3710         if (lpszClassW)
3711                 free(lpszClassW);
3712         return ret;
3713 }
3714
3715
3716 /******************************************************************************
3717  * RegConnectRegistry32W [ADVAPI32.128]
3718  *
3719  * PARAMS
3720  *    lpMachineName [I] Address of name of remote computer
3721  *    hHey          [I] Predefined registry handle
3722  *    phkResult     [I] Address of buffer for remote registry handle
3723  */
3724 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
3725                                    LPHKEY phkResult )
3726 {
3727     TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3728
3729     if (!lpMachineName || !*lpMachineName) {
3730         /* Use the local machine name */
3731         return RegOpenKey16( hKey, "", phkResult );
3732     }
3733
3734     FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3735     return ERROR_BAD_NETPATH;
3736 }
3737
3738
3739 /******************************************************************************
3740  * RegConnectRegistry32A [ADVAPI32.127]
3741  */
3742 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3743 {
3744     DWORD ret;
3745     LPWSTR machineW = strdupA2W(machine);
3746     ret = RegConnectRegistryW( machineW, hkey, reskey );
3747     free(machineW);
3748     return ret;
3749 }
3750
3751
3752 /******************************************************************************
3753  * RegGetKeySecurity [ADVAPI32.144]
3754  * Retrieves a copy of security descriptor protecting the registry key
3755  *
3756  * PARAMS
3757  *    hkey                   [I]   Open handle of key to set
3758  *    SecurityInformation    [I]   Descriptor contents
3759  *    pSecurityDescriptor    [O]   Address of descriptor for key
3760  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3761  *
3762  * RETURNS
3763  *    Success: ERROR_SUCCESS
3764  *    Failure: Error code
3765  */
3766 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
3767                                SECURITY_INFORMATION SecurityInformation,
3768                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
3769                                LPDWORD lpcbSecurityDescriptor )
3770 {
3771     LPKEYSTRUCT lpkey;
3772
3773     TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3774           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3775
3776     lpkey = lookup_hkey( hkey );
3777     if (!lpkey)
3778         return ERROR_INVALID_HANDLE;
3779
3780     /* FIXME: Check for valid SecurityInformation values */
3781
3782     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3783         return ERROR_INSUFFICIENT_BUFFER;
3784
3785     FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3786           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3787
3788     return ERROR_SUCCESS;
3789 }
3790
3791
3792 /******************************************************************************
3793  * RegLoadKey32W [ADVAPI32.???]
3794  *
3795  * PARAMS
3796  *    hkey       [I] Handle of open key
3797  *    lpszSubKey [I] Address of name of subkey
3798  *    lpszFile   [I] Address of filename for registry information
3799  */
3800 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3801 {
3802     LPKEYSTRUCT lpkey;
3803     TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3804
3805     /* Do this check before the hkey check */
3806     if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3807         return ERROR_INVALID_PARAMETER;
3808
3809     lpkey = lookup_hkey( hkey );
3810     if (!lpkey)
3811         return ERROR_INVALID_HANDLE;
3812
3813     FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3814           debugstr_w(lpszFile));
3815
3816     return ERROR_SUCCESS;
3817 }
3818
3819
3820 /******************************************************************************
3821  * RegLoadKey32A [ADVAPI32.???]
3822  */
3823 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3824 {
3825     LONG ret;
3826     LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3827     LPWSTR lpszFileW = strdupA2W(lpszFile);
3828     ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3829     if(lpszFileW) free(lpszFileW);
3830     if(lpszSubKeyW) free(lpszSubKeyW);
3831     return ret;
3832 }
3833
3834
3835 /******************************************************************************
3836  * RegNotifyChangeKeyValue [ADVAPI32.???]
3837  *
3838  * PARAMS
3839  *    hkey            [I] Handle of key to watch
3840  *    fWatchSubTree   [I] Flag for subkey notification
3841  *    fdwNotifyFilter [I] Changes to be reported
3842  *    hEvent          [I] Handle of signaled event
3843  *    fAsync          [I] Flag for asynchronous reporting
3844  */
3845 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
3846                                      DWORD fdwNotifyFilter, HANDLE hEvent,
3847                                      BOOL fAsync )
3848 {
3849     LPKEYSTRUCT lpkey;
3850     TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3851           hEvent,fAsync);
3852
3853     lpkey = lookup_hkey( hkey );
3854     if (!lpkey)
3855         return ERROR_INVALID_HANDLE;
3856
3857     FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3858           hEvent,fAsync);
3859
3860     return ERROR_SUCCESS;
3861 }
3862
3863
3864 /******************************************************************************
3865  * RegUnLoadKey32W [ADVAPI32.173]
3866  *
3867  * PARAMS
3868  *    hkey     [I] Handle of open key
3869  *    lpSubKey [I] Address of name of subkey to unload
3870  */
3871 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3872 {
3873     FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3874     return ERROR_SUCCESS;
3875 }
3876
3877
3878 /******************************************************************************
3879  * RegUnLoadKey32A [ADVAPI32.172]
3880  */
3881 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3882 {
3883     LONG ret;
3884     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3885     ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3886     if(lpSubKeyW) free(lpSubKeyW);
3887     return ret;
3888 }
3889
3890
3891 /******************************************************************************
3892  * RegSetKeySecurity [ADVAPI32.167]
3893  *
3894  * PARAMS
3895  *    hkey          [I] Open handle of key to set
3896  *    SecurityInfo  [I] Descriptor contents
3897  *    pSecurityDesc [I] Address of descriptor for key
3898  */
3899 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3900                                PSECURITY_DESCRIPTOR pSecurityDesc )
3901 {
3902     LPKEYSTRUCT lpkey;
3903
3904     TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3905
3906     /* It seems to perform this check before the hkey check */
3907     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3908         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3909         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3910         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3911         /* Param OK */
3912     } else
3913         return ERROR_INVALID_PARAMETER;
3914
3915     if (!pSecurityDesc)
3916         return ERROR_INVALID_PARAMETER;
3917
3918     lpkey = lookup_hkey( hkey );
3919     if (!lpkey)
3920         return ERROR_INVALID_HANDLE;
3921
3922     FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3923
3924     return ERROR_SUCCESS;
3925 }
3926
3927
3928 /******************************************************************************
3929  * RegSaveKey32W [ADVAPI32.166]
3930  *
3931  * PARAMS
3932  *    hkey   [I] Handle of key where save begins
3933  *    lpFile [I] Address of filename to save to
3934  *    sa     [I] Address of security structure
3935  */
3936 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile, 
3937                            LPSECURITY_ATTRIBUTES sa )
3938 {
3939     LPKEYSTRUCT lpkey;
3940
3941     TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3942
3943     /* It appears to do this check before the hkey check */
3944     if (!lpFile || !*lpFile)
3945         return ERROR_INVALID_PARAMETER;
3946
3947     lpkey = lookup_hkey( hkey );
3948     if (!lpkey)
3949         return ERROR_INVALID_HANDLE;
3950
3951     FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3952
3953     return ERROR_SUCCESS;
3954 }
3955
3956
3957 /******************************************************************************
3958  * RegSaveKey32A [ADVAPI32.165]
3959  */
3960 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile, 
3961                            LPSECURITY_ATTRIBUTES sa )
3962 {
3963     LONG ret;
3964     LPWSTR lpFileW = strdupA2W(lpFile);
3965     ret = RegSaveKeyW( hkey, lpFileW, sa );
3966     free(lpFileW);
3967     return ret;
3968 }
3969
3970
3971 /******************************************************************************
3972  * RegRestoreKey32W [ADVAPI32.164]
3973  *
3974  * PARAMS
3975  *    hkey    [I] Handle of key where restore begins
3976  *    lpFile  [I] Address of filename containing saved tree
3977  *    dwFlags [I] Optional flags
3978  */
3979 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3980 {
3981     LPKEYSTRUCT lpkey;
3982
3983     TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3984
3985     /* It seems to do this check before the hkey check */
3986     if (!lpFile || !*lpFile)
3987         return ERROR_INVALID_PARAMETER;
3988
3989     lpkey = lookup_hkey( hkey );
3990     if (!lpkey)
3991         return ERROR_INVALID_HANDLE;
3992
3993     FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3994
3995     /* Check for file existence */
3996
3997     return ERROR_SUCCESS;
3998 }
3999
4000
4001 /******************************************************************************
4002  * RegRestoreKey32A [ADVAPI32.163]
4003  */
4004 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4005 {
4006     LONG ret;
4007     LPWSTR lpFileW = strdupA2W(lpFile);
4008     ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4009     if(lpFileW) free(lpFileW);
4010     return ret;
4011 }
4012
4013
4014 /******************************************************************************
4015  * RegReplaceKey32W [ADVAPI32.162]
4016  *
4017  * PARAMS
4018  *    hkey      [I] Handle of open key
4019  *    lpSubKey  [I] Address of name of subkey
4020  *    lpNewFile [I] Address of filename for file with new data
4021  *    lpOldFile [I] Address of filename for backup file
4022  */
4023 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4024                               LPCWSTR lpOldFile )
4025 {
4026     LPKEYSTRUCT lpkey;
4027
4028     TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4029           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4030
4031     lpkey = lookup_hkey( hkey );
4032     if (!lpkey)
4033         return ERROR_INVALID_HANDLE;
4034
4035     FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
4036           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4037
4038     return ERROR_SUCCESS;
4039 }
4040
4041
4042 /******************************************************************************
4043  * RegReplaceKey32A [ADVAPI32.161]
4044  */
4045 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4046                               LPCSTR lpOldFile )
4047 {
4048     LONG ret;
4049     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4050     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4051     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4052     ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4053     free(lpOldFileW);
4054     free(lpNewFileW);
4055     free(lpSubKeyW);
4056     return ret;
4057 }
4058