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.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
29 #include <sys/types.h>
35 #include "debugtools.h"
39 #ifdef HAVE_SYS_MMAN_H
40 # include <sys/mman.h>
45 DEFAULT_DEBUG_CHANNEL(reg
);
47 /* FIXME: following defines should be configured global */
48 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
49 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
51 /* relative in ~user/.wine/ : */
52 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
53 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
54 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
56 /* _xmalloc [Internal] */
57 static void *_xmalloc( size_t size
)
61 res
= malloc (size
? size
: 1);
63 WARN("Virtual memory exhausted.\n");
69 /* _strdupnA [Internal] */
70 static LPSTR
_strdupnA(LPCSTR str
,size_t len
)
74 if (!str
) return NULL
;
75 ret
= _xmalloc( len
+ 1 );
76 memcpy( ret
, str
, len
);
81 /* convert ansi string to unicode [Internal] */
82 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
87 if (!strA
) return NULL
;
88 lenW
= MultiByteToWideChar(CP_ACP
,0,strA
,lenA
,NULL
,0);
89 ret
= _xmalloc(lenW
*sizeof(WCHAR
)+sizeof(WCHAR
));
90 MultiByteToWideChar(CP_ACP
,0,strA
,lenA
,ret
,lenW
);
95 /* dump a Unicode string with proper escaping [Internal] */
96 /* FIXME: this code duplicates server/unicode.c */
97 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,char escape
[2])
99 static const char escapes
[32] = ".......abtnvfr.............e....";
104 for (; len
; str
++, len
--)
106 if (pos
> buffer
+ sizeof(buffer
) - 8)
108 fwrite( buffer
, pos
- buffer
, 1, f
);
109 count
+= pos
- buffer
;
112 if (*str
> 127) /* hex escape */
114 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
115 pos
+= sprintf( pos
, "\\x%04x", *str
);
117 pos
+= sprintf( pos
, "\\x%x", *str
);
120 if (*str
< 32) /* octal or C escape */
122 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
123 if (escapes
[*str
] != '.')
124 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
125 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
126 pos
+= sprintf( pos
, "\\%03o", *str
);
128 pos
+= sprintf( pos
, "\\%o", *str
);
131 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
134 fwrite( buffer
, pos
- buffer
, 1, f
);
135 count
+= pos
- buffer
;
139 /* convert ansi string to unicode and dump with proper escaping [Internal] */
140 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,char escape
[2])
145 if (strA
== NULL
) return 0;
146 strW
= _strdupnAtoW(strA
,len
);
147 ret
= _dump_strW(strW
,len
,f
,escape
);
153 /* FIXME: this code duplicates server/registry.c */
155 WCHAR
*nameW
; /* value name */
156 int type
; /* value type */
157 size_t len
; /* value data length in bytes */
158 void *data
; /* pointer to value data */
161 /* dump a value to a text file */
162 /* FIXME: this code duplicates server/registry.c */
163 static void _dump_value(struct key_value
*value
,FILE *f
)
167 if (value
->nameW
[0]) {
169 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
170 count
+= fprintf( f
, "\"=" );
172 else count
= fprintf( f
, "@=" );
174 switch(value
->type
) {
178 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
180 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
184 if (value
->len
== sizeof(DWORD
)) {
186 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
187 fprintf( f
, "dword:%08lx", dw
);
190 /* else fall through */
192 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
193 else count
+= fprintf( f
, "hex(%x):", value
->type
);
194 for (i
= 0; i
< value
->len
; i
++) {
195 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
196 if (i
< value
->len
-1) {
199 fprintf( f
, "\\\n " );
209 /******************************************************************/
210 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
212 reghack - windows 3.11 registry data format demo program.
214 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
215 a combined hash table and tree description, and finally a text table.
217 The header is obvious from the struct header. The taboff1 and taboff2
218 fields are always 0x20, and their usage is unknown.
220 The 8-byte entry table has various entry types.
222 tabent[0] is a root index. The second word has the index of the root of
224 tabent[1..hashsize] is a hash table. The first word in the hash entry is
225 the index of the key/value that has that hash. Data with the same
226 hash value are on a circular list. The other three words in the
227 hash entry are always zero.
228 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
229 entry: dirent and keyent/valent. They are identified by context.
230 tabent[freeidx] is the first free entry. The first word in a free entry
231 is the index of the next free entry. The last has 0 as a link.
232 The other three words in the free list are probably irrelevant.
234 Entries in text table are preceded by a word at offset-2. This word
235 has the value (2*index)+1, where index is the referring keyent/valent
236 entry in the table. I have no suggestion for the 2* and the +1.
237 Following the word, there are N bytes of data, as per the keyent/valent
238 entry length. The offset of the keyent/valent entry is from the start
239 of the text table to the first data byte.
241 This information is not available from Microsoft. The data format is
242 deduced from the reg.dat file by me. Mistakes may
243 have been made. I claim no rights and give no guarantees for this program.
245 Tor Sjøwall, tor@sn.no
248 /* reg.dat header format */
250 char cookie
[8]; /* 'SHCC3.10' */
251 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
252 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
253 unsigned long tabcnt
; /* number of entries in index table */
254 unsigned long textoff
; /* offset of text part */
255 unsigned long textsize
; /* byte size of text part */
256 unsigned short hashsize
; /* hash size */
257 unsigned short freeidx
; /* free index */
260 /* generic format of table entries */
262 unsigned short w0
, w1
, w2
, w3
;
265 /* directory tabent: */
267 unsigned short sibling_idx
; /* table index of sibling dirent */
268 unsigned short child_idx
; /* table index of child dirent */
269 unsigned short key_idx
; /* table index of key keyent */
270 unsigned short value_idx
; /* table index of value valent */
275 unsigned short hash_idx
; /* hash chain index for string */
276 unsigned short refcnt
; /* reference count */
277 unsigned short length
; /* length of string */
278 unsigned short string_off
; /* offset of string in text table */
283 unsigned short hash_idx
; /* hash chain index for string */
284 unsigned short refcnt
; /* reference count */
285 unsigned short length
; /* length of string */
286 unsigned short string_off
; /* offset of string in text table */
289 /* recursive helper function to display a directory tree [Internal] */
290 void _w31_dumptree(unsigned short idx
,unsigned char *txt
,struct _w31_tabent
*tab
,struct _w31_header
*head
,HKEY hkey
,time_t lastmodified
, int level
)
292 struct _w31_dirent
*dir
;
293 struct _w31_keyent
*key
;
294 struct _w31_valent
*val
;
296 static char tail
[400];
299 dir
=(struct _w31_dirent
*)&tab
[idx
];
302 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
304 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
305 tail
[key
->length
]='\0';
306 /* all toplevel entries AND the entries in the
307 * toplevel subdirectory belong to \SOFTWARE\Classes
309 if (!level
&& !strcmp(tail
,".classes")) {
310 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
311 idx
=dir
->sibling_idx
;
314 if (subkey
) RegCloseKey( subkey
);
315 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
316 /* only add if leaf node or valued node */
317 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
318 if (dir
->value_idx
) {
319 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
320 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
321 tail
[val
->length
]='\0';
322 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
325 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
326 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
327 idx
=dir
->sibling_idx
;
329 if (subkey
) RegCloseKey( subkey
);
333 /******************************************************************************
334 * _w31_loadreg [Internal]
336 void _w31_loadreg(void)
339 struct _w31_header head
;
340 struct _w31_tabent
*tab
;
344 BY_HANDLE_FILE_INFORMATION hfinfo
;
349 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
350 if (hf
==HFILE_ERROR
) return;
352 /* read & dump header */
353 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
354 ERR("reg.dat is too short.\n");
358 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
359 ERR("reg.dat has bad signature.\n");
364 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
365 /* read and dump index table */
367 if (len
!=_lread(hf
,tab
,len
)) {
368 ERR("couldn't read %d bytes.\n",len
);
375 txt
= _xmalloc(head
.textsize
);
376 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
377 ERR("couldn't seek to textblock.\n");
383 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
384 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
391 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
392 ERR("GetFileInformationByHandle failed?.\n");
398 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
399 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
406 /***********************************************************************************/
407 /* windows 95 registry loader */
408 /***********************************************************************************/
410 /* SECTION 1: main header
414 #define W95_REG_CREG_ID 0x47455243
417 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
418 DWORD version
; /* ???? 0x00010000 */
419 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
420 DWORD uk2
; /* 0x0c */
421 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
427 /* SECTION 2: Directory information (tree structure)
429 * once on offset 0x20
431 * structure: [rgkn][dke]* (repeat till last_dke is reached)
433 #define W95_REG_RGKN_ID 0x4e4b4752
436 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
437 DWORD size
; /* Size of the RGKN-block */
438 DWORD root_off
; /* Rel. Offset of the root-record */
439 DWORD last_dke
; /* Offset to last DKE ? */
443 /* Disk Key Entry Structure
445 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
446 * hive itself. It looks the same like other keys. Even the ID-number can
449 * The "hash"-value is a value representing the key's name. Windows will not
450 * search for the name, but for a matching hash-value. if it finds one, it
451 * will compare the actual string info, otherwise continue with the next key.
452 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
453 * of the string which are smaller than 0x80 (128) to this D-Word.
455 * If you want to modify key names, also modify the hash-values, since they
456 * cannot be found again (although they would be displayed in REGEDIT)
457 * End of list-pointers are filled with 0xFFFFFFFF
459 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
460 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
461 * structure) and reading another RGDB_section.
463 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
464 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
465 * The remaining space between last_dke and the offset calculated from
466 * rgkn->size seems to be free for use for more dke:s.
467 * So it seems if more dke:s are added, they are added to that space and
468 * last_dke is grown, and in case that "free" space is out, the space
469 * gets grown and rgkn->size gets adjusted.
471 * there is a one to one relationship between dke and dkh
473 /* key struct, once per key */
475 DWORD x1
; /* Free entry indicator(?) */
476 DWORD hash
; /* sum of bytes of keyname */
477 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
478 DWORD prevlvl
; /* offset of previous key */
479 DWORD nextsub
; /* offset of child key */
480 DWORD next
; /* offset of sibling key */
481 WORD nrLS
; /* id inside the rgdb block */
482 WORD nrMS
; /* number of the rgdb block */
485 /* SECTION 3: key information, values and data
488 * section: [blocks]* (repeat creg->rgdb_num times)
489 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
490 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
492 * An interesting relationship exists in RGDB_section. The DWORD value
493 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
494 * I have no idea at the moment what this means. (Kevin Cozens)
497 /* block header, once per block */
498 #define W95_REG_RGDB_ID 0x42444752
501 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
502 DWORD size
; /* 0x04 */
503 DWORD uk1
; /* 0x08 */
504 DWORD uk2
; /* 0x0c */
505 DWORD uk3
; /* 0x10 */
506 DWORD uk4
; /* 0x14 */
507 DWORD uk5
; /* 0x18 */
508 DWORD uk6
; /* 0x1c */
512 /* Disk Key Header structure (RGDB part), once per key */
514 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
515 WORD nrLS
; /* 0x04 id inside the rgdb block */
516 WORD nrMS
; /* 0x06 number of the rgdb block */
517 DWORD bytesused
; /* 0x08 */
518 WORD keynamelen
; /* 0x0c len of name */
519 WORD values
; /* 0x0e number of values */
520 DWORD xx1
; /* 0x10 */
521 char name
[1]; /* 0x14 */
522 /* dkv */ /* 0x14 + keynamelen */
525 /* Disk Key Value structure, once per value */
527 DWORD type
; /* 0x00 */
529 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
530 WORD valdatalen
; /* 0x0A length of data */
531 char name
[1]; /* 0x0c */
532 /* raw data */ /* 0x0c + valnamelen */
535 /******************************************************************************
536 * _w95_lookup_dkh [Internal]
538 * seeks the dkh belonging to a dke
540 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
546 /* get the beginning of the rgdb datastore */
547 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
549 /* check: requested block < last_block) */
550 if (creg
->rgdb_num
<= nrMS
) {
551 ERR("registry file corrupt! requested block no. beyond end.\n");
555 /* find the right block */
556 for(i
=0; i
<nrMS
;i
++) {
557 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
558 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
561 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
564 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
567 if(nrLS
==dkh
->nrLS
) return dkh
;
568 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
569 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
575 /******************************************************************************
576 * _w95_dump_dkv [Internal]
578 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
583 /* first value block */
584 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
586 /* loop trought the values */
587 for (i
=0; i
< dkh
->values
; i
++) {
588 struct key_value value
;
591 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
592 value
.type
= dkv
->type
;
593 value
.len
= dkv
->valdatalen
;
595 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
597 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
598 pdata
= _strdupnAtoW(value
.data
,value
.len
);
601 if (pdata
!= NULL
) value
.data
= pdata
;
603 _dump_value(&value
,f
);
605 if (pdata
!= NULL
) free(pdata
);
608 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
613 /******************************************************************************
614 * _w95_dump_dke [Internal]
616 static int _w95_dump_dke(LPSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
619 LPSTR new_key_name
= NULL
;
621 /* special root key */
622 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
624 /* parse the one subkey */
625 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
626 /* has no sibling keys */
630 /* search subblock */
631 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
632 ERR("dke pointing to missing dkh !\n");
637 /* create new subkey name */
638 new_key_name
= _strdupnA(key_name
,strlen(key_name
)+dkh
->keynamelen
+1);
639 if (strcmp(new_key_name
,"") != 0) strcat(new_key_name
,"\\");
640 strncat(new_key_name
,dkh
->name
,dkh
->keynamelen
);
642 /* walk sibling keys */
643 if (dke
->next
!= 0xffffffff ) {
644 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
650 /* write the key path (something like [Software\\Microsoft\\..]) only if:
651 1) key has some values
652 2) key has no values and no subkeys
654 if (dkh
->values
> 0) {
655 /* there are some values */
657 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
659 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
664 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
665 /* no subkeys and no values */
667 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
670 } else new_key_name
= _strdupnA(key_name
,strlen(key_name
));
673 if (dke
->nextsub
!= 0xffffffff) {
674 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
683 /* end windows 95 loader */
685 /***********************************************************************************/
686 /* windows NT registry loader */
687 /***********************************************************************************/
689 /* NT REGISTRY LOADER */
691 #ifdef HAVE_SYS_MMAN_H
692 # include <sys/mman.h>
696 #define MAP_FAILED ((LPVOID)-1)
699 #define NT_REG_BLOCK_SIZE 0x1000
701 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
702 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
703 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
704 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
706 /* subblocks of nk */
707 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
708 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
709 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
711 #define NT_REG_KEY_BLOCK_TYPE 0x20
712 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
715 DWORD id
; /* 0x66676572 'regf'*/
716 DWORD uk1
; /* 0x04 */
717 DWORD uk2
; /* 0x08 */
718 FILETIME DateModified
; /* 0x0c */
719 DWORD uk3
; /* 0x14 */
720 DWORD uk4
; /* 0x18 */
721 DWORD uk5
; /* 0x1c */
722 DWORD uk6
; /* 0x20 */
723 DWORD RootKeyBlock
; /* 0x24 */
724 DWORD BlockSize
; /* 0x28 */
726 DWORD Checksum
; /* at offset 0x1FC */
735 DWORD id
; /* 0x6E696268 'hbin' */
739 DWORD uk2
; /* 0x10 */
740 DWORD uk3
; /* 0x14 */
741 DWORD uk4
; /* 0x18 */
742 DWORD size
; /* 0x1C */
743 nt_hbin_sub hbin_sub
; /* 0x20 */
747 * the value_list consists of offsets to the values (vk)
750 WORD SubBlockId
; /* 0x00 0x6B6E */
751 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
752 FILETIME writetime
; /* 0x04 */
753 DWORD uk1
; /* 0x0C */
754 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
755 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
756 DWORD uk8
; /* 0x18 */
757 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
758 DWORD uk2
; /* 0x20 */
759 DWORD nr_values
; /* 0x24 number of values */
760 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
761 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
762 DWORD off_class
; /* 0x30 Offset of the Class-Name */
763 DWORD uk3
; /* 0x34 */
764 DWORD uk4
; /* 0x38 */
765 DWORD uk5
; /* 0x3c */
766 DWORD uk6
; /* 0x40 */
767 DWORD uk7
; /* 0x44 */
768 WORD name_len
; /* 0x48 name-length */
769 WORD class_len
; /* 0x4a class-name length */
770 char name
[1]; /* 0x4c key-name */
774 DWORD off_nk
; /* 0x00 */
775 DWORD name
; /* 0x04 */
779 WORD id
; /* 0x00 0x666c */
780 WORD nr_keys
; /* 0x06 */
781 hash_rec hash_rec
[1];
785 list of subkeys without hash
792 WORD id
; /* 0x00 0x696c */
798 this is a intermediate node
809 WORD id
; /* 0x00 0x6972 */
810 WORD nr_li
; /* 0x02 number off offsets */
811 DWORD off_li
[1]; /* 0x04 points to li */
815 WORD id
; /* 0x00 'vk' */
829 * 0 value is a default value
830 * 1 the value has a name
833 * len of the whole data block
835 * bytes including the terminating \0 = 2*(number_of_chars+1)
836 * - reg_dword, reg_binary:
837 * if highest bit of data_len is set data_off contains the value
839 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
841 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
842 struct key_value value
;
844 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
845 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
849 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
850 value
.type
= vk
->type
;
851 value
.len
= (vk
->data_len
& 0x7fffffff);
852 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
854 _dump_value(&value
,f
);
860 /* it's called from _nt_dump_lf() */
861 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
866 * this structure contains the hash of a keyname and points to all
869 * exception: if the id is 'il' there are no hash values and every
872 static int _nt_dump_lf(LPSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
876 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
877 if (subkeys
!= lf
->nr_keys
) goto error1
;
879 for (i
=0; i
<lf
->nr_keys
; i
++)
880 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
881 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
882 nt_li
* li
= (nt_li
*)lf
;
883 if (subkeys
!= li
->nr_keys
) goto error1
;
885 for (i
=0; i
<li
->nr_keys
; i
++)
886 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
887 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
888 nt_ri
* ri
= (nt_ri
*)lf
;
891 /* count all subkeys */
892 for (i
=0; i
<ri
->nr_li
; i
++) {
893 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
894 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
895 li_subkeys
+= li
->nr_keys
;
899 if (subkeys
!= li_subkeys
) goto error1
;
901 /* loop through the keys */
902 for (i
=0; i
<ri
->nr_li
; i
++) {
903 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
904 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
911 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
915 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
919 ERR("error reading lf block\n");
923 /* _nt_dump_nk [Internal] */
924 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
928 LPSTR new_key_name
= NULL
;
931 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
932 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
936 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
937 ERR("registry file corrupt!\n");
941 /* create the new key */
943 /* create new subkey name */
944 new_key_name
= _strdupnA(key_name
,strlen(key_name
)+nk
->name_len
+1);
945 if (strcmp(new_key_name
,"") != 0) strcat(new_key_name
,"\\");
946 strncat(new_key_name
,nk
->name
,nk
->name_len
);
948 /* write the key path (something like [Software\\Microsoft\\..]) only if:
949 1) key has some values
950 2) key has no values and no subkeys
952 if (nk
->nr_values
> 0) {
953 /* there are some values */
955 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
958 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
959 /* no subkeys and no values */
961 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
965 /* loop trough the value list */
966 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
967 for (n
=0; n
<nk
->nr_values
; n
++) {
968 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
969 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
974 } else new_key_name
= _strdupnA(key_name
,strlen(key_name
));
976 /* loop through the subkeys */
977 if (nk
->nr_subkeys
) {
978 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
979 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
991 /**********************************************************************************
992 * _set_registry_levels [Internal]
994 * set level to 0 for loading system files
995 * set level to 1 for loading user files
997 static void _set_registry_levels(int level
,int saving
,int period
)
999 SERVER_START_REQ( set_registry_levels
)
1001 req
->current
= level
;
1002 req
->saving
= saving
;
1003 req
->period
= period
;
1009 /* _save_at_exit [Internal] */
1010 static void _save_at_exit(HKEY hkey
,LPCSTR path
)
1012 LPCSTR confdir
= get_config_dir();
1013 size_t len
= strlen(confdir
) + strlen(path
) + 2;
1015 if (len
> REQUEST_MAX_VAR_SIZE
) {
1016 ERR( "config dir '%s' too long\n", confdir
);
1019 SERVER_START_VAR_REQ( save_registry_atexit
, len
)
1021 sprintf( server_data_ptr(req
), "%s/%s", confdir
, path
);
1028 /* configure save files and start the periodic saving timer [Internal] */
1029 static void _init_registry_saving( HKEY hkey_users_default
)
1034 all
= PROFILE_GetWineIniBool("registry","SaveOnlyUpdatedKeys",1);
1035 period
= PROFILE_GetWineIniInt("registry","PeriodicSave",0);
1037 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1038 _set_registry_levels(1,!all
,period
*1000);
1040 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistryFiles",1))
1042 _save_at_exit(HKEY_CURRENT_USER
,SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1043 _save_at_exit(HKEY_LOCAL_MACHINE
,SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1044 _save_at_exit(hkey_users_default
,SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1049 /******************************************************************************
1050 * _allocate_default_keys [Internal]
1051 * Registry initialisation, allocates some default keys.
1053 static void _allocate_default_keys(void) {
1059 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
1062 /* This was an Open, but since it is called before the real registries
1063 are loaded, it was changed to a Create - MTB 980507*/
1064 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
1065 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
1068 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1070 * CurrentBuildNumber
1072 * string RegisteredOwner
1073 * string RegisteredOrganization
1076 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1078 * string SysLocation
1081 if (-1!=gethostname(buf
,200)) {
1082 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
1083 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
1087 RegCreateKeyA(HKEY_USERS
,".Default",&hkey
);
1091 #define REG_DONTLOAD -1
1096 /* return the type of native registry [Internal] */
1097 static int _get_reg_type(void)
1099 char windir
[MAX_PATHNAME_LEN
];
1100 char tmp
[MAX_PATHNAME_LEN
];
1101 int ret
= REG_WIN31
;
1103 GetWindowsDirectoryA(windir
,MAX_PATHNAME_LEN
);
1105 /* test %windir%/system32/config/system --> winnt */
1106 strcpy(tmp
, windir
);
1107 strncat(tmp
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(tmp
) - 1);
1108 if(GetFileAttributesA(tmp
) != (DWORD
)-1) {
1113 /* test %windir%/system.dat --> win95 */
1114 strcpy(tmp
, windir
);
1115 strncat(tmp
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(tmp
) - 1);
1116 if(GetFileAttributesA(tmp
) != (DWORD
)-1) {
1121 if ((ret
== REG_WINNT
) && (!PROFILE_GetWineIniString( "Wine", "Profile", "", tmp
, MAX_PATHNAME_LEN
))) {
1122 MESSAGE("When you are running with a native NT directory specify\n");
1123 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1124 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1131 #define WINE_REG_VER_ERROR -1
1132 #define WINE_REG_VER_1 0
1133 #define WINE_REG_VER_2 1
1134 #define WINE_REG_VER_OLD 2
1135 #define WINE_REG_VER_UNKNOWN 3
1137 /* return the version of wine registry file [Internal] */
1138 static int _get_wine_registry_file_format_version(LPCSTR fn
)
1144 if ((f
=fopen(fn
,"rt")) == NULL
) {
1145 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
));
1146 return WINE_REG_VER_ERROR
;
1149 if (fgets(tmp
,50,f
) == NULL
) {
1150 WARN("Error reading %s: %s\n",fn
,strerror(errno
));
1152 return WINE_REG_VER_ERROR
;
1156 if (sscanf(tmp
,"WINE REGISTRY Version %d",&ver
) != 1) return WINE_REG_VER_UNKNOWN
;
1159 return WINE_REG_VER_1
;
1162 return WINE_REG_VER_2
;
1165 return WINE_REG_VER_UNKNOWN
;
1169 /* load the registry file in wine format [Internal] */
1170 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1174 file_format
= _get_wine_registry_file_format_version(fn
);
1175 switch (file_format
) {
1177 case WINE_REG_VER_1
:
1178 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn
);
1181 case WINE_REG_VER_2
: {
1183 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1184 FILE_ATTRIBUTE_NORMAL
, 0, TRUE
)))
1186 SERVER_START_REQ( load_registry
)
1193 CloseHandle( file
);
1198 case WINE_REG_VER_UNKNOWN
:
1199 WARN("Unable to load registry file %s: unknown format.\n",fn
);
1202 case WINE_REG_VER_ERROR
:
1207 /* generate and return the name of the tmp file and associated stream [Internal] */
1208 static LPSTR
_get_tmp_fn(FILE **f
)
1215 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1216 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1217 if (errno
!= EEXIST
) {
1218 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1225 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1226 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1235 /* convert win95 native registry file to wine format [Internal] */
1236 static LPSTR
_convert_win95_registry_to_wine_format(LPCSTR fn
,int level
)
1240 DOS_FULL_NAME full_name
;
1247 _w95dke
*dke
, *root_dke
;
1249 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return NULL
;
1251 /* map the registry into the memory */
1252 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return NULL
;
1253 if ((fstat(fd
, &st
) == -1)) goto error1
;
1254 if (!st
.st_size
) goto error1
;
1255 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error1
;
1257 /* control signature */
1258 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1259 ERR("unable to load native win95 registry file %s: unknown signature.\n",fn
);
1264 /* load the header (rgkn) */
1265 rgkn
= (_w95rgkn
*)(creg
+ 1);
1266 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1267 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1270 if (rgkn
->root_off
!= 0x20) {
1271 ERR("rgkn->root_off not 0x20, please report !\n");
1274 if (rgkn
->last_dke
> rgkn
->size
)
1276 ERR("registry file corrupt! last_dke > size!\n");
1279 /* verify last dke */
1280 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1281 if (dke
->x1
!= 0x80000000)
1283 ERR("last dke invalid !\n");
1286 if (rgkn
->size
> creg
->rgdb_off
)
1288 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1291 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1292 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1294 ERR("registry file corrupt! invalid root dke !\n");
1298 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1299 fprintf(f
,"WINE REGISTRY Version 2");
1300 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1305 ERR("Unable to load native win95 registry file %s.\n",fn
);
1306 ERR("Please report to a.mohr@mailto.de.\n");
1307 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1310 munmap(base
, st
.st_size
);
1316 /* convert winnt native registry file to wine format [Internal] */
1317 static LPSTR
_convert_winnt_registry_to_wine_format(LPCSTR fn
,int level
)
1321 DOS_FULL_NAME full_name
;
1328 nt_hbin_sub
*hbin_sub
;
1331 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return NULL
;
1333 /* map the registry into the memory */
1334 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return NULL
;
1335 if ((fstat(fd
, &st
) == -1)) goto error1
;
1336 if (!st
.st_size
) goto error1
;
1337 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error1
;
1339 /* control signature */
1340 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1341 ERR("unable to load native winnt registry file %s: unknown signature.\n",fn
);
1349 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1350 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1351 ERR( "hbin block invalid\n");
1355 /* hbin_sub block */
1356 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1357 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1358 ERR( "hbin_sub block invalid\n");
1363 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1364 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1365 ERR( "special nk block not found\n");
1369 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1370 fprintf(f
,"WINE REGISTRY Version 2");
1371 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1375 munmap(base
,st
.st_size
);
1381 /* convert native native registry to wine format and load it via server call [Internal] */
1382 static void _convert_and_load_native_registry(LPCSTR fn
,HKEY hkey
,int reg_type
,int level
)
1388 /* FIXME: following function doesn't really convert yet */
1389 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1392 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1395 ERR("Don't know how to convert native 3.1 registry yet.\n");
1398 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1403 load_wine_registry(hkey
,tmp
);
1404 TRACE("File %s successfuly converted to %s and loaded to registry.\n",fn
,tmp
);
1407 else WARN("Unable to convert %s (not exist?)\n",fn
);
1411 /* load all native windows registry files [Internal] */
1412 static void _load_windows_registry( HKEY hkey_users_default
)
1415 char windir
[MAX_PATHNAME_LEN
];
1416 char path
[MAX_PATHNAME_LEN
];
1418 GetWindowsDirectoryA(windir
,MAX_PATHNAME_LEN
);
1420 reg_type
= _get_reg_type();
1425 /* user specific ntuser.dat */
1426 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)) {
1427 strcat(path
,"\\ntuser.dat");
1428 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WINNT
,1);
1431 /* default user.dat */
1432 if (hkey_users_default
) {
1433 strcpy(path
,windir
);
1434 strcat(path
,"\\system32\\config\\default");
1435 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1440 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1443 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM", &hkey
)) {
1444 strcpy(path
,windir
);
1445 strcat(path
,"\\system32\\config\\system");
1446 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1450 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SOFTWARE", &hkey
)) {
1451 strcpy(path
,windir
);
1452 strcat(path
,"\\system32\\config\\software");
1453 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1457 strcpy(path
,windir
);
1458 strcat(path
,"\\system32\\config\\sam");
1459 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WINNT
,0);
1461 strcpy(path
,windir
);
1462 strcat(path
,"\\system32\\config\\security");
1463 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WINNT
,0);
1465 /* this key is generated when the nt-core booted successfully */
1466 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
)) RegCloseKey(hkey
);
1471 _convert_and_load_native_registry("c:\\system.1st",HKEY_LOCAL_MACHINE
,REG_WIN95
,0);
1473 strcpy(path
,windir
);
1474 strcat(path
,"\\system.dat");
1475 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WIN95
,0);
1477 if (PROFILE_GetWineIniString("Wine","Profile","",path
,MAX_PATHNAME_LEN
)) {
1478 /* user specific user.dat */
1479 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1480 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WIN95
,1);
1482 /* default user.dat */
1483 if (hkey_users_default
) {
1484 strcpy(path
,windir
);
1485 strcat(path
,"\\user.dat");
1486 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1489 strcpy(path
,windir
);
1490 strcat(path
,"\\user.dat");
1491 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WIN95
,1);
1496 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1501 TRACE("REG_DONTLOAD\n");
1505 ERR("switch: no match (%d)\n",reg_type
);
1511 /* load global registry files (stored in /etc/wine) [Internal] */
1512 static void _load_global_registry(void)
1516 /* Load the global HKU hive directly from sysconfdir */
1517 load_wine_registry( HKEY_USERS
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
1519 /* Load the global machine defaults directly from sysconfdir */
1520 load_wine_registry( HKEY_LOCAL_MACHINE
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
1523 /* load home registry files (stored in ~/.wine) [Internal] */
1524 static void _load_home_registry( HKEY hkey_users_default
)
1526 LPCSTR confdir
= get_config_dir();
1527 LPSTR tmp
= _xmalloc(strlen(confdir
)+20);
1529 strcpy(tmp
,confdir
);
1530 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1531 load_wine_registry(hkey_users_default
,tmp
);
1533 strcpy(tmp
,confdir
);
1534 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1535 load_wine_registry(HKEY_CURRENT_USER
,tmp
);
1537 strcpy(tmp
,confdir
);
1538 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1539 load_wine_registry(HKEY_LOCAL_MACHINE
,tmp
);
1544 /* load all registry (native and global and home) */
1545 void SHELL_LoadRegistry( void )
1547 HKEY hkey_users_default
;
1551 if (!CLIENT_IsBootThread()) return; /* already loaded */
1553 if (RegCreateKeyA(HKEY_USERS
,".Default",&hkey_users_default
))
1555 ERR("Cannot create HKEY_USERS/.Default\n" );
1559 _allocate_default_keys();
1560 _set_registry_levels(0,0,0);
1561 if (PROFILE_GetWineIniBool("Registry","LoadWindowsRegistryFiles",1))
1562 _load_windows_registry( hkey_users_default
);
1563 if (PROFILE_GetWineIniBool("Registry","LoadGlobalRegistryFiles",1))
1564 _load_global_registry();
1565 _set_registry_levels(1,0,0);
1566 if (PROFILE_GetWineIniBool("Registry","LoadHomeRegistryFiles",1))
1567 _load_home_registry( hkey_users_default
);
1568 _init_registry_saving( hkey_users_default
);
1569 RegCloseKey(hkey_users_default
);
1572 /***************************************************************************/
1574 /***************************************************************************/
1576 /******************************************************************************
1577 * RegFlushKey [KERNEL.227] [ADVAPI32.@]
1578 * Immediately writes key to registry.
1579 * Only returns after data has been written to disk.
1581 * FIXME: does it really wait until data is written ?
1584 * hkey [I] Handle of key to write
1587 * Success: ERROR_SUCCESS
1588 * Failure: Error code
1590 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1592 FIXME( "(%x): stub\n", hkey
);
1593 return ERROR_SUCCESS
;
1597 /******************************************************************************
1598 * RegUnLoadKeyA [ADVAPI32.@]
1600 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1602 FIXME("(%x,%s): stub\n",hkey
, debugstr_a(lpSubKey
));
1603 return ERROR_SUCCESS
;
1607 /******************************************************************************
1608 * RegRestoreKeyW [ADVAPI32.@]
1611 * hkey [I] Handle of key where restore begins
1612 * lpFile [I] Address of filename containing saved tree
1613 * dwFlags [I] Optional flags
1615 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1617 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1619 /* It seems to do this check before the hkey check */
1620 if (!lpFile
|| !*lpFile
)
1621 return ERROR_INVALID_PARAMETER
;
1623 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1625 /* Check for file existence */
1627 return ERROR_SUCCESS
;
1631 /******************************************************************************
1632 * RegRestoreKeyA [ADVAPI32.@]
1634 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1636 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1637 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1638 HeapFree( GetProcessHeap(), 0, lpFileW
);
1643 /******************************************************************************
1644 * RegReplaceKeyA [ADVAPI32.@]
1646 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1649 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_a(lpSubKey
),
1650 debugstr_a(lpNewFile
),debugstr_a(lpOldFile
));
1651 return ERROR_SUCCESS
;
1659 /* 16-bit functions */
1661 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1662 * some programs. Do not remove those cases. -MM
1664 static inline void fix_win16_hkey( HKEY
*hkey
)
1666 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1669 /******************************************************************************
1670 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1672 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1674 fix_win16_hkey( &hkey
);
1675 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1678 /******************************************************************************
1679 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1681 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1683 fix_win16_hkey( &hkey
);
1684 return RegOpenKeyA( hkey
, name
, retkey
);
1687 /******************************************************************************
1688 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1690 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1692 fix_win16_hkey( &hkey
);
1693 return RegCreateKeyA( hkey
, name
, retkey
);
1696 /******************************************************************************
1697 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1699 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1701 fix_win16_hkey( &hkey
);
1702 return RegDeleteKeyA( hkey
, name
);
1705 /******************************************************************************
1706 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1708 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1710 fix_win16_hkey( &hkey
);
1711 return RegCloseKey( hkey
);
1714 /******************************************************************************
1715 * RegSetValue16 [KERNEL.221] [SHELL.5]
1717 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1719 fix_win16_hkey( &hkey
);
1720 return RegSetValueA( hkey
, name
, type
, data
, count
);
1723 /******************************************************************************
1724 * RegDeleteValue16 [KERNEL.222]
1726 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1728 fix_win16_hkey( &hkey
);
1729 return RegDeleteValueA( hkey
, name
);
1732 /******************************************************************************
1733 * RegEnumValue16 [KERNEL.223]
1735 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1736 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1738 fix_win16_hkey( &hkey
);
1739 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1742 /******************************************************************************
1743 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1746 * Is this HACK still applicable?
1749 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1750 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1753 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1755 fix_win16_hkey( &hkey
);
1756 if (count
) *count
&= 0xffff;
1757 return RegQueryValueA( hkey
, name
, data
, count
);
1760 /******************************************************************************
1761 * RegQueryValueEx16 [KERNEL.225]
1763 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1764 LPBYTE data
, LPDWORD count
)
1766 fix_win16_hkey( &hkey
);
1767 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1770 /******************************************************************************
1771 * RegSetValueEx16 [KERNEL.226]
1773 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1774 CONST BYTE
*data
, DWORD count
)
1776 fix_win16_hkey( &hkey
);
1777 if (!count
&& (type
==REG_SZ
)) count
= strlen(data
);
1778 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);
1781 /******************************************************************************
1782 * RegFlushKey16 [KERNEL.227]
1784 DWORD WINAPI
RegFlushKey16( HKEY hkey
)
1786 fix_win16_hkey( &hkey
);
1787 return RegFlushKey( hkey
);