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