Start to separate KERNEL out of libwine.
[wine] / misc / registry.c
1 /*
2  *      Registry Functions
3  *
4  * Copyright 1996 Marcus Meissner
5  * Copyright 1998 Matthew Becker
6  * Copyright 1999 Sylvain St-Germain
7  *
8  * December 21, 1997 - Kevin Cozens
9  * Fixed bugs in the _w95_loadreg() function. Added extra information
10  * regarding the format of the Windows '95 registry files.
11  *
12  * NOTES
13  *    When changing this file, please re-run the regtest program to ensure
14  *    the conditions are handled properly.
15  *
16  * TODO
17  *    Security access
18  *    Option handling
19  *    Time for RegEnumKey*, RegQueryInfoKey*
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
33 #endif
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/fcntl.h>
37 #include <sys/stat.h>
38 #include <time.h>
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wine/winbase16.h"
42 #include "wine/winestring.h"
43 #include "winerror.h"
44 #include "file.h"
45 #include "heap.h"
46 #include "debugtools.h"
47 #include "options.h"
48 #include "winreg.h"
49 #include "server.h"
50 #include "services.h"
51
52 DEFAULT_DEBUG_CHANNEL(reg);
53
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
56
57 #define SAVE_USERS_DEFAULT          ETCDIR"/wine.userreg"
58 #define SAVE_LOCAL_MACHINE_DEFAULT  ETCDIR"/wine.systemreg"
59
60 /* relative in ~user/.wine/ : */
61 #define SAVE_CURRENT_USER           "user.reg"
62 #define SAVE_DEFAULT_USER           "userdef.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT    "wine.userreg"
64 #define SAVE_LOCAL_MACHINE          "system.reg"
65
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK     ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
68
69
70 static void *xmalloc( size_t size )
71 {
72     void *res;
73  
74     res = malloc (size ? size : 1);
75     if (res == NULL) {
76         WARN("Virtual memory exhausted.\n");
77         exit (1);
78     }
79     return res;
80 }                                                                              
81
82 /*
83  * QUESTION
84  *   Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
85  *   If so, can we remove them?
86  * ANSWER
87  *   No, the memory handling functions are called very often in here, 
88  *   just replacing them by HeapAlloc(SystemHeap,...) makes registry
89  *   loading 100 times slower. -MM
90  */
91 static LPWSTR strdupA2W(LPCSTR src)
92 {
93     if(src) {
94         LPWSTR dest=xmalloc(2*strlen(src)+2);
95         lstrcpyAtoW(dest,src);
96         return dest;
97     }
98     return NULL;
99 }
100
101 LPWSTR strcvtA2W(LPCSTR src, int nchars)
102
103 {
104    LPWSTR dest = xmalloc (2 * nchars + 2);
105
106    lstrcpynAtoW(dest,src,nchars+1);
107    return dest;
108 }
109
110
111
112 /******************************************************************************
113  * REGISTRY_Init [Internal]
114  * Registry initialisation, allocates some default keys. 
115  */
116 static void REGISTRY_Init(void) {
117         HKEY    hkey;
118         char    buf[200];
119
120         TRACE("(void)\n");
121
122         RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
123         RegCloseKey(hkey);
124
125         /* This was an Open, but since it is called before the real registries
126            are loaded, it was changed to a Create - MTB 980507*/
127         RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
128         RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
129         RegCloseKey(hkey);
130
131         /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
132          *                                              CurrentVersion
133          *                                              CurrentBuildNumber
134          *                                              CurrentType
135          *                                      string  RegisteredOwner
136          *                                      string  RegisteredOrganization
137          *
138          */
139         /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
140          *                                      string  SysContact
141          *                                      string  SysLocation
142          *                                              SysServices
143          */
144         if (-1!=gethostname(buf,200)) {
145                 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
146                 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
147                 RegCloseKey(hkey);
148         }
149 }
150
151
152 /************************ LOAD Registry Function ****************************/
153
154
155
156 /******************************************************************************
157  * _find_or_add_key [Internal]
158  */
159 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
160 {
161     HKEY subkey;
162     if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
163     if (keyname) free( keyname );
164     return subkey;
165 }
166
167 /******************************************************************************
168  * _find_or_add_value [Internal]
169  */
170 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
171 {
172     RegSetValueExW( hkey, name, 0, type, data, len );
173     if (name) free( name );
174     if (data) free( data );
175 }
176
177
178 /******************************************************************************
179  * _wine_read_line [Internal]
180  *
181  * reads a line including dynamically enlarging the readbuffer and throwing
182  * away comments
183  */
184 static int _wine_read_line( FILE *F, char **buf, int *len )
185 {
186         char    *s,*curread;
187         int     mylen,curoff;
188
189         curread = *buf;
190         mylen   = *len;
191         **buf   = '\0';
192         while (1) {
193                 while (1) {
194                         s=fgets(curread,mylen,F);
195                         if (s==NULL)
196                                 return 0; /* EOF */
197                         if (NULL==(s=strchr(curread,'\n'))) {
198                                 /* buffer wasn't large enough */
199                                 curoff  = strlen(*buf);
200                                 curread = realloc(*buf,*len*2);
201                                 if(curread == NULL) {
202                                     WARN("Out of memory");
203                                     return 0;
204                                 }
205                                 *buf    = curread;
206                                 curread+= curoff;
207                                 mylen   = *len; /* we filled up the buffer and 
208                                                  * got new '*len' bytes to fill
209                                                  */
210                                 *len    = *len * 2;
211                         } else {
212                                 *s='\0';
213                                 break;
214                         }
215                 }
216                 /* throw away comments */
217                 if (**buf=='#' || **buf==';') {
218                         curread = *buf;
219                         mylen   = *len;
220                         continue;
221                 }
222                 if (s)  /* got end of line */
223                         break;
224         }
225         return 1;
226 }
227
228
229 /******************************************************************************
230  * _wine_read_USTRING [Internal]
231  *
232  * converts a char* into a UNICODE string (up to a special char)
233  * and returns the position exactly after that string
234  */
235 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
236 {
237         char    *s;
238         LPWSTR  ws;
239
240         /* read up to "=" or "\0" or "\n" */
241         s       = buf;
242         *str    = (LPWSTR)xmalloc(2*strlen(buf)+2);
243         ws      = *str;
244         while (*s && (*s!='\n') && (*s!='=')) {
245                 if (*s!='\\')
246                         *ws++=*((unsigned char*)s++);
247                 else {
248                         s++;
249                         if (!*s) {
250                                 /* Dangling \ ... may only happen if a registry
251                                  * write was short. FIXME: What to do?
252                                  */
253                                  break;
254                         }
255                         if (*s=='\\') {
256                                 *ws++='\\';
257                                 s++;
258                                 continue;
259                         }
260                         if (*s!='u') {
261                                 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
262                                 *ws++='\\';
263                                 *ws++=*s++;
264                         } else {
265                                 char    xbuf[5];
266                                 int     wc;
267
268                                 s++;
269                                 memcpy(xbuf,s,4);xbuf[4]='\0';
270                                 if (!sscanf(xbuf,"%x",&wc))
271                                         WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
272                                 s+=4;
273                                 *ws++   =(unsigned short)wc;
274                         }
275                 }
276         }
277         *ws     = 0;
278         return s;
279 }
280
281
282 /******************************************************************************
283  * _wine_loadsubkey [Internal]
284  *
285  * NOTES
286  *    It seems like this is returning a boolean.  Should it?
287  *
288  * RETURNS
289  *    Success: 1
290  *    Failure: 0
291  */
292 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
293 {
294         HKEY subkey;
295         int             i;
296         char            *s;
297         LPWSTR          name;
298
299     TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
300
301     /* Good.  We already got a line here ... so parse it */
302     subkey = 0;
303     while (1) {
304         i=0;s=*buf;
305         while (*s=='\t') {
306             s++;
307             i++;
308         }
309         if (i>level) {
310             if (!subkey) {
311                 WARN("Got a subhierarchy without resp. key?\n");
312                 return 0;
313             }
314             if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
315                if (!_wine_read_line(F,buf,buflen))
316                   goto done;
317             continue;
318         }
319
320                 /* let the caller handle this line */
321                 if (i<level || **buf=='\0')
322                         goto done;
323
324                 /* it can be: a value or a keyname. Parse the name first */
325                 s=_wine_read_USTRING(s,&name);
326
327                 /* switch() default: hack to avoid gotos */
328                 switch (0) {
329                 default:
330                         if (*s=='\0') {
331                                 if (subkey) RegCloseKey( subkey );
332                                 subkey=_find_or_add_key(hkey,name);
333                         } else {
334                                 LPBYTE          data;
335                                 int             len,lastmodified,type;
336
337                                 if (*s!='=') {
338                                         WARN("Unexpected character: %c\n",*s);
339                                         break;
340                                 }
341                                 s++;
342                                 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
343                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
344                                         break;
345                                 }
346                                 /* skip the 2 , */
347                                 s=strchr(s,',');s++;
348                                 s=strchr(s,',');
349                                 if (!s++) {
350                                         WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
351                                         break;
352                                 }
353                                 if (type == REG_SZ || type == REG_EXPAND_SZ) {
354                                         s=_wine_read_USTRING(s,(LPWSTR*)&data);
355                                         len = lstrlenW((LPWSTR)data)*2+2;
356                                 } else {
357                                         len=strlen(s)/2;
358                                         data = (LPBYTE)xmalloc(len+1);
359                                         for (i=0;i<len;i++) {
360                                                 data[i]=0;
361                                                 if (*s>='0' && *s<='9')
362                                                         data[i]=(*s-'0')<<4;
363                                                 if (*s>='a' && *s<='f')
364                                                         data[i]=(*s-'a'+'\xa')<<4;
365                                                 if (*s>='A' && *s<='F')
366                                                         data[i]=(*s-'A'+'\xa')<<4;
367                                                 s++;
368                                                 if (*s>='0' && *s<='9')
369                                                         data[i]|=*s-'0';
370                                                 if (*s>='a' && *s<='f')
371                                                         data[i]|=*s-'a'+'\xa';
372                                                 if (*s>='A' && *s<='F')
373                                                         data[i]|=*s-'A'+'\xa';
374                                                 s++;
375                                         }
376                                 }
377                                 _find_or_add_value(hkey,name,type,data,len);
378                         }
379                 }
380                 /* read the next line */
381                 if (!_wine_read_line(F,buf,buflen))
382                         goto done;
383     }
384  done:
385     if (subkey) RegCloseKey( subkey );
386     return 1;
387 }
388
389
390 /******************************************************************************
391  * _wine_loadsubreg [Internal]
392  */
393 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
394 {
395         int     ver;
396         char    *buf;
397         int     buflen;
398
399         buf=xmalloc(10);buflen=10;
400         if (!_wine_read_line(F,&buf,&buflen)) {
401                 free(buf);
402                 return 0;
403         }
404         if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
405                 free(buf);
406                 return 0;
407         }
408         if (ver!=1) {
409             if (ver == 2)  /* new version */
410             {
411                 HANDLE file;
412                 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
413                                       FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
414                 {
415                     struct load_registry_request *req = get_req_buffer();
416                     req->hkey    = hkey;
417                     req->file    = file;
418                     req->name[0] = 0;
419                     server_call( REQ_LOAD_REGISTRY );
420                     CloseHandle( file );
421                 }
422                 free( buf );
423                 return 1;
424             }
425             else
426             {
427                 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
428                 free(buf);
429                 return 0;
430             }
431         }
432         if (!_wine_read_line(F,&buf,&buflen)) {
433                 free(buf);
434                 return 0;
435         }
436         if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
437                 free(buf);
438                 return 0;
439         }
440         free(buf);
441         return 1;
442 }
443
444
445 /******************************************************************************
446  * _wine_loadreg [Internal]
447  */
448 static int _wine_loadreg( HKEY hkey, char *fn )
449 {
450     FILE *F;
451
452     TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
453
454     F = fopen(fn,"rb");
455     if (F==NULL) {
456         WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
457         return -1;
458     }
459     _wine_loadsubreg(F,hkey,fn);
460     fclose(F);
461     return 0;
462 }
463
464 /* NT REGISTRY LOADER */
465
466 #ifdef HAVE_SYS_MMAN_H
467 # include <sys/mman.h>
468 #endif
469
470 #ifndef MAP_FAILED
471 #define MAP_FAILED ((LPVOID)-1)
472 #endif
473
474 #define  NT_REG_BLOCK_SIZE              0x1000
475
476 #define NT_REG_HEADER_BLOCK_ID       0x66676572 /* regf */
477 #define NT_REG_POOL_BLOCK_ID         0x6E696268 /* hbin */
478 #define NT_REG_KEY_BLOCK_ID          0x6b6e /* nk */
479 #define NT_REG_VALUE_BLOCK_ID        0x6b76 /* vk */
480
481 /* subblocks of nk */
482 #define NT_REG_HASH_BLOCK_ID         0x666c /* lf */
483 #define NT_REG_NOHASH_BLOCK_ID       0x696c /* li */
484 #define NT_REG_RI_BLOCK_ID           0x6972 /* ri */
485
486 #define NT_REG_KEY_BLOCK_TYPE        0x20
487 #define NT_REG_ROOT_KEY_BLOCK_TYPE   0x2c
488
489 typedef struct 
490 {
491         DWORD   id;             /* 0x66676572 'regf'*/
492         DWORD   uk1;            /* 0x04 */
493         DWORD   uk2;            /* 0x08 */
494         FILETIME        DateModified;   /* 0x0c */
495         DWORD   uk3;            /* 0x14 */
496         DWORD   uk4;            /* 0x18 */
497         DWORD   uk5;            /* 0x1c */
498         DWORD   uk6;            /* 0x20 */
499         DWORD   RootKeyBlock;   /* 0x24 */
500         DWORD   BlockSize;      /* 0x28 */
501         DWORD   uk7[116];       
502         DWORD   Checksum; /* at offset 0x1FC */
503 } nt_regf;
504
505 typedef struct
506 {
507         DWORD   blocksize;
508         BYTE    data[1];
509 } nt_hbin_sub;
510
511 typedef struct
512 {
513         DWORD   id;             /* 0x6E696268 'hbin' */
514         DWORD   off_prev;
515         DWORD   off_next;
516         DWORD   uk1;
517         DWORD   uk2;            /* 0x10 */
518         DWORD   uk3;            /* 0x14 */
519         DWORD   uk4;            /* 0x18 */
520         DWORD   size;           /* 0x1C */
521         nt_hbin_sub     hbin_sub;       /* 0x20 */
522 } nt_hbin;
523
524 /*
525  * the value_list consists of offsets to the values (vk)
526  */
527 typedef struct
528 {
529         WORD    SubBlockId;             /* 0x00 0x6B6E */
530         WORD    Type;                   /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
531         FILETIME        writetime;      /* 0x04 */
532         DWORD   uk1;                    /* 0x0C */
533         DWORD   parent_off;             /* 0x10 Offset of Owner/Parent key */
534         DWORD   nr_subkeys;             /* 0x14 number of sub-Keys */
535         DWORD   uk8;                    /* 0x18 */
536         DWORD   lf_off;                 /* 0x1C Offset of the sub-key lf-Records */
537         DWORD   uk2;                    /* 0x20 */
538         DWORD   nr_values;              /* 0x24 number of values */
539         DWORD   valuelist_off;          /* 0x28 Offset of the Value-List */
540         DWORD   off_sk;                 /* 0x2c Offset of the sk-Record */
541         DWORD   off_class;              /* 0x30 Offset of the Class-Name */
542         DWORD   uk3;                    /* 0x34 */
543         DWORD   uk4;                    /* 0x38 */
544         DWORD   uk5;                    /* 0x3c */
545         DWORD   uk6;                    /* 0x40 */
546         DWORD   uk7;                    /* 0x44 */
547         WORD    name_len;               /* 0x48 name-length */
548         WORD    class_len;              /* 0x4a class-name length */
549         char    name[1];                /* 0x4c key-name */
550 } nt_nk;
551
552 typedef struct
553 {
554         DWORD   off_nk; /* 0x00 */
555         DWORD   name;   /* 0x04 */
556 } hash_rec;
557
558 typedef struct
559 {
560         WORD    id;             /* 0x00 0x666c */
561         WORD    nr_keys;        /* 0x06 */
562         hash_rec        hash_rec[1];
563 } nt_lf;
564
565 /*
566  list of subkeys without hash
567
568  li --+-->nk
569       |
570       +-->nk
571  */
572 typedef struct
573 {
574         WORD    id;             /* 0x00 0x696c */
575         WORD    nr_keys;
576         DWORD   off_nk[1];
577 } nt_li;
578
579 /*
580  this is a intermediate node
581
582  ri --+-->li--+-->nk
583       |       +
584       |       +-->nk
585       |
586       +-->li--+-->nk
587               +
588               +-->nk
589  */
590 typedef struct
591 {
592         WORD    id;             /* 0x00 0x6972 */
593         WORD    nr_li;          /* 0x02 number off offsets */
594         DWORD   off_li[1];      /* 0x04 points to li */
595 } nt_ri;
596
597 typedef struct
598 {
599         WORD    id;             /* 0x00 'vk' */
600         WORD    nam_len;
601         DWORD   data_len;
602         DWORD   data_off;
603         DWORD   type;
604         WORD    flag;
605         WORD    uk1;
606         char    name[1];
607 } nt_vk;
608
609 LPSTR _strdupnA( LPCSTR str, int len )
610 {
611     LPSTR ret;
612
613     if (!str) return NULL;
614     ret = malloc( len + 1 );
615     lstrcpynA( ret, str, len );
616     ret[len] = 0x00;
617     return ret;
618 }
619
620 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
621 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
622 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
623
624
625 /*
626  * gets a value
627  *
628  * vk->flag:
629  *  0 value is a default value
630  *  1 the value has a name
631  *
632  * vk->data_len
633  *  len of the whole data block
634  *  - reg_sz (unicode)
635  *    bytes including the terminating \0 = 2*(number_of_chars+1)
636  *  - reg_dword, reg_binary:
637  *    if highest bit of data_len is set data_off contains the value
638  */
639 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
640 {
641         WCHAR name [256];
642         DWORD ret;
643         BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
644
645         if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
646
647         lstrcpynAtoW(name, vk->name, vk->nam_len+1);
648
649         ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
650                         (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
651                         (vk->data_len & 0x7fffffff) );
652         if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
653         return TRUE;
654 error:
655         ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
656         return FALSE;
657 }
658
659 /*
660  * get the subkeys
661  *
662  * this structure contains the hash of a keyname and points to all
663  * subkeys
664  *
665  * exception: if the id is 'il' there are no hash values and every 
666  * dword is a offset
667  */
668 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
669 {
670         int i;
671
672         if (lf->id == NT_REG_HASH_BLOCK_ID)
673         {
674           if (subkeys != lf->nr_keys) goto error1;
675
676           for (i=0; i<lf->nr_keys; i++)
677           {
678             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
679           }
680         }
681         else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
682         {
683           nt_li * li = (nt_li*)lf;
684           if (subkeys != li->nr_keys) goto error1;
685
686           for (i=0; i<li->nr_keys; i++)
687           {
688             if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
689           }
690         }
691         else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
692         {
693           nt_ri * ri = (nt_ri*)lf;
694           int li_subkeys = 0;
695
696           /* count all subkeys */
697           for (i=0; i<ri->nr_li; i++)
698           {
699             nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
700             if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
701             li_subkeys += li->nr_keys;
702           }
703
704           /* check number */
705           if (subkeys != li_subkeys) goto error1;
706
707           /* loop through the keys */
708           for (i=0; i<ri->nr_li; i++)
709           {
710             nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
711             if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
712           }
713         }
714         else 
715         {
716           goto error2;
717         }
718         return TRUE;
719
720 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
721         return TRUE;
722         
723 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
724         return FALSE;
725
726 error:  ERR_(reg)("error reading lf block\n");
727         return FALSE;
728 }
729
730 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
731 {
732         char * name;
733         int i;
734         DWORD * vl;
735         HKEY subkey = hkey;
736
737         if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
738         {
739           ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
740           goto error;
741         }
742
743         if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
744            (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
745         {
746           ERR_(reg)("registry file corrupt!\n");
747           goto error;
748         }
749
750         /* create the new key */
751         if(level <= 0)
752         {
753           name = _strdupnA( nk->name, nk->name_len+1);
754           if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
755           free(name);
756         }
757
758         /* loop through the subkeys */
759         if (nk->nr_subkeys)
760         {
761           nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
762           if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
763         }
764
765         /* loop trough the value list */
766         vl = (DWORD *)(base+nk->valuelist_off+4);
767         for (i=0; i<nk->nr_values; i++)
768         {
769           nt_vk * vk = (nt_vk*)(base+vl[i]+4);
770           if (!_nt_parse_vk(subkey, base, vk)) goto error1;
771         }
772
773         RegCloseKey(subkey);
774         return TRUE;
775         
776 error1: RegCloseKey(subkey);
777 error:  return FALSE;
778 }
779
780 /* end nt loader */
781
782 /* windows 95 registry loader */
783
784 /* SECTION 1: main header
785  *
786  * once at offset 0
787  */
788 #define W95_REG_CREG_ID 0x47455243
789
790 typedef struct 
791 {
792         DWORD   id;             /* "CREG" = W95_REG_CREG_ID */
793         DWORD   version;        /* ???? 0x00010000 */
794         DWORD   rgdb_off;       /* 0x08 Offset of 1st RGDB-block */
795         DWORD   uk2;            /* 0x0c */
796         WORD    rgdb_num;       /* 0x10 # of RGDB-blocks */
797         WORD    uk3;
798         DWORD   uk[3];
799         /* rgkn */
800 } _w95creg;
801
802 /* SECTION 2: Directory information (tree structure)
803  *
804  * once on offset 0x20
805  *
806  * structure: [rgkn][dke]*      (repeat till rgkn->size is reached)
807  */
808 #define W95_REG_RGKN_ID 0x4e4b4752
809
810 typedef struct
811 {
812         DWORD   id;             /*"RGKN" = W95_REG_RGKN_ID */
813         DWORD   size;           /* Size of the RGKN-block */
814         DWORD   root_off;       /* Rel. Offset of the root-record */
815         DWORD   uk[5];
816 } _w95rgkn;
817
818 /* Disk Key Entry Structure
819  *
820  * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
821  * hive itself. It looks the same like other keys. Even the ID-number can
822  * be any value.
823  *
824  * The "hash"-value is a value representing the key's name. Windows will not
825  * search for the name, but for a matching hash-value. if it finds one, it
826  * will compare the actual string info, otherwise continue with the next key.
827  * To calculate the hash initialize a D-Word with 0 and add all ASCII-values 
828  * of the string which are smaller than 0x80 (128) to this D-Word.   
829  *
830  * If you want to modify key names, also modify the hash-values, since they
831  * cannot be found again (although they would be displayed in REGEDIT)
832  * End of list-pointers are filled with 0xFFFFFFFF
833  *
834  * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
835  * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
836  * structure) and reading another RGDB_section.
837  *
838  * there is a one to one relationship between dke and dkh
839  */
840  /* key struct, once per key */
841 typedef struct
842 {
843         DWORD   x1;             /* Free entry indicator(?) */
844         DWORD   hash;           /* sum of bytes of keyname */
845         DWORD   x3;             /* Root key indicator? usually 0xFFFFFFFF */
846         DWORD   prevlvl;        /* offset of previous key */
847         DWORD   nextsub;        /* offset of child key */
848         DWORD   next;           /* offset of sibling key */
849         WORD    nrLS;           /* id inside the rgdb block */
850         WORD    nrMS;           /* number of the rgdb block */
851 } _w95dke;
852
853 /* SECTION 3: key information, values and data
854  *
855  * structure:
856  *  section:    [blocks]*               (repeat creg->rgdb_num times)
857  *  blocks:     [rgdb] [subblocks]*     (repeat till block size reached )
858  *  subblocks:  [dkh] [dkv]*            (repeat dkh->values times )
859  *
860  * An interesting relationship exists in RGDB_section. The value at offset
861  * 10 equals the value at offset 4 minus the value at offset 8. I have no
862  * idea at the moment what this means.  (Kevin Cozens)
863  */
864
865 /* block header, once per block */
866 #define W95_REG_RGDB_ID 0x42444752
867
868 typedef struct
869 {
870         DWORD   id;     /* 0x00 'rgdb' = W95_REG_RGDB_ID */
871         DWORD   size;   /* 0x04 */
872         DWORD   uk1;    /* 0x08 */
873         DWORD   uk2;    /* 0x0c */
874         DWORD   uk3;    /* 0x10 */
875         DWORD   uk4;    /* 0x14 */
876         DWORD   uk5;    /* 0x18 */
877         DWORD   uk6;    /* 0x1c */
878         /* dkh */
879 } _w95rgdb;
880
881 /* Disk Key Header structure (RGDB part), once per key */
882 typedef struct 
883 {
884         DWORD   nextkeyoff;     /* 0x00 offset to next dkh*/
885         WORD    nrLS;           /* 0x04 id inside the rgdb block */
886         WORD    nrMS;           /* 0x06 number of the rgdb block */
887         DWORD   bytesused;      /* 0x08 */
888         WORD    keynamelen;     /* 0x0c len of name */
889         WORD    values;         /* 0x0e number of values */
890         DWORD   xx1;            /* 0x10 */
891         char    name[1];        /* 0x14 */
892         /* dkv */               /* 0x14 + keynamelen */
893 } _w95dkh;
894
895 /* Disk Key Value structure, once per value */
896 typedef struct
897 {
898         DWORD   type;           /* 0x00 */
899         DWORD   x1;             /* 0x04 */
900         WORD    valnamelen;     /* 0x08 length of name, 0 is default key */
901         WORD    valdatalen;     /* 0x0A length of data */
902         char    name[1];        /* 0x0c */
903         /* raw data */          /* 0x0c + valnamelen */
904 } _w95dkv;
905
906 /******************************************************************************
907  * _w95_lookup_dkh [Internal]
908  *
909  * seeks the dkh belonging to a dke
910  */
911 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
912 {
913         _w95rgdb * rgdb;
914         _w95dkh * dkh;
915         int i;
916         
917         /* get the beginning of the rgdb datastore */
918         rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
919
920         /* check: requested block < last_block) */
921         if (creg->rgdb_num <= nrMS)                             
922         {
923           ERR("registry file corrupt! requested block no. beyond end.\n");
924           goto error;
925         }
926         
927         /* find the right block */
928         for(i=0; i<nrMS ;i++)
929         {
930           if(rgdb->id != W95_REG_RGDB_ID)                       /* check the magic */
931           {
932             ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
933             goto error;
934           }
935           rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size);          /* find next block */
936         }
937
938         dkh = (_w95dkh*)(rgdb + 1);                             /* first sub block within the rgdb */
939
940         do
941         {
942           if(nrLS==dkh->nrLS ) return dkh;
943           dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff);       /* find next subblock */
944         } while ((char *)dkh < ((char*)rgdb+rgdb->size));
945
946 error:  return NULL;
947 }       
948  
949 /******************************************************************************
950  * _w95_parse_dkv [Internal]
951  */
952 static int _w95_parse_dkv (
953         HKEY hkey,
954         _w95dkh * dkh,
955         int nrLS,
956         int nrMS )
957 {
958         _w95dkv * dkv;
959         int i;
960         DWORD ret;
961         char * name;
962                         
963         /* first value block */
964         dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
965
966         /* loop trought the values */
967         for (i=0; i< dkh->values; i++)
968         {
969           name = _strdupnA(dkv->name, dkv->valnamelen+1);
970           ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen); 
971           if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
972           free (name);
973
974           /* next value */
975           dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
976         }
977         return TRUE;
978 }
979
980 /******************************************************************************
981  * _w95_parse_dke [Internal]
982  */
983 static int _w95_parse_dke( 
984         HKEY hkey,
985         _w95creg * creg,
986         _w95rgkn *rgkn,
987         _w95dke * dke,
988         int level )
989 {
990         _w95dkh * dkh;
991         HKEY hsubkey = hkey;
992         char * name;
993         int ret = FALSE;
994
995         /* get start address of root key block */
996         if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
997         
998         /* special root key */
999         if (dke->nrLS == 0xffff || dke->nrMS==0xffff)           /* eg. the root key has no name */
1000         {
1001           /* parse the one subkey*/
1002           if (dke->nextsub != 0xffffffff) 
1003           {
1004             return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1005           }
1006           /* has no sibling keys */
1007           goto error;
1008         }
1009
1010         /* search subblock */
1011         if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1012         {
1013           fprintf(stderr, "dke pointing to missing dkh !\n");
1014           goto error;
1015         }
1016
1017         if ( level <= 0 )
1018         {
1019           /* walk sibling keys */
1020           if (dke->next != 0xffffffff )
1021           {
1022             if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1023           }
1024
1025           /* create subkey and insert values */
1026           name = _strdupnA( dkh->name, dkh->keynamelen+1);
1027           if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1028           free(name);
1029           if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1030         }  
1031         
1032         /* next sub key */
1033         if (dke->nextsub != 0xffffffff) 
1034         {
1035           if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1036         }
1037
1038         ret = TRUE;
1039 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1040 error:  return ret;
1041 }
1042 /* end windows 95 loader */
1043
1044 /******************************************************************************
1045  *      NativeRegLoadKey [Internal]
1046  *
1047  * Loads a native registry file (win95/nt)
1048  *      hkey    root key
1049  *      fn      filename
1050  *      level   number of levels to cut away (eg. ".Default" in user.dat)
1051  *
1052  * this function intentionally uses unix file functions to make it possible
1053  * to move it to a seperate registry helper programm
1054  */
1055 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1056 {
1057         int fd = 0;
1058         struct stat st;
1059         DOS_FULL_NAME full_name;
1060         int ret = FALSE;
1061         void * base;
1062                         
1063         if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1064         
1065         /* map the registry into the memory */
1066         if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1067         if ((fstat(fd, &st) == -1)) goto error;
1068         if (!st.st_size) goto error;
1069         if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1070
1071         switch (*(LPDWORD)base)
1072         {
1073           /* windows 95 'creg' */
1074           case W95_REG_CREG_ID:
1075             {
1076               _w95creg * creg;
1077               _w95rgkn * rgkn;
1078               creg = base;
1079               TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1080
1081               /* load the header (rgkn) */
1082               rgkn = (_w95rgkn*)(creg + 1);
1083               if (rgkn->id != W95_REG_RGKN_ID) 
1084               {
1085                 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1086                 goto error1;
1087               }
1088
1089               ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1090             }
1091             break;
1092           /* nt 'regf'*/
1093           case NT_REG_HEADER_BLOCK_ID:
1094             {
1095               nt_regf * regf;
1096               nt_hbin * hbin;
1097               nt_hbin_sub * hbin_sub;
1098               nt_nk* nk;
1099
1100               TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1101
1102               /* start block */
1103               regf = base;
1104
1105               /* hbin block */
1106               hbin = (nt_hbin*)((char*) base + 0x1000);
1107               if (hbin->id != NT_REG_POOL_BLOCK_ID)
1108               {
1109                 ERR_(reg)( "%s hbin block invalid\n", fn);
1110                 goto error1;
1111               }
1112
1113               /* hbin_sub block */
1114               hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1115               if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1116               {
1117                 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1118                 goto error1;
1119               }
1120
1121               /* nk block */
1122               nk = (nt_nk*)&(hbin_sub->data[0]);
1123               if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1124               {
1125                 ERR_(reg)( "%s special nk block not found\n", fn);
1126                 goto error1;
1127               }
1128
1129               ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1130             }
1131             break;
1132           default:
1133             {
1134               ERR("unknown signature in registry file %s.\n",fn);
1135               goto error1;
1136             }
1137         }
1138         if(!ret) ERR("error loading registry file %s\n", fn);
1139 error1: munmap(base, st.st_size);
1140 error:  close(fd);
1141         return ret;     
1142 }
1143
1144 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1145 /*
1146     reghack - windows 3.11 registry data format demo program.
1147
1148     The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1149     a combined hash table and tree description, and finally a text table.
1150
1151     The header is obvious from the struct header. The taboff1 and taboff2
1152     fields are always 0x20, and their usage is unknown.
1153
1154     The 8-byte entry table has various entry types.
1155
1156     tabent[0] is a root index. The second word has the index of the root of
1157             the directory.
1158     tabent[1..hashsize] is a hash table. The first word in the hash entry is
1159             the index of the key/value that has that hash. Data with the same
1160             hash value are on a circular list. The other three words in the
1161             hash entry are always zero.
1162     tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1163             entry: dirent and keyent/valent. They are identified by context.
1164     tabent[freeidx] is the first free entry. The first word in a free entry
1165             is the index of the next free entry. The last has 0 as a link.
1166             The other three words in the free list are probably irrelevant.
1167
1168     Entries in text table are preceeded by a word at offset-2. This word
1169     has the value (2*index)+1, where index is the referring keyent/valent
1170     entry in the table. I have no suggestion for the 2* and the +1.
1171     Following the word, there are N bytes of data, as per the keyent/valent
1172     entry length. The offset of the keyent/valent entry is from the start
1173     of the text table to the first data byte.
1174
1175     This information is not available from Microsoft. The data format is
1176     deduced from the reg.dat file by me. Mistakes may
1177     have been made. I claim no rights and give no guarantees for this program.
1178
1179     Tor Sjøwall, tor@sn.no
1180 */
1181
1182 /* reg.dat header format */
1183 struct _w31_header {
1184         char            cookie[8];      /* 'SHCC3.10' */
1185         unsigned long   taboff1;        /* offset of hash table (??) = 0x20 */
1186         unsigned long   taboff2;        /* offset of index table (??) = 0x20 */
1187         unsigned long   tabcnt;         /* number of entries in index table */
1188         unsigned long   textoff;        /* offset of text part */
1189         unsigned long   textsize;       /* byte size of text part */
1190         unsigned short  hashsize;       /* hash size */
1191         unsigned short  freeidx;        /* free index */
1192 };
1193
1194 /* generic format of table entries */
1195 struct _w31_tabent {
1196         unsigned short w0, w1, w2, w3;
1197 };
1198
1199 /* directory tabent: */
1200 struct _w31_dirent {
1201         unsigned short  sibling_idx;    /* table index of sibling dirent */
1202         unsigned short  child_idx;      /* table index of child dirent */
1203         unsigned short  key_idx;        /* table index of key keyent */
1204         unsigned short  value_idx;      /* table index of value valent */
1205 };
1206
1207 /* key tabent: */
1208 struct _w31_keyent {
1209         unsigned short  hash_idx;       /* hash chain index for string */
1210         unsigned short  refcnt;         /* reference count */
1211         unsigned short  length;         /* length of string */
1212         unsigned short  string_off;     /* offset of string in text table */
1213 };
1214
1215 /* value tabent: */
1216 struct _w31_valent {
1217         unsigned short  hash_idx;       /* hash chain index for string */
1218         unsigned short  refcnt;         /* reference count */
1219         unsigned short  length;         /* length of string */
1220         unsigned short  string_off;     /* offset of string in text table */
1221 };
1222
1223 /* recursive helper function to display a directory tree */
1224 void
1225 __w31_dumptree( unsigned short idx,
1226                 unsigned char *txt,
1227                 struct _w31_tabent *tab,
1228                 struct _w31_header *head,
1229                 HKEY hkey,
1230                 time_t          lastmodified,
1231                 int             level
1232 ) {
1233         struct _w31_dirent      *dir;
1234         struct _w31_keyent      *key;
1235         struct _w31_valent      *val;
1236         HKEY subkey = 0;
1237         static char             tail[400];
1238
1239         while (idx!=0) {
1240                 dir=(struct _w31_dirent*)&tab[idx];
1241
1242                 if (dir->key_idx) {
1243                         key = (struct _w31_keyent*)&tab[dir->key_idx];
1244
1245                         memcpy(tail,&txt[key->string_off],key->length);
1246                         tail[key->length]='\0';
1247                         /* all toplevel entries AND the entries in the 
1248                          * toplevel subdirectory belong to \SOFTWARE\Classes
1249                          */
1250                         if (!level && !lstrcmpA(tail,".classes")) {
1251                                 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1252                                 idx=dir->sibling_idx;
1253                                 continue;
1254                         }
1255                         if (subkey) RegCloseKey( subkey );
1256                         if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1257                         /* only add if leaf node or valued node */
1258                         if (dir->value_idx!=0||dir->child_idx==0) {
1259                                 if (dir->value_idx) {
1260                                         val=(struct _w31_valent*)&tab[dir->value_idx];
1261                                         memcpy(tail,&txt[val->string_off],val->length);
1262                                         tail[val->length]='\0';
1263                                         RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1264                                 }
1265                         }
1266                 } else {
1267                         TRACE("strange: no directory key name, idx=%04x\n", idx);
1268                 }
1269                 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1270                 idx=dir->sibling_idx;
1271         }
1272         if (subkey) RegCloseKey( subkey );
1273 }
1274
1275
1276 /******************************************************************************
1277  * _w31_loadreg [Internal]
1278  */
1279 void _w31_loadreg(void) {
1280         HFILE                   hf;
1281         struct _w31_header      head;
1282         struct _w31_tabent      *tab;
1283         unsigned char           *txt;
1284         int                     len;
1285         OFSTRUCT                ofs;
1286         BY_HANDLE_FILE_INFORMATION hfinfo;
1287         time_t                  lastmodified;
1288
1289         TRACE("(void)\n");
1290
1291         hf = OpenFile("reg.dat",&ofs,OF_READ);
1292         if (hf==HFILE_ERROR)
1293                 return;
1294
1295         /* read & dump header */
1296         if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1297                 ERR("reg.dat is too short.\n");
1298                 _lclose(hf);
1299                 return;
1300         }
1301         if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1302                 ERR("reg.dat has bad signature.\n");
1303                 _lclose(hf);
1304                 return;
1305         }
1306
1307         len = head.tabcnt * sizeof(struct _w31_tabent);
1308         /* read and dump index table */
1309         tab = xmalloc(len);
1310         if (len!=_lread(hf,tab,len)) {
1311                 ERR("couldn't read %d bytes.\n",len); 
1312                 free(tab);
1313                 _lclose(hf);
1314                 return;
1315         }
1316
1317         /* read text */
1318         txt = xmalloc(head.textsize);
1319         if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1320                 ERR("couldn't seek to textblock.\n"); 
1321                 free(tab);
1322                 free(txt);
1323                 _lclose(hf);
1324                 return;
1325         }
1326         if (head.textsize!=_lread(hf,txt,head.textsize)) {
1327                 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize); 
1328                 free(tab);
1329                 free(txt);
1330                 _lclose(hf);
1331                 return;
1332         }
1333
1334         if (!GetFileInformationByHandle(hf,&hfinfo)) {
1335                 ERR("GetFileInformationByHandle failed?.\n"); 
1336                 free(tab);
1337                 free(txt);
1338                 _lclose(hf);
1339                 return;
1340         }
1341         lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1342         __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1343         free(tab);
1344         free(txt);
1345         _lclose(hf);
1346         return;
1347 }
1348
1349
1350 /* configure save files and start the periodic saving timer */
1351 static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
1352 {
1353     struct set_registry_levels_request *req = get_req_buffer();
1354
1355     int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1356     int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1357
1358     /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1359     req->current = 1;
1360     req->saving  = !all;
1361     req->period  = period * 1000;
1362     server_call( REQ_SET_REGISTRY_LEVELS );
1363
1364     if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1365     {
1366         struct save_registry_atexit_request *req = get_req_buffer();
1367         const char *confdir = get_config_dir();
1368         char *str = req->file + strlen(confdir);
1369
1370         if (str + 20 > req->file + server_remaining(req->file))
1371         {
1372             ERR("config dir '%s' too long\n", confdir );
1373             return;
1374         }
1375
1376         strcpy( req->file, confdir );
1377         strcpy( str, "/" SAVE_CURRENT_USER );
1378         req->hkey = HKEY_CURRENT_USER;
1379         server_call( REQ_SAVE_REGISTRY_ATEXIT );
1380
1381         strcpy( req->file, confdir );
1382         strcpy( str, "/" SAVE_LOCAL_MACHINE );
1383         req->hkey = HKEY_LOCAL_MACHINE;
1384         server_call( REQ_SAVE_REGISTRY_ATEXIT );
1385
1386         strcpy( req->file, confdir );
1387         strcpy( str, "/" SAVE_DEFAULT_USER );
1388         req->hkey = hkey_users_default;
1389         server_call( REQ_SAVE_REGISTRY_ATEXIT );
1390
1391         strcpy( req->file, confdir );
1392         strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1393         req->hkey = HKEY_USERS;
1394         server_call( REQ_SAVE_REGISTRY_ATEXIT );
1395     }
1396 }
1397
1398
1399 /**********************************************************************************
1400  * SetLoadLevel [Internal]
1401  *
1402  * set level to 0 for loading system files
1403  * set level to 1 for loading user files
1404  */
1405 static void SetLoadLevel(int level)
1406 {
1407         struct set_registry_levels_request *req = get_req_buffer();
1408
1409         req->current = level;
1410         req->saving  = 0;
1411         req->period  = 0;
1412         server_call( REQ_SET_REGISTRY_LEVELS );
1413 }
1414
1415 /**********************************************************************************
1416  * SHELL_LoadRegistry [Internal]
1417  */
1418 #define REG_DONTLOAD -1
1419 #define REG_WIN31  0
1420 #define REG_WIN95  1
1421 #define REG_WINNT  2
1422
1423 void SHELL_LoadRegistry( void )
1424 {
1425   HKEY  hkey;
1426   char windir[MAX_PATHNAME_LEN];
1427   char path[MAX_PATHNAME_LEN];
1428   int  systemtype = REG_WIN31;
1429   HKEY hkey_users_default;
1430
1431   TRACE("(void)\n");
1432
1433   if (!CLIENT_IsBootThread()) return;  /* already loaded */
1434
1435   REGISTRY_Init();
1436   SetLoadLevel(0);
1437
1438   if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default))
1439           hkey_users_default = 0;
1440
1441   GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1442
1443   if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1444   {
1445     /* test %windir%/system32/config/system --> winnt */
1446     strcpy(path, windir);
1447     strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1448     if(GetFileAttributesA(path) != -1) 
1449     {
1450       systemtype = REG_WINNT;
1451     }
1452     else
1453     {
1454        /* test %windir%/system.dat --> win95 */
1455       strcpy(path, windir);
1456       strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1457       if(GetFileAttributesA(path) != -1)
1458       {
1459         systemtype = REG_WIN95;
1460       }
1461     }
1462
1463     if ((systemtype==REG_WINNT)
1464       && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1465     {
1466        MESSAGE("When you are running with a native NT directory specify\n");
1467        MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1468        MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1469        systemtype = REG_DONTLOAD;
1470     }
1471   }
1472   else
1473   {
1474     /* only wine registry */
1475     systemtype = REG_DONTLOAD;
1476   }  
1477
1478   switch (systemtype)
1479   {
1480     case REG_WIN31:
1481       _w31_loadreg();
1482       break;
1483
1484     case REG_WIN95:  
1485       /* Load windows 95 entries */
1486       NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1487
1488       strcpy(path, windir);
1489       strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1490       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1491
1492       if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1493       {
1494         /* user specific user.dat */
1495         strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1496         if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1497         {
1498           MESSAGE("can't load win95 user-registry %s\n", path);
1499           MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1500         }
1501         /* default user.dat */
1502         if (hkey_users_default)
1503         {
1504           strcpy(path, windir);
1505           strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1506           NativeRegLoadKey(hkey_users_default, path, 1);
1507         }
1508       }
1509       else
1510       {
1511         /* global user.dat */
1512         strcpy(path, windir);
1513         strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1514         NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1515       }
1516       break;
1517
1518     case REG_WINNT:  
1519       /* default user.dat */
1520       if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1521       {
1522         strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1523         if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1524         {
1525            MESSAGE("can't load NT user-registry %s\n", path);
1526            MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1527         }
1528       }
1529
1530       /* default user.dat */
1531       if (hkey_users_default)
1532       {
1533         strcpy(path, windir);
1534         strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1535         NativeRegLoadKey(hkey_users_default, path, 1);
1536       }
1537
1538       /*
1539       * FIXME
1540       *  map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1541       */
1542
1543       if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1544       {
1545         strcpy(path, windir);
1546         strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1547         NativeRegLoadKey(hkey, path, 1);
1548         RegCloseKey(hkey);
1549       }
1550
1551       if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1552       {
1553         strcpy(path, windir);
1554         strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1555         NativeRegLoadKey(hkey, path, 1);
1556         RegCloseKey(hkey);
1557       }
1558
1559       strcpy(path, windir);
1560       strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1561       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1562
1563       strcpy(path, windir);
1564       strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1565       NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1566
1567       /* this key is generated when the nt-core booted successfully */
1568       if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1569         RegCloseKey(hkey);
1570       break;
1571   } /* switch */
1572   
1573   if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1574   {
1575       /* 
1576        * Load the global HKU hive directly from sysconfdir
1577        */ 
1578       _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1579
1580       /* 
1581        * Load the global machine defaults directly from sysconfdir
1582        */
1583       _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1584   }
1585
1586   SetLoadLevel(1);
1587
1588   /*
1589    * Load the user saved registries 
1590    */
1591   if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1592   {
1593       const char *confdir = get_config_dir();
1594       int len = strlen(confdir) + 20;
1595       char *fn = path;
1596
1597       if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1598       /* 
1599        * Load user's personal versions of global HKU/.Default keys
1600        */
1601       if (fn)
1602       {
1603           char *str;
1604           strcpy( fn, confdir );
1605           str = fn + strlen(fn);
1606           *str++ = '/';
1607
1608           /* try to load HKU\.Default key only */
1609           strcpy( str, SAVE_DEFAULT_USER );
1610           if (_wine_loadreg( hkey_users_default, fn ))
1611           {
1612               /* if not found load old file containing both HKU\.Default and HKU\user */
1613               strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1614               _wine_loadreg( HKEY_USERS, fn ); 
1615           }
1616
1617           strcpy( str, SAVE_CURRENT_USER );
1618           _wine_loadreg( HKEY_CURRENT_USER, fn );
1619
1620           strcpy( str, SAVE_LOCAL_MACHINE );
1621           _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1622
1623           if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1624       }
1625   }
1626   SHELL_InitRegistrySaving( hkey_users_default );
1627   RegCloseKey( hkey_users_default );
1628 }
1629
1630 /********************* API FUNCTIONS ***************************************/
1631
1632
1633
1634
1635 /******************************************************************************
1636  * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1637  * Immediately writes key to registry.
1638  * Only returns after data has been written to disk.
1639  *
1640  * FIXME: does it really wait until data is written ?
1641  *
1642  * PARAMS
1643  *    hkey [I] Handle of key to write
1644  *
1645  * RETURNS
1646  *    Success: ERROR_SUCCESS
1647  *    Failure: Error code
1648  */
1649 DWORD WINAPI RegFlushKey( HKEY hkey )
1650 {
1651     FIXME( "(%x): stub\n", hkey );
1652     return ERROR_SUCCESS;
1653 }
1654
1655 /******************************************************************************
1656  * RegConnectRegistryW [ADVAPI32.128]
1657  *
1658  * PARAMS
1659  *    lpMachineName [I] Address of name of remote computer
1660  *    hHey          [I] Predefined registry handle
1661  *    phkResult     [I] Address of buffer for remote registry handle
1662  */
1663 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, 
1664                                    LPHKEY phkResult )
1665 {
1666     TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1667
1668     if (!lpMachineName || !*lpMachineName) {
1669         /* Use the local machine name */
1670         return RegOpenKey16( hKey, "", phkResult );
1671     }
1672
1673     FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1674     return ERROR_BAD_NETPATH;
1675 }
1676
1677
1678 /******************************************************************************
1679  * RegConnectRegistryA [ADVAPI32.127]
1680  */
1681 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1682 {
1683     DWORD ret;
1684     LPWSTR machineW = strdupA2W(machine);
1685     ret = RegConnectRegistryW( machineW, hkey, reskey );
1686     free(machineW);
1687     return ret;
1688 }
1689
1690
1691 /******************************************************************************
1692  * RegGetKeySecurity [ADVAPI32.144]
1693  * Retrieves a copy of security descriptor protecting the registry key
1694  *
1695  * PARAMS
1696  *    hkey                   [I]   Open handle of key to set
1697  *    SecurityInformation    [I]   Descriptor contents
1698  *    pSecurityDescriptor    [O]   Address of descriptor for key
1699  *    lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1700  *
1701  * RETURNS
1702  *    Success: ERROR_SUCCESS
1703  *    Failure: Error code
1704  */
1705 LONG WINAPI RegGetKeySecurity( HKEY hkey, 
1706                                SECURITY_INFORMATION SecurityInformation,
1707                                PSECURITY_DESCRIPTOR pSecurityDescriptor,
1708                                LPDWORD lpcbSecurityDescriptor )
1709 {
1710     TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1711           lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1712
1713     /* FIXME: Check for valid SecurityInformation values */
1714
1715     if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1716         return ERROR_INSUFFICIENT_BUFFER;
1717
1718     FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1719           pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1720
1721     return ERROR_SUCCESS;
1722 }
1723
1724
1725 /******************************************************************************
1726  * RegNotifyChangeKeyValue [ADVAPI32.???]
1727  *
1728  * PARAMS
1729  *    hkey            [I] Handle of key to watch
1730  *    fWatchSubTree   [I] Flag for subkey notification
1731  *    fdwNotifyFilter [I] Changes to be reported
1732  *    hEvent          [I] Handle of signaled event
1733  *    fAsync          [I] Flag for asynchronous reporting
1734  */
1735 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree, 
1736                                      DWORD fdwNotifyFilter, HANDLE hEvent,
1737                                      BOOL fAsync )
1738 {
1739     FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1740           hEvent,fAsync);
1741     return ERROR_SUCCESS;
1742 }
1743
1744
1745 /******************************************************************************
1746  * RegUnLoadKeyW [ADVAPI32.173]
1747  *
1748  * PARAMS
1749  *    hkey     [I] Handle of open key
1750  *    lpSubKey [I] Address of name of subkey to unload
1751  */
1752 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1753 {
1754     FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1755     return ERROR_SUCCESS;
1756 }
1757
1758
1759 /******************************************************************************
1760  * RegUnLoadKeyA [ADVAPI32.172]
1761  */
1762 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1763 {
1764     LONG ret;
1765     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1766     ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1767     if(lpSubKeyW) free(lpSubKeyW);
1768     return ret;
1769 }
1770
1771
1772 /******************************************************************************
1773  * RegSetKeySecurity [ADVAPI32.167]
1774  *
1775  * PARAMS
1776  *    hkey          [I] Open handle of key to set
1777  *    SecurityInfo  [I] Descriptor contents
1778  *    pSecurityDesc [I] Address of descriptor for key
1779  */
1780 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1781                                PSECURITY_DESCRIPTOR pSecurityDesc )
1782 {
1783     TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1784
1785     /* It seems to perform this check before the hkey check */
1786     if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1787         (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1788         (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1789         (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1790         /* Param OK */
1791     } else
1792         return ERROR_INVALID_PARAMETER;
1793
1794     if (!pSecurityDesc)
1795         return ERROR_INVALID_PARAMETER;
1796
1797     FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1798
1799     return ERROR_SUCCESS;
1800 }
1801
1802
1803 /******************************************************************************
1804  * RegRestoreKeyW [ADVAPI32.164]
1805  *
1806  * PARAMS
1807  *    hkey    [I] Handle of key where restore begins
1808  *    lpFile  [I] Address of filename containing saved tree
1809  *    dwFlags [I] Optional flags
1810  */
1811 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1812 {
1813     TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1814
1815     /* It seems to do this check before the hkey check */
1816     if (!lpFile || !*lpFile)
1817         return ERROR_INVALID_PARAMETER;
1818
1819     FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1820
1821     /* Check for file existence */
1822
1823     return ERROR_SUCCESS;
1824 }
1825
1826
1827 /******************************************************************************
1828  * RegRestoreKeyA [ADVAPI32.163]
1829  */
1830 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1831 {
1832     LONG ret;
1833     LPWSTR lpFileW = strdupA2W(lpFile);
1834     ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1835     if(lpFileW) free(lpFileW);
1836     return ret;
1837 }
1838
1839
1840 /******************************************************************************
1841  * RegReplaceKeyW [ADVAPI32.162]
1842  *
1843  * PARAMS
1844  *    hkey      [I] Handle of open key
1845  *    lpSubKey  [I] Address of name of subkey
1846  *    lpNewFile [I] Address of filename for file with new data
1847  *    lpOldFile [I] Address of filename for backup file
1848  */
1849 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1850                               LPCWSTR lpOldFile )
1851 {
1852     FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), 
1853           debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1854     return ERROR_SUCCESS;
1855 }
1856
1857
1858 /******************************************************************************
1859  * RegReplaceKeyA [ADVAPI32.161]
1860  */
1861 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1862                               LPCSTR lpOldFile )
1863 {
1864     LONG ret;
1865     LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1866     LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1867     LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1868     ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1869     free(lpOldFileW);
1870     free(lpNewFileW);
1871     free(lpSubKeyW);
1872     return ret;
1873 }
1874
1875
1876
1877
1878
1879
1880 /* 16-bit functions */
1881
1882 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1883  * some programs. Do not remove those cases. -MM
1884  */
1885 static inline void fix_win16_hkey( HKEY *hkey )
1886 {
1887     if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1888 }
1889
1890 /******************************************************************************
1891  *           RegEnumKey16   [KERNEL.216] [SHELL.7]
1892  */
1893 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1894 {
1895     fix_win16_hkey( &hkey );
1896     return RegEnumKeyA( hkey, index, name, name_len );
1897 }
1898
1899 /******************************************************************************
1900  *           RegOpenKey16   [KERNEL.217] [SHELL.1]
1901  */
1902 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1903 {
1904     fix_win16_hkey( &hkey );
1905     return RegOpenKeyA( hkey, name, retkey );
1906 }
1907
1908 /******************************************************************************
1909  *           RegCreateKey16   [KERNEL.218] [SHELL.2]
1910  */
1911 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1912 {
1913     fix_win16_hkey( &hkey );
1914     return RegCreateKeyA( hkey, name, retkey );
1915 }
1916
1917 /******************************************************************************
1918  *           RegDeleteKey16   [KERNEL.219] [SHELL.4]
1919  */
1920 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1921 {
1922     fix_win16_hkey( &hkey );
1923     return RegDeleteKeyA( hkey, name );
1924 }
1925
1926 /******************************************************************************
1927  *           RegCloseKey16   [KERNEL.220] [SHELL.3]
1928  */
1929 DWORD WINAPI RegCloseKey16( HKEY hkey )
1930 {
1931     fix_win16_hkey( &hkey );
1932     return RegCloseKey( hkey );
1933 }
1934
1935 /******************************************************************************
1936  *           RegSetValue16   [KERNEL.221] [SHELL.5]
1937  */
1938 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1939 {
1940     fix_win16_hkey( &hkey );
1941     return RegSetValueA( hkey, name, type, data, count );
1942 }
1943
1944 /******************************************************************************
1945  *           RegDeleteValue16  [KERNEL.222]
1946  */
1947 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1948 {
1949     fix_win16_hkey( &hkey );
1950     return RegDeleteValueA( hkey, name );
1951 }
1952
1953 /******************************************************************************
1954  *           RegEnumValue16   [KERNEL.223]
1955  */
1956 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1957                              LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1958 {
1959     fix_win16_hkey( &hkey );
1960     return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1961 }
1962
1963 /******************************************************************************
1964  *           RegQueryValue16   [KERNEL.224] [SHELL.6]
1965  *
1966  * NOTES
1967  *    Is this HACK still applicable?
1968  *
1969  * HACK
1970  *    The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1971  *    mask out the high 16 bit.  This (not so much incidently) hopefully fixes
1972  *    Aldus FH4)
1973  */
1974 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1975 {
1976     fix_win16_hkey( &hkey );
1977     if (count) *count &= 0xffff;
1978     return RegQueryValueA( hkey, name, data, count );
1979 }
1980
1981 /******************************************************************************
1982  *           RegQueryValueEx16   [KERNEL.225]
1983  */
1984 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1985                                 LPBYTE data, LPDWORD count )
1986 {
1987     fix_win16_hkey( &hkey );
1988     return RegQueryValueExA( hkey, name, reserved, type, data, count );
1989 }
1990
1991 /******************************************************************************
1992  *           RegSetValueEx16   [KERNEL.226]
1993  */
1994 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1995                               CONST BYTE *data, DWORD count )
1996 {
1997     fix_win16_hkey( &hkey );
1998     return RegSetValueExA( hkey, name, reserved, type, data, count );
1999 }