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 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * When changing this file, please re-run the regtest program to ensure
28 * the conditions are handled properly.
33 * Time for RegEnumKey*, RegQueryInfoKey*
37 #include "wine/port.h"
46 #include <sys/types.h>
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
57 #include "wine/winbase16.h"
58 #include "wine/library.h"
59 #include "wine/server.h"
60 #include "wine/unicode.h"
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
67 /* FIXME: following defines should be configured global */
68 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT ETCDIR"/wine.userreg"
69 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE ETCDIR"/wine.systemreg"
71 /* relative in ~user/.wine/ : */
72 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
73 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
74 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
76 /* _xmalloc [Internal] */
77 static void *_xmalloc( size_t size
)
81 res
= malloc (size
? size
: 1);
83 WARN("Virtual memory exhausted.\n");
89 /* _strdupnA [Internal] */
90 static LPSTR
_strdupnA(LPCSTR str
,size_t len
)
94 if (!str
) return NULL
;
95 ret
= _xmalloc( len
+ 1 );
96 memcpy( ret
, str
, len
);
101 /* convert ansi string to unicode [Internal] */
102 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
107 if (!strA
) return NULL
;
108 lenW
= MultiByteToWideChar(CP_ACP
,0,strA
,lenA
,NULL
,0);
109 ret
= _xmalloc(lenW
*sizeof(WCHAR
)+sizeof(WCHAR
));
110 MultiByteToWideChar(CP_ACP
,0,strA
,lenA
,ret
,lenW
);
115 /* dump a Unicode string with proper escaping [Internal] */
116 /* FIXME: this code duplicates server/unicode.c */
117 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,char escape
[2])
119 static const char escapes
[32] = ".......abtnvfr.............e....";
124 for (; len
; str
++, len
--)
126 if (pos
> buffer
+ sizeof(buffer
) - 8)
128 fwrite( buffer
, pos
- buffer
, 1, f
);
129 count
+= pos
- buffer
;
132 if (*str
> 127) /* hex escape */
134 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
135 pos
+= sprintf( pos
, "\\x%04x", *str
);
137 pos
+= sprintf( pos
, "\\x%x", *str
);
140 if (*str
< 32) /* octal or C escape */
142 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
143 if (escapes
[*str
] != '.')
144 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
145 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
146 pos
+= sprintf( pos
, "\\%03o", *str
);
148 pos
+= sprintf( pos
, "\\%o", *str
);
151 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
154 fwrite( buffer
, pos
- buffer
, 1, f
);
155 count
+= pos
- buffer
;
159 /* convert ansi string to unicode and dump with proper escaping [Internal] */
160 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,char escape
[2])
165 if (strA
== NULL
) return 0;
166 strW
= _strdupnAtoW(strA
,len
);
167 ret
= _dump_strW(strW
,len
,f
,escape
);
173 /* FIXME: this code duplicates server/registry.c */
175 WCHAR
*nameW
; /* value name */
176 int type
; /* value type */
177 size_t len
; /* value data length in bytes */
178 void *data
; /* pointer to value data */
181 /* dump a value to a text file */
182 /* FIXME: this code duplicates server/registry.c */
183 static void _dump_value(struct key_value
*value
,FILE *f
)
187 if (value
->nameW
[0]) {
189 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
190 count
+= fprintf( f
, "\"=" );
192 else count
= fprintf( f
, "@=" );
194 switch(value
->type
) {
198 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
200 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
204 if (value
->len
== sizeof(DWORD
)) {
206 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
207 fprintf( f
, "dword:%08lx", dw
);
210 /* else fall through */
212 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
213 else count
+= fprintf( f
, "hex(%x):", value
->type
);
214 for (i
= 0; i
< value
->len
; i
++) {
215 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
216 if (i
< value
->len
-1) {
219 fprintf( f
, "\\\n " );
229 /******************************************************************/
230 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
232 reghack - windows 3.11 registry data format demo program.
234 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
235 a combined hash table and tree description, and finally a text table.
237 The header is obvious from the struct header. The taboff1 and taboff2
238 fields are always 0x20, and their usage is unknown.
240 The 8-byte entry table has various entry types.
242 tabent[0] is a root index. The second word has the index of the root of
244 tabent[1..hashsize] is a hash table. The first word in the hash entry is
245 the index of the key/value that has that hash. Data with the same
246 hash value are on a circular list. The other three words in the
247 hash entry are always zero.
248 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
249 entry: dirent and keyent/valent. They are identified by context.
250 tabent[freeidx] is the first free entry. The first word in a free entry
251 is the index of the next free entry. The last has 0 as a link.
252 The other three words in the free list are probably irrelevant.
254 Entries in text table are preceded by a word at offset-2. This word
255 has the value (2*index)+1, where index is the referring keyent/valent
256 entry in the table. I have no suggestion for the 2* and the +1.
257 Following the word, there are N bytes of data, as per the keyent/valent
258 entry length. The offset of the keyent/valent entry is from the start
259 of the text table to the first data byte.
261 This information is not available from Microsoft. The data format is
262 deduced from the reg.dat file by me. Mistakes may
263 have been made. I claim no rights and give no guarantees for this program.
265 Tor Sjøwall, tor@sn.no
268 /* reg.dat header format */
270 char cookie
[8]; /* 'SHCC3.10' */
271 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
272 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
273 unsigned long tabcnt
; /* number of entries in index table */
274 unsigned long textoff
; /* offset of text part */
275 unsigned long textsize
; /* byte size of text part */
276 unsigned short hashsize
; /* hash size */
277 unsigned short freeidx
; /* free index */
280 /* generic format of table entries */
282 unsigned short w0
, w1
, w2
, w3
;
285 /* directory tabent: */
287 unsigned short sibling_idx
; /* table index of sibling dirent */
288 unsigned short child_idx
; /* table index of child dirent */
289 unsigned short key_idx
; /* table index of key keyent */
290 unsigned short value_idx
; /* table index of value valent */
295 unsigned short hash_idx
; /* hash chain index for string */
296 unsigned short refcnt
; /* reference count */
297 unsigned short length
; /* length of string */
298 unsigned short string_off
; /* offset of string in text table */
303 unsigned short hash_idx
; /* hash chain index for string */
304 unsigned short refcnt
; /* reference count */
305 unsigned short length
; /* length of string */
306 unsigned short string_off
; /* offset of string in text table */
309 /* recursive helper function to display a directory tree [Internal] */
310 void _w31_dumptree(unsigned short idx
,unsigned char *txt
,struct _w31_tabent
*tab
,struct _w31_header
*head
,HKEY hkey
,time_t lastmodified
, int level
)
312 struct _w31_dirent
*dir
;
313 struct _w31_keyent
*key
;
314 struct _w31_valent
*val
;
316 static char tail
[400];
319 dir
=(struct _w31_dirent
*)&tab
[idx
];
322 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
324 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
325 tail
[key
->length
]='\0';
326 /* all toplevel entries AND the entries in the
327 * toplevel subdirectory belong to \SOFTWARE\Classes
329 if (!level
&& !strcmp(tail
,".classes")) {
330 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
331 idx
=dir
->sibling_idx
;
334 if (subkey
) RegCloseKey( subkey
);
335 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
336 /* only add if leaf node or valued node */
337 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
338 if (dir
->value_idx
) {
339 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
340 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
341 tail
[val
->length
]='\0';
342 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
345 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
346 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
347 idx
=dir
->sibling_idx
;
349 if (subkey
) RegCloseKey( subkey
);
353 /******************************************************************************
354 * _w31_loadreg [Internal]
356 void _w31_loadreg(void)
359 struct _w31_header head
;
360 struct _w31_tabent
*tab
;
364 BY_HANDLE_FILE_INFORMATION hfinfo
;
369 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
370 if (hf
==HFILE_ERROR
) return;
372 /* read & dump header */
373 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
374 ERR("reg.dat is too short.\n");
378 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
379 ERR("reg.dat has bad signature.\n");
384 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
385 /* read and dump index table */
387 if (len
!=_lread(hf
,tab
,len
)) {
388 ERR("couldn't read %d bytes.\n",len
);
395 txt
= _xmalloc(head
.textsize
);
396 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
397 ERR("couldn't seek to textblock.\n");
403 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
404 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
411 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
412 ERR("GetFileInformationByHandle failed?.\n");
418 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
419 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
426 /***********************************************************************************/
427 /* windows 95 registry loader */
428 /***********************************************************************************/
430 /* SECTION 1: main header
434 #define W95_REG_CREG_ID 0x47455243
437 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
438 DWORD version
; /* ???? 0x00010000 */
439 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
440 DWORD uk2
; /* 0x0c */
441 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
447 /* SECTION 2: Directory information (tree structure)
449 * once on offset 0x20
451 * structure: [rgkn][dke]* (repeat till last_dke is reached)
453 #define W95_REG_RGKN_ID 0x4e4b4752
456 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
457 DWORD size
; /* Size of the RGKN-block */
458 DWORD root_off
; /* Rel. Offset of the root-record */
459 DWORD last_dke
; /* Offset to last DKE ? */
463 /* Disk Key Entry Structure
465 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
466 * hive itself. It looks the same like other keys. Even the ID-number can
469 * The "hash"-value is a value representing the key's name. Windows will not
470 * search for the name, but for a matching hash-value. if it finds one, it
471 * will compare the actual string info, otherwise continue with the next key.
472 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
473 * of the string which are smaller than 0x80 (128) to this D-Word.
475 * If you want to modify key names, also modify the hash-values, since they
476 * cannot be found again (although they would be displayed in REGEDIT)
477 * End of list-pointers are filled with 0xFFFFFFFF
479 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
480 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
481 * structure) and reading another RGDB_section.
483 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
484 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
485 * The remaining space between last_dke and the offset calculated from
486 * rgkn->size seems to be free for use for more dke:s.
487 * So it seems if more dke:s are added, they are added to that space and
488 * last_dke is grown, and in case that "free" space is out, the space
489 * gets grown and rgkn->size gets adjusted.
491 * there is a one to one relationship between dke and dkh
493 /* key struct, once per key */
495 DWORD x1
; /* Free entry indicator(?) */
496 DWORD hash
; /* sum of bytes of keyname */
497 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
498 DWORD prevlvl
; /* offset of previous key */
499 DWORD nextsub
; /* offset of child key */
500 DWORD next
; /* offset of sibling key */
501 WORD nrLS
; /* id inside the rgdb block */
502 WORD nrMS
; /* number of the rgdb block */
505 /* SECTION 3: key information, values and data
508 * section: [blocks]* (repeat creg->rgdb_num times)
509 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
510 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
512 * An interesting relationship exists in RGDB_section. The DWORD value
513 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
514 * I have no idea at the moment what this means. (Kevin Cozens)
517 /* block header, once per block */
518 #define W95_REG_RGDB_ID 0x42444752
521 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
522 DWORD size
; /* 0x04 */
523 DWORD uk1
; /* 0x08 */
524 DWORD uk2
; /* 0x0c */
525 DWORD uk3
; /* 0x10 */
526 DWORD uk4
; /* 0x14 */
527 DWORD uk5
; /* 0x18 */
528 DWORD uk6
; /* 0x1c */
532 /* Disk Key Header structure (RGDB part), once per key */
534 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
535 WORD nrLS
; /* 0x04 id inside the rgdb block */
536 WORD nrMS
; /* 0x06 number of the rgdb block */
537 DWORD bytesused
; /* 0x08 */
538 WORD keynamelen
; /* 0x0c len of name */
539 WORD values
; /* 0x0e number of values */
540 DWORD xx1
; /* 0x10 */
541 char name
[1]; /* 0x14 */
542 /* dkv */ /* 0x14 + keynamelen */
545 /* Disk Key Value structure, once per value */
547 DWORD type
; /* 0x00 */
549 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
550 WORD valdatalen
; /* 0x0A length of data */
551 char name
[1]; /* 0x0c */
552 /* raw data */ /* 0x0c + valnamelen */
555 /******************************************************************************
556 * _w95_lookup_dkh [Internal]
558 * seeks the dkh belonging to a dke
560 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
566 /* get the beginning of the rgdb datastore */
567 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
569 /* check: requested block < last_block) */
570 if (creg
->rgdb_num
<= nrMS
) {
571 ERR("registry file corrupt! requested block no. beyond end.\n");
575 /* find the right block */
576 for(i
=0; i
<nrMS
;i
++) {
577 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
578 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
581 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
584 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
587 if(nrLS
==dkh
->nrLS
) return dkh
;
588 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
589 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
595 /******************************************************************************
596 * _w95_dump_dkv [Internal]
598 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
603 /* first value block */
604 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
606 /* loop through the values */
607 for (i
=0; i
< dkh
->values
; i
++) {
608 struct key_value value
;
611 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
612 value
.type
= dkv
->type
;
613 value
.len
= dkv
->valdatalen
;
615 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
617 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
618 pdata
= _strdupnAtoW(value
.data
,value
.len
);
621 if (pdata
!= NULL
) value
.data
= pdata
;
623 _dump_value(&value
,f
);
625 if (pdata
!= NULL
) free(pdata
);
628 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
633 /******************************************************************************
634 * _w95_dump_dke [Internal]
636 static int _w95_dump_dke(LPSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
639 LPSTR new_key_name
= NULL
;
641 /* special root key */
642 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
644 /* parse the one subkey */
645 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
646 /* has no sibling keys */
650 /* search subblock */
651 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
652 ERR("dke pointing to missing dkh !\n");
657 /* create new subkey name */
658 new_key_name
= _strdupnA(key_name
,strlen(key_name
)+dkh
->keynamelen
+1);
659 if (strcmp(new_key_name
,"") != 0) strcat(new_key_name
,"\\");
660 strncat(new_key_name
,dkh
->name
,dkh
->keynamelen
);
662 /* walk sibling keys */
663 if (dke
->next
!= 0xffffffff ) {
664 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
670 /* write the key path (something like [Software\\Microsoft\\..]) only if:
671 1) key has some values
672 2) key has no values and no subkeys
674 if (dkh
->values
> 0) {
675 /* there are some values */
677 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
679 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
684 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
685 /* no subkeys and no values */
687 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
690 } else new_key_name
= _strdupnA(key_name
,strlen(key_name
));
693 if (dke
->nextsub
!= 0xffffffff) {
694 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
703 /* end windows 95 loader */
705 /***********************************************************************************/
706 /* windows NT registry loader */
707 /***********************************************************************************/
709 /* NT REGISTRY LOADER */
711 #ifdef HAVE_SYS_MMAN_H
712 # include <sys/mman.h>
716 #define MAP_FAILED ((LPVOID)-1)
719 #define NT_REG_BLOCK_SIZE 0x1000
721 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
722 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
723 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
724 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
726 /* subblocks of nk */
727 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
728 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
729 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
731 #define NT_REG_KEY_BLOCK_TYPE 0x20
732 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
735 DWORD id
; /* 0x66676572 'regf'*/
736 DWORD uk1
; /* 0x04 */
737 DWORD uk2
; /* 0x08 */
738 FILETIME DateModified
; /* 0x0c */
739 DWORD uk3
; /* 0x14 */
740 DWORD uk4
; /* 0x18 */
741 DWORD uk5
; /* 0x1c */
742 DWORD uk6
; /* 0x20 */
743 DWORD RootKeyBlock
; /* 0x24 */
744 DWORD BlockSize
; /* 0x28 */
746 DWORD Checksum
; /* at offset 0x1FC */
755 DWORD id
; /* 0x6E696268 'hbin' */
759 DWORD uk2
; /* 0x10 */
760 DWORD uk3
; /* 0x14 */
761 DWORD uk4
; /* 0x18 */
762 DWORD size
; /* 0x1C */
763 nt_hbin_sub hbin_sub
; /* 0x20 */
767 * the value_list consists of offsets to the values (vk)
770 WORD SubBlockId
; /* 0x00 0x6B6E */
771 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
772 FILETIME writetime
; /* 0x04 */
773 DWORD uk1
; /* 0x0C */
774 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
775 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
776 DWORD uk8
; /* 0x18 */
777 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
778 DWORD uk2
; /* 0x20 */
779 DWORD nr_values
; /* 0x24 number of values */
780 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
781 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
782 DWORD off_class
; /* 0x30 Offset of the Class-Name */
783 DWORD uk3
; /* 0x34 */
784 DWORD uk4
; /* 0x38 */
785 DWORD uk5
; /* 0x3c */
786 DWORD uk6
; /* 0x40 */
787 DWORD uk7
; /* 0x44 */
788 WORD name_len
; /* 0x48 name-length */
789 WORD class_len
; /* 0x4a class-name length */
790 char name
[1]; /* 0x4c key-name */
794 DWORD off_nk
; /* 0x00 */
795 DWORD name
; /* 0x04 */
799 WORD id
; /* 0x00 0x666c */
800 WORD nr_keys
; /* 0x06 */
801 hash_rec hash_rec
[1];
805 list of subkeys without hash
812 WORD id
; /* 0x00 0x696c */
818 this is a intermediate node
829 WORD id
; /* 0x00 0x6972 */
830 WORD nr_li
; /* 0x02 number off offsets */
831 DWORD off_li
[1]; /* 0x04 points to li */
835 WORD id
; /* 0x00 'vk' */
849 * 0 value is a default value
850 * 1 the value has a name
853 * len of the whole data block
855 * bytes including the terminating \0 = 2*(number_of_chars+1)
856 * - reg_dword, reg_binary:
857 * if highest bit of data_len is set data_off contains the value
859 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
861 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
862 struct key_value value
;
864 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
865 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
869 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
870 value
.type
= vk
->type
;
871 value
.len
= (vk
->data_len
& 0x7fffffff);
872 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
874 _dump_value(&value
,f
);
880 /* it's called from _nt_dump_lf() */
881 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
886 * this structure contains the hash of a keyname and points to all
889 * exception: if the id is 'il' there are no hash values and every
892 static int _nt_dump_lf(LPSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
896 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
897 if (subkeys
!= lf
->nr_keys
) goto error1
;
899 for (i
=0; i
<lf
->nr_keys
; i
++)
900 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
901 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
902 nt_li
* li
= (nt_li
*)lf
;
903 if (subkeys
!= li
->nr_keys
) goto error1
;
905 for (i
=0; i
<li
->nr_keys
; i
++)
906 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
907 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
908 nt_ri
* ri
= (nt_ri
*)lf
;
911 /* count all subkeys */
912 for (i
=0; i
<ri
->nr_li
; i
++) {
913 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
914 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
915 li_subkeys
+= li
->nr_keys
;
919 if (subkeys
!= li_subkeys
) goto error1
;
921 /* loop through the keys */
922 for (i
=0; i
<ri
->nr_li
; i
++) {
923 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
924 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
931 if (lf
->id
== 0x686c)
932 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
934 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
938 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
942 ERR("error reading lf block\n");
946 /* _nt_dump_nk [Internal] */
947 static int _nt_dump_nk(LPSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
951 LPSTR new_key_name
= NULL
;
953 TRACE("%s\n", key_name
);
955 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
956 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
960 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
961 ERR("registry file corrupt!\n");
965 /* create the new key */
967 /* create new subkey name */
968 new_key_name
= _strdupnA(key_name
,strlen(key_name
)+nk
->name_len
+1);
969 if (strcmp(new_key_name
,"") != 0) strcat(new_key_name
,"\\");
970 strncat(new_key_name
,nk
->name
,nk
->name_len
);
972 /* write the key path (something like [Software\\Microsoft\\..]) only if:
973 1) key has some values
974 2) key has no values and no subkeys
976 if (nk
->nr_values
> 0) {
977 /* there are some values */
979 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
982 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
983 /* no subkeys and no values */
985 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
989 /* loop trough the value list */
990 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
991 for (n
=0; n
<nk
->nr_values
; n
++) {
992 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
993 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
998 } else new_key_name
= _strdupnA(key_name
,strlen(key_name
));
1000 /* loop through the subkeys */
1001 if (nk
->nr_subkeys
) {
1002 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
1003 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
1015 /**********************************************************************************
1016 * _set_registry_levels [Internal]
1018 * set level to 0 for loading system files
1019 * set level to 1 for loading user files
1021 static void _set_registry_levels(int level
,int saving
,int period
)
1023 SERVER_START_REQ( set_registry_levels
)
1025 req
->current
= level
;
1026 req
->saving
= saving
;
1027 req
->period
= period
;
1028 wine_server_call( req
);
1033 /* _save_at_exit [Internal] */
1034 static void _save_at_exit(HKEY hkey
,LPCSTR path
)
1036 LPCSTR confdir
= wine_get_config_dir();
1038 SERVER_START_REQ( save_registry_atexit
)
1041 wine_server_add_data( req
, confdir
, strlen(confdir
) );
1042 wine_server_add_data( req
, path
, strlen(path
)+1 );
1043 wine_server_call( req
);
1048 /* configure save files and start the periodic saving timer [Internal] */
1049 static void _init_registry_saving( HKEY hkey_users_default
)
1054 static const WCHAR registryW
[] = {'r','e','g','i','s','t','r','y',0};
1055 static const WCHAR SaveOnlyUpdatedKeysW
[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1056 static const WCHAR PeriodicSaveW
[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1057 static const WCHAR WritetoHomeRegistryFilesW
[] = {'W','r','i','t','e','t','o','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1058 static const WCHAR empty_strW
[] = { 0 };
1060 all
= !PROFILE_GetWineIniBool(registryW
, SaveOnlyUpdatedKeysW
, 1);
1061 PROFILE_GetWineIniString( registryW
, PeriodicSaveW
, empty_strW
, buffer
, 20 );
1062 if (buffer
[0]) period
= (int)strtolW(buffer
, NULL
, 10);
1064 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1065 _set_registry_levels(1,!all
,period
*1000);
1067 if (PROFILE_GetWineIniBool(registryW
, WritetoHomeRegistryFilesW
, 1))
1069 _save_at_exit(HKEY_CURRENT_USER
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1070 _save_at_exit(HKEY_LOCAL_MACHINE
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1071 _save_at_exit(hkey_users_default
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1076 /******************************************************************************
1077 * _allocate_default_keys [Internal]
1078 * Registry initialisation, allocates some default keys.
1080 static void _allocate_default_keys(void) {
1086 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
1089 /* This was an Open, but since it is called before the real registries
1090 are loaded, it was changed to a Create - MTB 980507*/
1091 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
1092 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
1095 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
1097 * CurrentBuildNumber
1099 * string RegisteredOwner
1100 * string RegisteredOrganization
1103 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
1105 * string SysLocation
1108 if (-1!=gethostname(buf
,200)) {
1109 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
1110 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
1114 RegCreateKeyA(HKEY_USERS
,".Default",&hkey
);
1118 #define REG_DONTLOAD -1
1123 /* return the type of native registry [Internal] */
1124 static int _get_reg_type(void)
1126 WCHAR windir
[MAX_PATHNAME_LEN
];
1127 WCHAR tmp
[MAX_PATHNAME_LEN
];
1128 int ret
= REG_WIN31
;
1129 static const WCHAR nt_reg_pathW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1130 static const WCHAR win9x_reg_pathW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1131 static const WCHAR WineW
[] = {'W','i','n','e',0};
1132 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1133 static const WCHAR empty_strW
[] = { 0 };
1135 GetWindowsDirectoryW(windir
, MAX_PATHNAME_LEN
);
1137 /* test %windir%/system32/config/system --> winnt */
1138 strcpyW(tmp
, windir
);
1139 strcatW(tmp
, nt_reg_pathW
);
1140 if(GetFileAttributesW(tmp
) != (DWORD
)-1)
1144 /* test %windir%/system.dat --> win95 */
1145 strcpyW(tmp
, windir
);
1146 strcatW(tmp
, win9x_reg_pathW
);
1147 if(GetFileAttributesW(tmp
) != (DWORD
)-1)
1151 if ((ret
== REG_WINNT
) && (!PROFILE_GetWineIniString( WineW
, ProfileW
, empty_strW
, tmp
, MAX_PATHNAME_LEN
)))
1153 MESSAGE("When you are running with a native NT directory specify\n");
1154 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1155 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1162 #define WINE_REG_VER_ERROR -1
1163 #define WINE_REG_VER_1 0
1164 #define WINE_REG_VER_2 1
1165 #define WINE_REG_VER_OLD 2
1166 #define WINE_REG_VER_UNKNOWN 3
1168 /* return the version of wine registry file [Internal] */
1169 static int _get_wine_registry_file_format_version(LPCSTR fn
)
1175 if ((f
=fopen(fn
,"rt")) == NULL
) {
1176 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
));
1177 return WINE_REG_VER_ERROR
;
1180 if (fgets(tmp
,50,f
) == NULL
) {
1181 WARN("Error reading %s: %s\n",fn
,strerror(errno
));
1183 return WINE_REG_VER_ERROR
;
1187 if (sscanf(tmp
,"WINE REGISTRY Version %d",&ver
) != 1) return WINE_REG_VER_UNKNOWN
;
1190 return WINE_REG_VER_1
;
1193 return WINE_REG_VER_2
;
1196 return WINE_REG_VER_UNKNOWN
;
1200 /* load the registry file in wine format [Internal] */
1201 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1205 file_format
= _get_wine_registry_file_format_version(fn
);
1206 switch (file_format
) {
1208 case WINE_REG_VER_1
:
1209 WARN("Unable to load registry file %s: old format which is no longer supported.\n",fn
);
1212 case WINE_REG_VER_2
: {
1214 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
1215 FILE_ATTRIBUTE_NORMAL
, 0, TRUE
, DRIVE_UNKNOWN
)))
1217 SERVER_START_REQ( load_registry
)
1221 wine_server_call( req
);
1224 CloseHandle( file
);
1229 case WINE_REG_VER_UNKNOWN
:
1230 WARN("Unable to load registry file %s: unknown format.\n",fn
);
1233 case WINE_REG_VER_ERROR
:
1238 /* generate and return the name of the tmp file and associated stream [Internal] */
1239 static LPSTR
_get_tmp_fn(FILE **f
)
1246 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1247 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1248 if (errno
!= EEXIST
) {
1249 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1256 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1257 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1266 /* convert win95 native registry file to wine format [Internal] */
1267 static LPSTR
_convert_win95_registry_to_wine_format(LPCWSTR fn
, int level
)
1271 DOS_FULL_NAME full_name
;
1278 _w95dke
*dke
, *root_dke
;
1280 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return NULL
;
1282 /* map the registry into the memory */
1283 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return NULL
;
1284 if ((fstat(fd
, &st
) == -1)) goto error1
;
1285 if (!st
.st_size
) goto error1
;
1286 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error1
;
1288 /* control signature */
1289 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1290 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1296 /* load the header (rgkn) */
1297 rgkn
= (_w95rgkn
*)(creg
+ 1);
1298 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1299 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1302 if (rgkn
->root_off
!= 0x20) {
1303 ERR("rgkn->root_off not 0x20, please report !\n");
1306 if (rgkn
->last_dke
> rgkn
->size
)
1308 ERR("registry file corrupt! last_dke > size!\n");
1311 /* verify last dke */
1312 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1313 if (dke
->x1
!= 0x80000000)
1315 ERR("last dke invalid !\n");
1318 if (rgkn
->size
> creg
->rgdb_off
)
1320 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1323 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1324 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1326 ERR("registry file corrupt! invalid root dke !\n");
1330 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1331 fprintf(f
,"WINE REGISTRY Version 2");
1332 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1337 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn
));
1338 ERR("Please report this.\n");
1339 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1342 munmap(base
, st
.st_size
);
1348 /* convert winnt native registry file to wine format [Internal] */
1349 static LPSTR
_convert_winnt_registry_to_wine_format(LPCWSTR fn
, int level
)
1359 nt_hbin_sub
*hbin_sub
;
1362 TRACE("%s\n", debugstr_w(fn
));
1364 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1365 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1366 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
|SEC_COMMIT
, 0, 0, NULL
);
1367 if (!hMapping
) goto error1
;
1368 base
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
1369 CloseHandle( hMapping
);
1370 if (!base
) goto error1
;
1372 /* control signature */
1373 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1374 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1383 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1384 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1385 ERR( "hbin block invalid\n");
1389 /* hbin_sub block */
1390 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1391 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1392 ERR( "hbin_sub block invalid\n");
1397 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1398 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1399 ERR( "special nk block not found\n");
1403 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1404 fprintf(f
,"WINE REGISTRY Version 2");
1405 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1409 UnmapViewOfFile( base
);
1415 /* convert native registry to wine format and load it via server call [Internal] */
1416 static void _convert_and_load_native_registry(LPCWSTR fn
, HKEY hkey
, int reg_type
, int level
)
1422 /* FIXME: following function doesn't really convert yet */
1423 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1426 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1429 ERR("Don't know how to convert native 3.1 registry yet.\n");
1432 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1437 load_wine_registry(hkey
,tmp
);
1438 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1439 debugstr_w(fn
), tmp
);
1442 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn
));
1446 /* load all native windows registry files [Internal] */
1447 static void _load_windows_registry( HKEY hkey_users_default
)
1450 WCHAR windir
[MAX_PATHNAME_LEN
];
1451 WCHAR path
[MAX_PATHNAME_LEN
];
1452 static const WCHAR WineW
[] = {'W','i','n','e',0};
1453 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1454 static const WCHAR empty_strW
[] = { 0 };
1456 GetWindowsDirectoryW(windir
, MAX_PATHNAME_LEN
);
1458 reg_type
= _get_reg_type();
1462 static const WCHAR ntuser_datW
[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1463 static const WCHAR defaultW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','d','e','f','a','u','l','t',0};
1464 static const WCHAR systemW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','y','s','t','e','m',0};
1465 static const WCHAR softwareW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','o','f','t','w','a','r','e',0};
1466 static const WCHAR samW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1467 static const WCHAR securityW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','e','c','u','r','i','t','y',0};
1469 /* user specific ntuser.dat */
1470 if (PROFILE_GetWineIniString( WineW
, ProfileW
, empty_strW
, path
, MAX_PATHNAME_LEN
)) {
1471 strcatW(path
, ntuser_datW
);
1472 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WINNT
,1);
1475 /* default user.dat */
1476 if (hkey_users_default
) {
1477 strcpyW(path
, windir
);
1478 strcatW(path
, defaultW
);
1479 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1484 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1487 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM", &hkey
)) {
1488 strcpyW(path
, windir
);
1489 strcatW(path
, systemW
);
1490 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1494 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SOFTWARE", &hkey
)) {
1495 strcpyW(path
, windir
);
1496 strcatW(path
, softwareW
);
1497 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1501 strcpyW(path
, windir
);
1502 strcatW(path
, samW
);
1503 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WINNT
,0);
1505 strcpyW(path
,windir
);
1506 strcatW(path
, securityW
);
1507 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WINNT
,0);
1509 /* this key is generated when the nt-core booted successfully */
1510 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
)) RegCloseKey(hkey
);
1516 static const WCHAR system_1stW
[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1517 static const WCHAR system_datW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1518 static const WCHAR classes_datW
[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1519 static const WCHAR user_datW
[] = {'\\','u','s','e','r','.','d','a','t',0};
1521 _convert_and_load_native_registry(system_1stW
,HKEY_LOCAL_MACHINE
,REG_WIN95
,0);
1523 strcpyW(path
, windir
);
1524 strcatW(path
, system_datW
);
1525 _convert_and_load_native_registry(path
,HKEY_LOCAL_MACHINE
,REG_WIN95
,0);
1527 strcpyW(path
, windir
);
1528 strcatW(path
, classes_datW
);
1529 _convert_and_load_native_registry(path
,HKEY_CLASSES_ROOT
,REG_WIN95
,0);
1531 if (PROFILE_GetWineIniString(WineW
, ProfileW
, empty_strW
, path
, MAX_PATHNAME_LEN
)) {
1532 /* user specific user.dat */
1533 strcatW(path
, user_datW
);
1534 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WIN95
,1);
1536 /* default user.dat */
1537 if (hkey_users_default
) {
1538 strcpyW(path
, windir
);
1539 strcatW(path
, user_datW
);
1540 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1543 strcpyW(path
, windir
);
1544 strcatW(path
, user_datW
);
1545 _convert_and_load_native_registry(path
,HKEY_CURRENT_USER
,REG_WIN95
,1);
1551 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1556 TRACE("REG_DONTLOAD\n");
1560 ERR("switch: no match (%d)\n",reg_type
);
1566 /* load global registry files (stored in /etc/wine) [Internal] */
1567 static void _load_global_registry(void)
1571 /* Load the global HKU hive directly from sysconfdir */
1572 load_wine_registry( HKEY_USERS
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
1574 /* Load the global machine defaults directly from sysconfdir */
1575 load_wine_registry( HKEY_LOCAL_MACHINE
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
1578 /* load home registry files (stored in ~/.wine) [Internal] */
1579 static void _load_home_registry( HKEY hkey_users_default
)
1581 LPCSTR confdir
= wine_get_config_dir();
1582 LPSTR tmp
= _xmalloc(strlen(confdir
)+20);
1584 strcpy(tmp
,confdir
);
1585 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1586 load_wine_registry(hkey_users_default
,tmp
);
1588 strcpy(tmp
,confdir
);
1589 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1590 load_wine_registry(HKEY_CURRENT_USER
,tmp
);
1592 strcpy(tmp
,confdir
);
1593 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1594 load_wine_registry(HKEY_LOCAL_MACHINE
,tmp
);
1599 /* load all registry (native and global and home) */
1600 void SHELL_LoadRegistry( void )
1602 HKEY hkey_users_default
;
1603 static const WCHAR RegistryW
[] = {'R','e','g','i','s','t','r','y',0};
1604 static const WCHAR load_win_reg_filesW
[] = {'L','o','a','d','W','i','n','d','o','w','s','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1605 static const WCHAR load_global_reg_filesW
[] = {'L','o','a','d','G','l','o','b','a','l','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1606 static const WCHAR load_home_reg_filesW
[] = {'L','o','a','d','H','o','m','e','R','e','g','i','s','t','r','y','F','i','l','e','s',0};
1610 if (!CLIENT_IsBootThread()) return; /* already loaded */
1612 if (RegCreateKeyA(HKEY_USERS
,".Default",&hkey_users_default
))
1614 ERR("Cannot create HKEY_USERS/.Default\n" );
1618 _allocate_default_keys();
1619 _set_registry_levels(0,0,0);
1620 if (PROFILE_GetWineIniBool(RegistryW
, load_win_reg_filesW
, 1))
1621 _load_windows_registry( hkey_users_default
);
1622 if (PROFILE_GetWineIniBool(RegistryW
, load_global_reg_filesW
, 1))
1623 _load_global_registry();
1624 _set_registry_levels(1,0,0);
1625 if (PROFILE_GetWineIniBool(RegistryW
, load_home_reg_filesW
, 1))
1626 _load_home_registry( hkey_users_default
);
1627 _init_registry_saving( hkey_users_default
);
1628 RegCloseKey(hkey_users_default
);
1631 /***************************************************************************/
1632 /* 16-BIT API FUNCTIONS */
1633 /***************************************************************************/
1635 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1636 * some programs. Do not remove those cases. -MM
1638 static inline void fix_win16_hkey( HKEY
*hkey
)
1640 if (*hkey
== 0 || *hkey
== (HKEY
)1) *hkey
= HKEY_CLASSES_ROOT
;
1643 /******************************************************************************
1644 * RegEnumKey [KERNEL.216]
1645 * RegEnumKey [SHELL.7]
1647 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1649 fix_win16_hkey( &hkey
);
1650 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1653 /******************************************************************************
1654 * RegOpenKey [KERNEL.217]
1655 * RegOpenKey [SHELL.1]
1657 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1659 fix_win16_hkey( &hkey
);
1660 return RegOpenKeyA( hkey
, name
, retkey
);
1663 /******************************************************************************
1664 * RegCreateKey [KERNEL.218]
1665 * RegCreateKey [SHELL.2]
1667 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1669 fix_win16_hkey( &hkey
);
1670 return RegCreateKeyA( hkey
, name
, retkey
);
1673 /******************************************************************************
1674 * RegDeleteKey [KERNEL.219]
1675 * RegDeleteKey [SHELL.4]
1677 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1679 fix_win16_hkey( &hkey
);
1680 return RegDeleteKeyA( hkey
, name
);
1683 /******************************************************************************
1684 * RegCloseKey [KERNEL.220]
1685 * RegCloseKey [SHELL.3]
1687 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1689 fix_win16_hkey( &hkey
);
1690 return RegCloseKey( hkey
);
1693 /******************************************************************************
1694 * RegSetValue [KERNEL.221]
1695 * RegSetValue [SHELL.5]
1697 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1699 fix_win16_hkey( &hkey
);
1700 return RegSetValueA( hkey
, name
, type
, data
, count
);
1703 /******************************************************************************
1704 * RegDeleteValue [KERNEL.222]
1706 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1708 fix_win16_hkey( &hkey
);
1709 return RegDeleteValueA( hkey
, name
);
1712 /******************************************************************************
1713 * RegEnumValue [KERNEL.223]
1715 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1716 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1718 fix_win16_hkey( &hkey
);
1719 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1722 /******************************************************************************
1723 * RegQueryValue [KERNEL.224]
1724 * RegQueryValue [SHELL.6]
1727 * Is this HACK still applicable?
1730 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1731 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1734 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1736 fix_win16_hkey( &hkey
);
1737 if (count
) *count
&= 0xffff;
1738 return RegQueryValueA( hkey
, name
, data
, count
);
1741 /******************************************************************************
1742 * RegQueryValueEx [KERNEL.225]
1744 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1745 LPBYTE data
, LPDWORD count
)
1747 fix_win16_hkey( &hkey
);
1748 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1751 /******************************************************************************
1752 * RegSetValueEx [KERNEL.226]
1754 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1755 CONST BYTE
*data
, DWORD count
)
1757 fix_win16_hkey( &hkey
);
1758 if (!count
&& (type
==REG_SZ
)) count
= strlen(data
);
1759 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);
1762 /******************************************************************************
1763 * RegFlushKey [KERNEL.227]
1765 DWORD WINAPI
RegFlushKey16( HKEY hkey
)
1767 fix_win16_hkey( &hkey
);
1768 return RegFlushKey( hkey
);