Added new configuration file option for selecting graphics driver.
[wine/wine64.git] / misc / registry.c
blob8dc7c2757a713e3b887b400f09c659ac4d451b69
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
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.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include "config.h"
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 <assert.h>
39 #include <time.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wine/winbase16.h"
43 #include "wine/winestring.h"
44 #include "winerror.h"
45 #include "file.h"
46 #include "heap.h"
47 #include "debugtools.h"
48 #include "options.h"
49 #include "winreg.h"
50 #include "server.h"
51 #include "services.h"
53 DEFAULT_DEBUG_CHANNEL(reg);
55 static void REGISTRY_Init(void);
56 /* FIXME: following defines should be configured global ... */
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
70 static void *xmalloc( size_t size )
72 void *res;
74 res = malloc (size ? size : 1);
75 if (res == NULL) {
76 WARN("Virtual memory exhausted.\n");
77 exit (1);
79 return res;
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
91 static LPWSTR strdupA2W(LPCSTR src)
93 if(src) {
94 LPWSTR dest=xmalloc(2*strlen(src)+2);
95 lstrcpyAtoW(dest,src);
96 return dest;
98 return NULL;
101 LPWSTR strcvtA2W(LPCSTR src, int nchars)
104 LPWSTR dest = xmalloc (2 * nchars + 2);
106 lstrcpynAtoW(dest,src,nchars+1);
107 return dest;
112 /******************************************************************************
113 * REGISTRY_Init [Internal]
114 * Registry initialisation, allocates some default keys.
116 static void REGISTRY_Init(void) {
117 HKEY hkey;
118 char buf[200];
120 TRACE("(void)\n");
122 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
123 RegCloseKey(hkey);
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);
131 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
132 * CurrentVersion
133 * CurrentBuildNumber
134 * CurrentType
135 * string RegisteredOwner
136 * string RegisteredOrganization
139 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
140 * string SysContact
141 * string SysLocation
142 * SysServices
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);
152 /************************ LOAD Registry Function ****************************/
156 /******************************************************************************
157 * _find_or_add_key [Internal]
159 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
161 HKEY subkey;
162 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
163 if (keyname) free( keyname );
164 return subkey;
167 /******************************************************************************
168 * _find_or_add_value [Internal]
170 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
172 RegSetValueExW( hkey, name, 0, type, data, len );
173 if (name) free( name );
174 if (data) free( data );
178 /******************************************************************************
179 * _wine_read_line [Internal]
181 * reads a line including dynamically enlarging the readbuffer and throwing
182 * away comments
184 static int _wine_read_line( FILE *F, char **buf, int *len )
186 char *s,*curread;
187 int mylen,curoff;
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;
205 *buf = curread;
206 curread+= curoff;
207 mylen = *len; /* we filled up the buffer and
208 * got new '*len' bytes to fill
210 *len = *len * 2;
211 } else {
212 *s='\0';
213 break;
216 /* throw away comments */
217 if (**buf=='#' || **buf==';') {
218 curread = *buf;
219 mylen = *len;
220 continue;
222 if (s) /* got end of line */
223 break;
225 return 1;
229 /******************************************************************************
230 * _wine_read_USTRING [Internal]
232 * converts a char* into a UNICODE string (up to a special char)
233 * and returns the position exactly after that string
235 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
237 char *s;
238 LPWSTR ws;
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 do to?
253 break;
255 if (*s=='\\') {
256 *ws++='\\';
257 s++;
258 continue;
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;
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;
277 *ws = 0;
278 return s;
282 /******************************************************************************
283 * _wine_loadsubkey [Internal]
285 * NOTES
286 * It seems like this is returning a boolean. Should it?
288 * RETURNS
289 * Success: 1
290 * Failure: 0
292 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
294 HKEY subkey;
295 int i;
296 char *s;
297 LPWSTR name;
299 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
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++;
309 if (i>level) {
310 if (!subkey) {
311 WARN("Got a subhierarchy without resp. key?\n");
312 return 0;
314 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
315 if (!_wine_read_line(F,buf,buflen))
316 goto done;
317 continue;
320 /* let the caller handle this line */
321 if (i<level || **buf=='\0')
322 goto done;
324 /* it can be: a value or a keyname. Parse the name first */
325 s=_wine_read_USTRING(s,&name);
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;
337 if (*s!='=') {
338 WARN("Unexpected character: %c\n",*s);
339 break;
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;
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;
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++;
377 _find_or_add_value(hkey,name,type,data,len);
380 /* read the next line */
381 if (!_wine_read_line(F,buf,buflen))
382 goto done;
384 done:
385 if (subkey) RegCloseKey( subkey );
386 return 1;
390 /******************************************************************************
391 * _wine_loadsubreg [Internal]
393 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
395 int ver;
396 char *buf;
397 int buflen;
399 buf=xmalloc(10);buflen=10;
400 if (!_wine_read_line(F,&buf,&buflen)) {
401 free(buf);
402 return 0;
404 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
405 free(buf);
406 return 0;
408 if (ver!=1) {
409 if (ver == 2) /* new version */
411 HANDLE file;
412 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
413 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
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 );
422 free( buf );
423 return 1;
425 else
427 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
428 free(buf);
429 return 0;
432 if (!_wine_read_line(F,&buf,&buflen)) {
433 free(buf);
434 return 0;
436 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
437 free(buf);
438 return 0;
440 free(buf);
441 return 1;
445 /******************************************************************************
446 * _wine_loadreg [Internal]
448 static void _wine_loadreg( HKEY hkey, char *fn )
450 FILE *F;
452 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
454 F = fopen(fn,"rb");
455 if (F==NULL) {
456 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
457 return;
459 _wine_loadsubreg(F,hkey,fn);
460 fclose(F);
463 /* NT REGISTRY LOADER */
465 #ifdef HAVE_SYS_MMAN_H
466 # include <sys/mman.h>
467 #endif
469 #ifndef MAP_FAILED
470 #define MAP_FAILED ((LPVOID)-1)
471 #endif
473 #define NT_REG_BLOCK_SIZE 0x1000
475 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
476 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
477 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
478 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
480 /* subblocks of nk */
481 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
482 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
483 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
485 #define NT_REG_KEY_BLOCK_TYPE 0x20
486 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
488 typedef struct
490 DWORD id; /* 0x66676572 'regf'*/
491 DWORD uk1; /* 0x04 */
492 DWORD uk2; /* 0x08 */
493 FILETIME DateModified; /* 0x0c */
494 DWORD uk3; /* 0x14 */
495 DWORD uk4; /* 0x18 */
496 DWORD uk5; /* 0x1c */
497 DWORD uk6; /* 0x20 */
498 DWORD RootKeyBlock; /* 0x24 */
499 DWORD BlockSize; /* 0x28 */
500 DWORD uk7[116];
501 DWORD Checksum; /* at offset 0x1FC */
502 } nt_regf;
504 typedef struct
506 DWORD blocksize;
507 BYTE data[1];
508 } nt_hbin_sub;
510 typedef struct
512 DWORD id; /* 0x6E696268 'hbin' */
513 DWORD off_prev;
514 DWORD off_next;
515 DWORD uk1;
516 DWORD uk2; /* 0x10 */
517 DWORD uk3; /* 0x14 */
518 DWORD uk4; /* 0x18 */
519 DWORD size; /* 0x1C */
520 nt_hbin_sub hbin_sub; /* 0x20 */
521 } nt_hbin;
524 * the value_list consists of offsets to the values (vk)
526 typedef struct
528 WORD SubBlockId; /* 0x00 0x6B6E */
529 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
530 FILETIME writetime; /* 0x04 */
531 DWORD uk1; /* 0x0C */
532 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
533 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
534 DWORD uk8; /* 0x18 */
535 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
536 DWORD uk2; /* 0x20 */
537 DWORD nr_values; /* 0x24 number of values */
538 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
539 DWORD off_sk; /* 0x2c Offset of the sk-Record */
540 DWORD off_class; /* 0x30 Offset of the Class-Name */
541 DWORD uk3; /* 0x34 */
542 DWORD uk4; /* 0x38 */
543 DWORD uk5; /* 0x3c */
544 DWORD uk6; /* 0x40 */
545 DWORD uk7; /* 0x44 */
546 WORD name_len; /* 0x48 name-length */
547 WORD class_len; /* 0x4a class-name length */
548 char name[1]; /* 0x4c key-name */
549 } nt_nk;
551 typedef struct
553 DWORD off_nk; /* 0x00 */
554 DWORD name; /* 0x04 */
555 } hash_rec;
557 typedef struct
559 WORD id; /* 0x00 0x666c */
560 WORD nr_keys; /* 0x06 */
561 hash_rec hash_rec[1];
562 } nt_lf;
565 list of subkeys without hash
567 li --+-->nk
569 +-->nk
571 typedef struct
573 WORD id; /* 0x00 0x696c */
574 WORD nr_keys;
575 DWORD off_nk[1];
576 } nt_li;
579 this is a intermediate node
581 ri --+-->li--+-->nk
583 | +-->nk
585 +-->li--+-->nk
587 +-->nk
589 typedef struct
591 WORD id; /* 0x00 0x6972 */
592 WORD nr_li; /* 0x02 number off offsets */
593 DWORD off_li[1]; /* 0x04 points to li */
594 } nt_ri;
596 typedef struct
598 WORD id; /* 0x00 'vk' */
599 WORD nam_len;
600 DWORD data_len;
601 DWORD data_off;
602 DWORD type;
603 WORD flag;
604 WORD uk1;
605 char name[1];
606 } nt_vk;
608 LPSTR _strdupnA( LPCSTR str, int len )
610 LPSTR ret;
612 if (!str) return NULL;
613 ret = malloc( len + 1 );
614 lstrcpynA( ret, str, len );
615 ret[len] = 0x00;
616 return ret;
619 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
620 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
621 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
625 * gets a value
627 * vk->flag:
628 * 0 value is a default value
629 * 1 the value has a name
631 * vk->data_len
632 * len of the whole data block
633 * - reg_sz (unicode)
634 * bytes including the terminating \0 = 2*(number_of_chars+1)
635 * - reg_dword, reg_binary:
636 * if highest bit of data_len is set data_off contains the value
638 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
640 WCHAR name [256];
641 DWORD ret;
642 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
644 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
646 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
648 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
649 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
650 (vk->data_len & 0x7fffffff) );
651 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
652 return TRUE;
653 error:
654 ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
655 return FALSE;
659 * get the subkeys
661 * this structure contains the hash of a keyname and points to all
662 * subkeys
664 * exception: if the id is 'il' there are no hash values and every
665 * dword is a offset
667 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
669 int i;
671 if (lf->id == NT_REG_HASH_BLOCK_ID)
673 if (subkeys != lf->nr_keys) goto error1;
675 for (i=0; i<lf->nr_keys; i++)
677 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
680 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
682 nt_li * li = (nt_li*)lf;
683 if (subkeys != li->nr_keys) goto error1;
685 for (i=0; i<li->nr_keys; i++)
687 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
690 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
692 nt_ri * ri = (nt_ri*)lf;
693 int li_subkeys = 0;
695 /* count all subkeys */
696 for (i=0; i<ri->nr_li; i++)
698 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
699 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
700 li_subkeys += li->nr_keys;
703 /* check number */
704 if (subkeys != li_subkeys) goto error1;
706 /* loop through the keys */
707 for (i=0; i<ri->nr_li; i++)
709 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
710 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
713 else
715 goto error2;
717 return TRUE;
719 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
720 return TRUE;
722 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
723 return FALSE;
725 error: ERR_(reg)("error reading lf block\n");
726 return FALSE;
729 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
731 char * name;
732 int i;
733 DWORD * vl;
734 HKEY subkey = hkey;
736 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
738 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
739 goto error;
742 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
743 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
745 ERR_(reg)("registry file corrupt!\n");
746 goto error;
749 /* create the new key */
750 if(level <= 0)
752 name = _strdupnA( nk->name, nk->name_len+1);
753 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
754 free(name);
757 /* loop through the subkeys */
758 if (nk->nr_subkeys)
760 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
761 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
764 /* loop trough the value list */
765 vl = (DWORD *)(base+nk->valuelist_off+4);
766 for (i=0; i<nk->nr_values; i++)
768 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
769 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
772 RegCloseKey(subkey);
773 return TRUE;
775 error1: RegCloseKey(subkey);
776 error: return FALSE;
779 /* end nt loader */
781 /* windows 95 registry loader */
783 /* SECTION 1: main header
785 * once at offset 0
787 #define W95_REG_CREG_ID 0x47455243
789 typedef struct
791 DWORD id; /* "CREG" = W95_REG_CREG_ID */
792 DWORD version; /* ???? 0x00010000 */
793 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
794 DWORD uk2; /* 0x0c */
795 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
796 WORD uk3;
797 DWORD uk[3];
798 /* rgkn */
799 } _w95creg;
801 /* SECTION 2: Directory information (tree structure)
803 * once on offset 0x20
805 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
807 #define W95_REG_RGKN_ID 0x4e4b4752
809 typedef struct
811 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
812 DWORD size; /* Size of the RGKN-block */
813 DWORD root_off; /* Rel. Offset of the root-record */
814 DWORD uk[5];
815 } _w95rgkn;
817 /* Disk Key Entry Structure
819 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
820 * hive itself. It looks the same like other keys. Even the ID-number can
821 * be any value.
823 * The "hash"-value is a value representing the key's name. Windows will not
824 * search for the name, but for a matching hash-value. if it finds one, it
825 * will compare the actual string info, otherwise continue with the next key.
826 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
827 * of the string which are smaller than 0x80 (128) to this D-Word.
829 * If you want to modify key names, also modify the hash-values, since they
830 * cannot be found again (although they would be displayed in REGEDIT)
831 * End of list-pointers are filled with 0xFFFFFFFF
833 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
834 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
835 * structure) and reading another RGDB_section.
837 * there is a one to one relationship between dke and dkh
839 /* key struct, once per key */
840 typedef struct
842 DWORD x1; /* Free entry indicator(?) */
843 DWORD hash; /* sum of bytes of keyname */
844 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
845 DWORD prevlvl; /* offset of previous key */
846 DWORD nextsub; /* offset of child key */
847 DWORD next; /* offset of sibling key */
848 WORD nrLS; /* id inside the rgdb block */
849 WORD nrMS; /* number of the rgdb block */
850 } _w95dke;
852 /* SECTION 3: key information, values and data
854 * structure:
855 * section: [blocks]* (repeat creg->rgdb_num times)
856 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
857 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
859 * An interesting relationship exists in RGDB_section. The value at offset
860 * 10 equals the value at offset 4 minus the value at offset 8. I have no
861 * idea at the moment what this means. (Kevin Cozens)
864 /* block header, once per block */
865 #define W95_REG_RGDB_ID 0x42444752
867 typedef struct
869 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
870 DWORD size; /* 0x04 */
871 DWORD uk1; /* 0x08 */
872 DWORD uk2; /* 0x0c */
873 DWORD uk3; /* 0x10 */
874 DWORD uk4; /* 0x14 */
875 DWORD uk5; /* 0x18 */
876 DWORD uk6; /* 0x1c */
877 /* dkh */
878 } _w95rgdb;
880 /* Disk Key Header structure (RGDB part), once per key */
881 typedef struct
883 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
884 WORD nrLS; /* 0x04 id inside the rgdb block */
885 WORD nrMS; /* 0x06 number of the rgdb block */
886 DWORD bytesused; /* 0x08 */
887 WORD keynamelen; /* 0x0c len of name */
888 WORD values; /* 0x0e number of values */
889 DWORD xx1; /* 0x10 */
890 char name[1]; /* 0x14 */
891 /* dkv */ /* 0x14 + keynamelen */
892 } _w95dkh;
894 /* Disk Key Value structure, once per value */
895 typedef struct
897 DWORD type; /* 0x00 */
898 DWORD x1; /* 0x04 */
899 WORD valnamelen; /* 0x08 length of name, 0 is default key */
900 WORD valdatalen; /* 0x0A length of data */
901 char name[1]; /* 0x0c */
902 /* raw data */ /* 0x0c + valnamelen */
903 } _w95dkv;
905 /******************************************************************************
906 * _w95_lookup_dkh [Internal]
908 * seeks the dkh belonging to a dke
910 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
912 _w95rgdb * rgdb;
913 _w95dkh * dkh;
914 int i;
916 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
917 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
919 /* find the right block */
920 for(i=0; i<nrMS ;i++)
922 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
923 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
926 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
930 if(nrLS==dkh->nrLS ) return dkh;
931 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
932 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
934 return NULL;
937 /******************************************************************************
938 * _w95_parse_dkv [Internal]
940 static int _w95_parse_dkv (
941 HKEY hkey,
942 _w95dkh * dkh,
943 int nrLS,
944 int nrMS )
946 _w95dkv * dkv;
947 int i;
948 DWORD ret;
949 char * name;
951 /* first value block */
952 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
954 /* loop trought the values */
955 for (i=0; i< dkh->values; i++)
957 name = _strdupnA(dkv->name, dkv->valnamelen+1);
958 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
959 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
960 free (name);
962 /* next value */
963 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
965 return TRUE;
968 /******************************************************************************
969 * _w95_parse_dke [Internal]
971 static int _w95_parse_dke(
972 HKEY hkey,
973 _w95creg * creg,
974 _w95rgkn *rgkn,
975 _w95dke * dke,
976 int level )
978 _w95dkh * dkh;
979 HKEY hsubkey = hkey;
980 char * name;
981 int ret = FALSE;
983 /* get start address of root key block */
984 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
986 /* special root key */
987 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
989 /* parse the one subkey*/
990 if (dke->nextsub != 0xffffffff)
992 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
994 /* has no sibling keys */
995 goto error;
998 /* search subblock */
999 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1001 fprintf(stderr, "dke pointing to missing dkh !\n");
1002 goto error;
1005 if ( level <= 0 )
1007 /* walk sibling keys */
1008 if (dke->next != 0xffffffff )
1010 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1013 /* create subkey and insert values */
1014 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1015 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1016 free(name);
1017 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1020 /* next sub key */
1021 if (dke->nextsub != 0xffffffff)
1023 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1026 ret = TRUE;
1027 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1028 error: return ret;
1030 /* end windows 95 loader */
1032 /******************************************************************************
1033 * NativeRegLoadKey [Internal]
1035 * Loads a native registry file (win95/nt)
1036 * hkey root key
1037 * fn filename
1038 * level number of levels to cut away (eg. ".Default" in user.dat)
1040 * this function intentionally uses unix file functions to make it possible
1041 * to move it to a seperate registry helper programm
1043 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1045 int fd = 0;
1046 struct stat st;
1047 DOS_FULL_NAME full_name;
1048 int ret = FALSE;
1049 void * base;
1051 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1053 /* map the registry into the memory */
1054 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1055 if ((fstat(fd, &st) == -1)) goto error;
1056 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1058 switch (*(LPDWORD)base)
1060 /* windows 95 'creg' */
1061 case W95_REG_CREG_ID:
1063 _w95creg * creg;
1064 _w95rgkn * rgkn;
1065 creg = base;
1066 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1068 /* load the header (rgkn) */
1069 rgkn = (_w95rgkn*)(creg + 1);
1070 if (rgkn->id != W95_REG_RGKN_ID)
1072 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1073 goto error1;
1076 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1078 break;
1079 /* nt 'regf'*/
1080 case NT_REG_HEADER_BLOCK_ID:
1082 nt_regf * regf;
1083 nt_hbin * hbin;
1084 nt_hbin_sub * hbin_sub;
1085 nt_nk* nk;
1087 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1089 /* start block */
1090 regf = base;
1092 /* hbin block */
1093 hbin = (nt_hbin *) ((char *) base + 0x1000);
1094 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1096 ERR_(reg)( "%s hbin block invalid\n", fn);
1097 goto error1;
1100 /* hbin_sub block */
1101 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1102 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1104 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1105 goto error1;
1108 /* nk block */
1109 nk = (nt_nk*)&(hbin_sub->data[0]);
1110 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1112 ERR_(reg)( "%s special nk block not found\n", fn);
1113 goto error1;
1116 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1118 break;
1119 default:
1121 ERR("unknown signature in registry file %s.\n",fn);
1122 goto error1;
1125 if(!ret) ERR("error loading registry file %s\n", fn);
1126 error1: munmap(base, st.st_size);
1127 error: close(fd);
1128 return ret;
1131 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1133 reghack - windows 3.11 registry data format demo program.
1135 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1136 a combined hash table and tree description, and finally a text table.
1138 The header is obvious from the struct header. The taboff1 and taboff2
1139 fields are always 0x20, and their usage is unknown.
1141 The 8-byte entry table has various entry types.
1143 tabent[0] is a root index. The second word has the index of the root of
1144 the directory.
1145 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1146 the index of the key/value that has that hash. Data with the same
1147 hash value are on a circular list. The other three words in the
1148 hash entry are always zero.
1149 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1150 entry: dirent and keyent/valent. They are identified by context.
1151 tabent[freeidx] is the first free entry. The first word in a free entry
1152 is the index of the next free entry. The last has 0 as a link.
1153 The other three words in the free list are probably irrelevant.
1155 Entries in text table are preceeded by a word at offset-2. This word
1156 has the value (2*index)+1, where index is the referring keyent/valent
1157 entry in the table. I have no suggestion for the 2* and the +1.
1158 Following the word, there are N bytes of data, as per the keyent/valent
1159 entry length. The offset of the keyent/valent entry is from the start
1160 of the text table to the first data byte.
1162 This information is not available from Microsoft. The data format is
1163 deduced from the reg.dat file by me. Mistakes may
1164 have been made. I claim no rights and give no guarantees for this program.
1166 Tor Sjøwall, tor@sn.no
1169 /* reg.dat header format */
1170 struct _w31_header {
1171 char cookie[8]; /* 'SHCC3.10' */
1172 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1173 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1174 unsigned long tabcnt; /* number of entries in index table */
1175 unsigned long textoff; /* offset of text part */
1176 unsigned long textsize; /* byte size of text part */
1177 unsigned short hashsize; /* hash size */
1178 unsigned short freeidx; /* free index */
1181 /* generic format of table entries */
1182 struct _w31_tabent {
1183 unsigned short w0, w1, w2, w3;
1186 /* directory tabent: */
1187 struct _w31_dirent {
1188 unsigned short sibling_idx; /* table index of sibling dirent */
1189 unsigned short child_idx; /* table index of child dirent */
1190 unsigned short key_idx; /* table index of key keyent */
1191 unsigned short value_idx; /* table index of value valent */
1194 /* key tabent: */
1195 struct _w31_keyent {
1196 unsigned short hash_idx; /* hash chain index for string */
1197 unsigned short refcnt; /* reference count */
1198 unsigned short length; /* length of string */
1199 unsigned short string_off; /* offset of string in text table */
1202 /* value tabent: */
1203 struct _w31_valent {
1204 unsigned short hash_idx; /* hash chain index for string */
1205 unsigned short refcnt; /* reference count */
1206 unsigned short length; /* length of string */
1207 unsigned short string_off; /* offset of string in text table */
1210 /* recursive helper function to display a directory tree */
1211 void
1212 __w31_dumptree( unsigned short idx,
1213 unsigned char *txt,
1214 struct _w31_tabent *tab,
1215 struct _w31_header *head,
1216 HKEY hkey,
1217 time_t lastmodified,
1218 int level
1220 struct _w31_dirent *dir;
1221 struct _w31_keyent *key;
1222 struct _w31_valent *val;
1223 HKEY subkey = 0;
1224 static char tail[400];
1226 while (idx!=0) {
1227 dir=(struct _w31_dirent*)&tab[idx];
1229 if (dir->key_idx) {
1230 key = (struct _w31_keyent*)&tab[dir->key_idx];
1232 memcpy(tail,&txt[key->string_off],key->length);
1233 tail[key->length]='\0';
1234 /* all toplevel entries AND the entries in the
1235 * toplevel subdirectory belong to \SOFTWARE\Classes
1237 if (!level && !lstrcmpA(tail,".classes")) {
1238 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1239 idx=dir->sibling_idx;
1240 continue;
1242 if (subkey) RegCloseKey( subkey );
1243 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1244 /* only add if leaf node or valued node */
1245 if (dir->value_idx!=0||dir->child_idx==0) {
1246 if (dir->value_idx) {
1247 val=(struct _w31_valent*)&tab[dir->value_idx];
1248 memcpy(tail,&txt[val->string_off],val->length);
1249 tail[val->length]='\0';
1250 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1253 } else {
1254 TRACE("strange: no directory key name, idx=%04x\n", idx);
1256 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1257 idx=dir->sibling_idx;
1259 if (subkey) RegCloseKey( subkey );
1263 /******************************************************************************
1264 * _w31_loadreg [Internal]
1266 void _w31_loadreg(void) {
1267 HFILE hf;
1268 struct _w31_header head;
1269 struct _w31_tabent *tab;
1270 unsigned char *txt;
1271 int len;
1272 OFSTRUCT ofs;
1273 BY_HANDLE_FILE_INFORMATION hfinfo;
1274 time_t lastmodified;
1276 TRACE("(void)\n");
1278 hf = OpenFile("reg.dat",&ofs,OF_READ);
1279 if (hf==HFILE_ERROR)
1280 return;
1282 /* read & dump header */
1283 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1284 ERR("reg.dat is too short.\n");
1285 _lclose(hf);
1286 return;
1288 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1289 ERR("reg.dat has bad signature.\n");
1290 _lclose(hf);
1291 return;
1294 len = head.tabcnt * sizeof(struct _w31_tabent);
1295 /* read and dump index table */
1296 tab = xmalloc(len);
1297 if (len!=_lread(hf,tab,len)) {
1298 ERR("couldn't read %d bytes.\n",len);
1299 free(tab);
1300 _lclose(hf);
1301 return;
1304 /* read text */
1305 txt = xmalloc(head.textsize);
1306 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1307 ERR("couldn't seek to textblock.\n");
1308 free(tab);
1309 free(txt);
1310 _lclose(hf);
1311 return;
1313 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1314 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1315 free(tab);
1316 free(txt);
1317 _lclose(hf);
1318 return;
1321 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1322 ERR("GetFileInformationByHandle failed?.\n");
1323 free(tab);
1324 free(txt);
1325 _lclose(hf);
1326 return;
1328 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1329 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1330 free(tab);
1331 free(txt);
1332 _lclose(hf);
1333 return;
1337 /* configure save files and start the periodic saving timer */
1338 static void SHELL_InitRegistrySaving(void)
1340 struct set_registry_levels_request *req = get_req_buffer();
1342 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1343 int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
1344 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1346 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1347 req->current = 1;
1348 req->saving = !all;
1349 req->version = version;
1350 req->period = period * 1000;
1351 server_call( REQ_SET_REGISTRY_LEVELS );
1353 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1355 struct save_registry_atexit_request *req = get_req_buffer();
1356 const char *confdir = get_config_dir();
1357 char *str = req->file + strlen(confdir);
1359 if (str + 20 > req->file + server_remaining(req->file))
1361 ERR("config dir '%s' too long\n", confdir );
1362 return;
1365 strcpy( req->file, confdir );
1366 strcpy( str, "/" SAVE_CURRENT_USER );
1367 req->hkey = HKEY_CURRENT_USER;
1368 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1370 strcpy( req->file, confdir );
1371 strcpy( str, "/" SAVE_LOCAL_MACHINE );
1372 req->hkey = HKEY_LOCAL_MACHINE;
1373 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1375 strcpy( req->file, confdir );
1376 strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1377 req->hkey = HKEY_USERS;
1378 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1383 /**********************************************************************************
1384 * SetLoadLevel [Internal]
1386 * set level to 0 for loading system files
1387 * set level to 1 for loading user files
1389 static void SetLoadLevel(int level)
1391 struct set_registry_levels_request *req = get_req_buffer();
1393 req->current = level;
1394 req->saving = 0;
1395 req->version = 1;
1396 req->period = 0;
1397 server_call( REQ_SET_REGISTRY_LEVELS );
1400 /**********************************************************************************
1401 * SHELL_LoadRegistry [Internal]
1403 #define REG_DONTLOAD -1
1404 #define REG_WIN31 0
1405 #define REG_WIN95 1
1406 #define REG_WINNT 2
1408 void SHELL_LoadRegistry( void )
1410 HKEY hkey;
1411 char windir[MAX_PATHNAME_LEN];
1412 char path[MAX_PATHNAME_LEN];
1413 int systemtype = REG_WIN31;
1415 TRACE("(void)\n");
1417 if (!CLIENT_IsBootThread()) return; /* already loaded */
1419 REGISTRY_Init();
1420 SetLoadLevel(0);
1422 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1424 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1426 /* test %windir%/system32/config/system --> winnt */
1427 strcpy(path, windir);
1428 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1429 if(GetFileAttributesA(path) != -1)
1431 systemtype = REG_WINNT;
1433 else
1435 /* test %windir%/system.dat --> win95 */
1436 strcpy(path, windir);
1437 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1438 if(GetFileAttributesA(path) != -1)
1440 systemtype = REG_WIN95;
1444 if ((systemtype==REG_WINNT)
1445 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1447 MESSAGE("When you are running with a native NT directory specify\n");
1448 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1449 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1450 systemtype = REG_DONTLOAD;
1453 else
1455 /* only wine registry */
1456 systemtype = REG_DONTLOAD;
1459 switch (systemtype)
1461 case REG_WIN31:
1462 _w31_loadreg();
1463 break;
1465 case REG_WIN95:
1466 /* Load windows 95 entries */
1467 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1469 strcpy(path, windir);
1470 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1471 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1473 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1475 /* user specific user.dat */
1476 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1477 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1479 MESSAGE("can't load win95 user-registry %s\n", path);
1480 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1482 /* default user.dat */
1483 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1485 strcpy(path, windir);
1486 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1487 NativeRegLoadKey(hkey, path, 1);
1488 RegCloseKey(hkey);
1491 else
1493 /* global user.dat */
1494 strcpy(path, windir);
1495 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1496 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1498 break;
1500 case REG_WINNT:
1501 /* default user.dat */
1502 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1504 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1505 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1507 MESSAGE("can't load NT user-registry %s\n", path);
1508 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1512 /* default user.dat */
1513 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1515 strcpy(path, windir);
1516 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1517 NativeRegLoadKey(hkey, path, 1);
1518 RegCloseKey(hkey);
1522 * FIXME
1523 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1526 strcpy(path, windir);
1527 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1528 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1530 strcpy(path, windir);
1531 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1532 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1534 strcpy(path, windir);
1535 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1536 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1538 strcpy(path, windir);
1539 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1540 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1542 /* this key is generated when the nt-core booted successfully */
1543 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1544 RegCloseKey(hkey);
1545 break;
1546 } /* switch */
1548 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1551 * Load the global HKU hive directly from sysconfdir
1553 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1556 * Load the global machine defaults directly form sysconfdir
1558 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1561 SetLoadLevel(1);
1564 * Load the user saved registries
1566 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1568 const char *confdir = get_config_dir();
1569 int len = strlen(confdir) + 20;
1570 char *fn = path;
1572 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1574 * Load user's personal versions of global HKU/.Default keys
1576 if (fn)
1578 char *str;
1579 strcpy( fn, confdir );
1580 str = fn + strlen(fn);
1581 *str++ = '/';
1583 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1584 _wine_loadreg( HKEY_USERS, fn );
1586 strcpy( str, SAVE_CURRENT_USER );
1587 _wine_loadreg( HKEY_CURRENT_USER, fn );
1589 strcpy( str, SAVE_LOCAL_MACHINE );
1590 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1592 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1596 SHELL_InitRegistrySaving();
1599 /********************* API FUNCTIONS ***************************************/
1604 /******************************************************************************
1605 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1606 * Immediately writes key to registry.
1607 * Only returns after data has been written to disk.
1609 * FIXME: does it really wait until data is written ?
1611 * PARAMS
1612 * hkey [I] Handle of key to write
1614 * RETURNS
1615 * Success: ERROR_SUCCESS
1616 * Failure: Error code
1618 DWORD WINAPI RegFlushKey( HKEY hkey )
1620 FIXME( "(%x): stub\n", hkey );
1621 return ERROR_SUCCESS;
1624 /******************************************************************************
1625 * RegConnectRegistryW [ADVAPI32.128]
1627 * PARAMS
1628 * lpMachineName [I] Address of name of remote computer
1629 * hHey [I] Predefined registry handle
1630 * phkResult [I] Address of buffer for remote registry handle
1632 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1633 LPHKEY phkResult )
1635 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1637 if (!lpMachineName || !*lpMachineName) {
1638 /* Use the local machine name */
1639 return RegOpenKey16( hKey, "", phkResult );
1642 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1643 return ERROR_BAD_NETPATH;
1647 /******************************************************************************
1648 * RegConnectRegistryA [ADVAPI32.127]
1650 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1652 DWORD ret;
1653 LPWSTR machineW = strdupA2W(machine);
1654 ret = RegConnectRegistryW( machineW, hkey, reskey );
1655 free(machineW);
1656 return ret;
1660 /******************************************************************************
1661 * RegGetKeySecurity [ADVAPI32.144]
1662 * Retrieves a copy of security descriptor protecting the registry key
1664 * PARAMS
1665 * hkey [I] Open handle of key to set
1666 * SecurityInformation [I] Descriptor contents
1667 * pSecurityDescriptor [O] Address of descriptor for key
1668 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1670 * RETURNS
1671 * Success: ERROR_SUCCESS
1672 * Failure: Error code
1674 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1675 SECURITY_INFORMATION SecurityInformation,
1676 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1677 LPDWORD lpcbSecurityDescriptor )
1679 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1680 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1682 /* FIXME: Check for valid SecurityInformation values */
1684 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1685 return ERROR_INSUFFICIENT_BUFFER;
1687 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1688 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1690 return ERROR_SUCCESS;
1694 /******************************************************************************
1695 * RegNotifyChangeKeyValue [ADVAPI32.???]
1697 * PARAMS
1698 * hkey [I] Handle of key to watch
1699 * fWatchSubTree [I] Flag for subkey notification
1700 * fdwNotifyFilter [I] Changes to be reported
1701 * hEvent [I] Handle of signaled event
1702 * fAsync [I] Flag for asynchronous reporting
1704 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1705 DWORD fdwNotifyFilter, HANDLE hEvent,
1706 BOOL fAsync )
1708 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1709 hEvent,fAsync);
1710 return ERROR_SUCCESS;
1714 /******************************************************************************
1715 * RegUnLoadKeyW [ADVAPI32.173]
1717 * PARAMS
1718 * hkey [I] Handle of open key
1719 * lpSubKey [I] Address of name of subkey to unload
1721 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1723 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1724 return ERROR_SUCCESS;
1728 /******************************************************************************
1729 * RegUnLoadKeyA [ADVAPI32.172]
1731 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1733 LONG ret;
1734 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1735 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1736 if(lpSubKeyW) free(lpSubKeyW);
1737 return ret;
1741 /******************************************************************************
1742 * RegSetKeySecurity [ADVAPI32.167]
1744 * PARAMS
1745 * hkey [I] Open handle of key to set
1746 * SecurityInfo [I] Descriptor contents
1747 * pSecurityDesc [I] Address of descriptor for key
1749 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1750 PSECURITY_DESCRIPTOR pSecurityDesc )
1752 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1754 /* It seems to perform this check before the hkey check */
1755 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1756 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1757 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1758 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1759 /* Param OK */
1760 } else
1761 return ERROR_INVALID_PARAMETER;
1763 if (!pSecurityDesc)
1764 return ERROR_INVALID_PARAMETER;
1766 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1768 return ERROR_SUCCESS;
1772 /******************************************************************************
1773 * RegRestoreKeyW [ADVAPI32.164]
1775 * PARAMS
1776 * hkey [I] Handle of key where restore begins
1777 * lpFile [I] Address of filename containing saved tree
1778 * dwFlags [I] Optional flags
1780 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1782 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1784 /* It seems to do this check before the hkey check */
1785 if (!lpFile || !*lpFile)
1786 return ERROR_INVALID_PARAMETER;
1788 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1790 /* Check for file existence */
1792 return ERROR_SUCCESS;
1796 /******************************************************************************
1797 * RegRestoreKeyA [ADVAPI32.163]
1799 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1801 LONG ret;
1802 LPWSTR lpFileW = strdupA2W(lpFile);
1803 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1804 if(lpFileW) free(lpFileW);
1805 return ret;
1809 /******************************************************************************
1810 * RegReplaceKeyW [ADVAPI32.162]
1812 * PARAMS
1813 * hkey [I] Handle of open key
1814 * lpSubKey [I] Address of name of subkey
1815 * lpNewFile [I] Address of filename for file with new data
1816 * lpOldFile [I] Address of filename for backup file
1818 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1819 LPCWSTR lpOldFile )
1821 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1822 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1823 return ERROR_SUCCESS;
1827 /******************************************************************************
1828 * RegReplaceKeyA [ADVAPI32.161]
1830 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1831 LPCSTR lpOldFile )
1833 LONG ret;
1834 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1835 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1836 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1837 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1838 free(lpOldFileW);
1839 free(lpNewFileW);
1840 free(lpSubKeyW);
1841 return ret;
1849 /* 16-bit functions */
1851 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1852 * some programs. Do not remove those cases. -MM
1854 static inline void fix_win16_hkey( HKEY *hkey )
1856 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1859 /******************************************************************************
1860 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1862 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1864 fix_win16_hkey( &hkey );
1865 return RegEnumKeyA( hkey, index, name, name_len );
1868 /******************************************************************************
1869 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1871 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1873 fix_win16_hkey( &hkey );
1874 return RegOpenKeyA( hkey, name, retkey );
1877 /******************************************************************************
1878 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1880 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1882 fix_win16_hkey( &hkey );
1883 return RegCreateKeyA( hkey, name, retkey );
1886 /******************************************************************************
1887 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1889 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1891 fix_win16_hkey( &hkey );
1892 return RegDeleteKeyA( hkey, name );
1895 /******************************************************************************
1896 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1898 DWORD WINAPI RegCloseKey16( HKEY hkey )
1900 fix_win16_hkey( &hkey );
1901 return RegCloseKey( hkey );
1904 /******************************************************************************
1905 * RegSetValue16 [KERNEL.221] [SHELL.5]
1907 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1909 fix_win16_hkey( &hkey );
1910 return RegSetValueA( hkey, name, type, data, count );
1913 /******************************************************************************
1914 * RegDeleteValue16 [KERNEL.222]
1916 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1918 fix_win16_hkey( &hkey );
1919 return RegDeleteValueA( hkey, name );
1922 /******************************************************************************
1923 * RegEnumValue16 [KERNEL.223]
1925 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1926 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1928 fix_win16_hkey( &hkey );
1929 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1932 /******************************************************************************
1933 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1935 * NOTES
1936 * Is this HACK still applicable?
1938 * HACK
1939 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1940 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1941 * Aldus FH4)
1943 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1945 fix_win16_hkey( &hkey );
1946 if (count) *count &= 0xffff;
1947 return RegQueryValueA( hkey, name, data, count );
1950 /******************************************************************************
1951 * RegQueryValueEx16 [KERNEL.225]
1953 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1954 LPBYTE data, LPDWORD count )
1956 fix_win16_hkey( &hkey );
1957 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1960 /******************************************************************************
1961 * RegSetValueEx16 [KERNEL.226]
1963 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1964 CONST BYTE *data, DWORD count )
1966 fix_win16_hkey( &hkey );
1967 return RegSetValueExA( hkey, name, reserved, type, data, count );