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