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"
47 #include <sys/types.h>
50 #ifdef HAVE_SYS_MMAN_H
51 # include <sys/mman.h>
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
56 #ifdef HAVE_LINUX_HDREG_H
57 # include <linux/hdreg.h>
60 #define NONAMELESSUNION
61 #define NONAMELESSSTRUCT
69 #include "wine/winbase16.h"
70 #include "wine/library.h"
71 #include "wine/server.h"
72 #include "wine/unicode.h"
74 #include "wine/debug.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(reg
);
78 #define SAVE_GLOBAL_REGBRANCH_USER_DEFAULT "/wine.userreg"
79 #define SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE "/wine.systemreg"
81 /* relative in ~user/.wine/ : */
82 #define SAVE_LOCAL_REGBRANCH_CURRENT_USER "user.reg"
83 #define SAVE_LOCAL_REGBRANCH_USER_DEFAULT "userdef.reg"
84 #define SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE "system.reg"
86 #define MAX_PATHNAME_LEN 1024
88 static const WCHAR ClassesRootW
[] = {'M','a','c','h','i','n','e','\\',
89 'S','o','f','t','w','a','r','e','\\',
90 'C','l','a','s','s','e','s',0};
92 #define IS_OPTION_FALSE(ch) \
93 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
95 /* _xmalloc [Internal] */
96 static void *_xmalloc( size_t size
)
100 res
= malloc (size
? size
: 1);
102 WARN("Virtual memory exhausted.\n");
108 /* _xstrdup [Internal] */
109 static LPSTR
_xstrdup(LPCSTR str
)
112 size_t len
= strlen(str
) + 1;
114 if (!str
) return NULL
;
115 ret
= _xmalloc( len
);
116 memcpy( ret
, str
, len
);
120 /* convert ansi string to unicode [Internal] */
121 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
126 if (!strA
) return NULL
;
127 if (RtlMultiByteToUnicodeSize( &len
, strA
, lenA
) != STATUS_SUCCESS
) return NULL
;
129 ret
= _xmalloc(len
+sizeof(WCHAR
));
130 RtlMultiByteToUnicodeN(ret
, len
, NULL
, strA
, lenA
);
131 ret
[len
/ sizeof(WCHAR
)] = 0;
135 /* dump a Unicode string with proper escaping [Internal] */
136 /* FIXME: this code duplicates server/unicode.c */
137 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,const char escape
[2])
139 static const char escapes
[32] = ".......abtnvfr.............e....";
144 for (; len
; str
++, len
--)
146 if (pos
> buffer
+ sizeof(buffer
) - 8)
148 fwrite( buffer
, pos
- buffer
, 1, f
);
149 count
+= pos
- buffer
;
152 if (*str
> 127) /* hex escape */
154 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
155 pos
+= sprintf( pos
, "\\x%04x", *str
);
157 pos
+= sprintf( pos
, "\\x%x", *str
);
160 if (*str
< 32) /* octal or C escape */
162 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
163 if (escapes
[*str
] != '.')
164 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
165 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
166 pos
+= sprintf( pos
, "\\%03o", *str
);
168 pos
+= sprintf( pos
, "\\%o", *str
);
171 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
174 fwrite( buffer
, pos
- buffer
, 1, f
);
175 count
+= pos
- buffer
;
179 /* convert ansi string to unicode and dump with proper escaping [Internal] */
180 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,const char escape
[2])
185 if (strA
== NULL
) return 0;
186 strW
= _strdupnAtoW(strA
,len
);
187 ret
= _dump_strW(strW
,len
,f
,escape
);
193 /* FIXME: this code duplicates server/registry.c */
195 WCHAR
*nameW
; /* value name */
196 int type
; /* value type */
197 size_t len
; /* value data length in bytes */
198 void *data
; /* pointer to value data */
201 /* dump a value to a text file */
202 /* FIXME: this code duplicates server/registry.c */
203 static void _dump_value(struct key_value
*value
,FILE *f
)
207 if (value
->nameW
[0]) {
209 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
210 count
+= fprintf( f
, "\"=" );
212 else count
= fprintf( f
, "@=" );
214 switch(value
->type
) {
218 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
220 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
224 if (value
->len
== sizeof(DWORD
)) {
226 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
227 fprintf( f
, "dword:%08lx", dw
);
230 /* else fall through */
232 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
233 else count
+= fprintf( f
, "hex(%x):", value
->type
);
234 for (i
= 0; i
< value
->len
; i
++) {
235 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
236 if (i
< value
->len
-1) {
239 fprintf( f
, "\\\n " );
249 /******************************************************************/
250 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
252 reghack - windows 3.11 registry data format demo program.
254 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
255 a combined hash table and tree description, and finally a text table.
257 The header is obvious from the struct header. The taboff1 and taboff2
258 fields are always 0x20, and their usage is unknown.
260 The 8-byte entry table has various entry types.
262 tabent[0] is a root index. The second word has the index of the root of
264 tabent[1..hashsize] is a hash table. The first word in the hash entry is
265 the index of the key/value that has that hash. Data with the same
266 hash value are on a circular list. The other three words in the
267 hash entry are always zero.
268 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
269 entry: dirent and keyent/valent. They are identified by context.
270 tabent[freeidx] is the first free entry. The first word in a free entry
271 is the index of the next free entry. The last has 0 as a link.
272 The other three words in the free list are probably irrelevant.
274 Entries in text table are preceded by a word at offset-2. This word
275 has the value (2*index)+1, where index is the referring keyent/valent
276 entry in the table. I have no suggestion for the 2* and the +1.
277 Following the word, there are N bytes of data, as per the keyent/valent
278 entry length. The offset of the keyent/valent entry is from the start
279 of the text table to the first data byte.
281 This information is not available from Microsoft. The data format is
282 deduced from the reg.dat file by me. Mistakes may
283 have been made. I claim no rights and give no guarantees for this program.
285 Tor Sjøwall, tor@sn.no
288 /* reg.dat header format */
290 char cookie
[8]; /* 'SHCC3.10' */
291 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
292 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
293 unsigned long tabcnt
; /* number of entries in index table */
294 unsigned long textoff
; /* offset of text part */
295 unsigned long textsize
; /* byte size of text part */
296 unsigned short hashsize
; /* hash size */
297 unsigned short freeidx
; /* free index */
300 /* generic format of table entries */
302 unsigned short w0
, w1
, w2
, w3
;
305 /* directory tabent: */
307 unsigned short sibling_idx
; /* table index of sibling dirent */
308 unsigned short child_idx
; /* table index of child dirent */
309 unsigned short key_idx
; /* table index of key keyent */
310 unsigned short value_idx
; /* table index of value valent */
315 unsigned short hash_idx
; /* hash chain index for string */
316 unsigned short refcnt
; /* reference count */
317 unsigned short length
; /* length of string */
318 unsigned short string_off
; /* offset of string in text table */
323 unsigned short hash_idx
; /* hash chain index for string */
324 unsigned short refcnt
; /* reference count */
325 unsigned short length
; /* length of string */
326 unsigned short string_off
; /* offset of string in text table */
329 /* recursive helper function to display a directory tree [Internal] */
330 static void _w31_dumptree(unsigned short idx
, unsigned char *txt
,
331 struct _w31_tabent
*tab
, struct _w31_header
*head
,
332 HKEY hkey
, ULONG lastmodified
, int level
)
334 static const WCHAR classesW
[] = {'.','c','l','a','s','s','e','s',0};
335 struct _w31_dirent
*dir
;
336 struct _w31_keyent
*key
;
337 struct _w31_valent
*val
;
339 OBJECT_ATTRIBUTES attr
;
340 UNICODE_STRING nameW
, valueW
;
341 static WCHAR tail
[400];
343 attr
.Length
= sizeof(attr
);
344 attr
.RootDirectory
= hkey
;
345 attr
.ObjectName
= &nameW
;
347 attr
.SecurityDescriptor
= NULL
;
348 attr
.SecurityQualityOfService
= NULL
;
349 RtlInitUnicodeString( &valueW
, NULL
);
352 dir
=(struct _w31_dirent
*)&tab
[idx
];
356 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
358 RtlMultiByteToUnicodeN( tail
, sizeof(tail
)-sizeof(WCHAR
), &len
,
359 &txt
[key
->string_off
], key
->length
);
360 tail
[len
/sizeof(WCHAR
)] = 0;
362 /* all toplevel entries AND the entries in the
363 * toplevel subdirectory belong to \SOFTWARE\Classes
365 if (!level
&& !strcmpW(tail
,classesW
))
367 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
368 idx
=dir
->sibling_idx
;
372 if (subkey
) NtClose( subkey
);
373 RtlInitUnicodeString( &nameW
, tail
);
374 if (NtCreateKey( &subkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) subkey
= 0;
376 /* only add if leaf node or valued node */
377 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
378 if (dir
->value_idx
) {
380 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
381 RtlMultiByteToUnicodeN( tail
, sizeof(tail
) - sizeof(WCHAR
), &len
,
382 &txt
[val
->string_off
], val
->length
);
383 tail
[len
/sizeof(WCHAR
)] = 0;
384 NtSetValueKey( subkey
, &valueW
, 0, REG_SZ
, tail
, len
+ sizeof(WCHAR
) );
387 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
388 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
389 idx
=dir
->sibling_idx
;
391 if (subkey
) NtClose( subkey
);
395 /******************************************************************************
396 * _w31_loadreg [Internal]
398 static void _w31_loadreg(void)
402 OBJECT_ATTRIBUTES attr
;
403 UNICODE_STRING nameW
;
404 struct _w31_header head
;
405 struct _w31_tabent
* tab
= NULL
;
406 unsigned char* txt
= NULL
;
411 IO_STATUS_BLOCK iosb
;
412 FILE_POSITION_INFORMATION fpi
;
413 FILE_BASIC_INFORMATION fbi
;
417 hf
= (HANDLE
)OpenFile("reg.dat",&ofs
,OF_READ
);
418 if (hf
==(HANDLE
)HFILE_ERROR
) return;
420 /* read & dump header */
421 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
422 &head
, sizeof(head
), NULL
, NULL
) != STATUS_SUCCESS
||
423 iosb
.Information
!= sizeof(head
))
425 ERR("reg.dat is too short.\n");
428 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
)) != 0)
430 ERR("reg.dat has bad signature.\n");
434 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
435 /* read and dump index table */
437 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
438 tab
, len
, NULL
, NULL
) != STATUS_SUCCESS
||
439 iosb
.Information
!= len
)
441 ERR("couldn't read index table (%d bytes).\n",len
);
446 txt
= _xmalloc(head
.textsize
);
447 fpi
.CurrentByteOffset
.u
.LowPart
= head
.textoff
;
448 fpi
.CurrentByteOffset
.u
.HighPart
= 0;
449 if (NtSetInformationFile(hf
, &iosb
, &fpi
, sizeof(fpi
),
450 FilePositionInformation
) != STATUS_SUCCESS
)
452 ERR("couldn't seek to textblock.\n");
455 status
= NtReadFile(hf
, 0, NULL
, NULL
, &iosb
, txt
, head
.textsize
, NULL
, NULL
);
456 if (!(status
== STATUS_SUCCESS
|| status
== STATUS_END_OF_FILE
) ||
457 iosb
.Information
!= head
.textsize
)
459 ERR("textblock too short (%d instead of %ld).\n", len
, head
.textsize
);
462 if (NtQueryInformationFile(hf
, &iosb
, &fbi
, sizeof(fbi
),
463 FileBasicInformation
) != STATUS_SUCCESS
)
465 ERR("Couldn't get basic information.\n");
468 RtlTimeToSecondsSince1970(&fbi
.LastWriteTime
, &lastmodified
);
470 attr
.Length
= sizeof(attr
);
471 attr
.RootDirectory
= 0;
472 attr
.ObjectName
= &nameW
;
474 attr
.SecurityDescriptor
= NULL
;
475 attr
.SecurityQualityOfService
= NULL
;
476 RtlInitUnicodeString( &nameW
, ClassesRootW
);
478 if (!NtCreateKey( &root
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
480 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,root
,lastmodified
,0);
490 /***********************************************************************************/
491 /* windows 95 registry loader */
492 /***********************************************************************************/
494 /* SECTION 1: main header
498 #define W95_REG_CREG_ID 0x47455243
501 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
502 DWORD version
; /* ???? 0x00010000 */
503 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
504 DWORD uk2
; /* 0x0c */
505 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
511 /* SECTION 2: Directory information (tree structure)
513 * once on offset 0x20
515 * structure: [rgkn][dke]* (repeat till last_dke is reached)
517 #define W95_REG_RGKN_ID 0x4e4b4752
520 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
521 DWORD size
; /* Size of the RGKN-block */
522 DWORD root_off
; /* Rel. Offset of the root-record */
523 DWORD last_dke
; /* Offset to last DKE ? */
527 /* Disk Key Entry Structure
529 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
530 * hive itself. It looks the same like other keys. Even the ID-number can
533 * The "hash"-value is a value representing the key's name. Windows will not
534 * search for the name, but for a matching hash-value. if it finds one, it
535 * will compare the actual string info, otherwise continue with the next key.
536 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
537 * of the string which are smaller than 0x80 (128) to this D-Word.
539 * If you want to modify key names, also modify the hash-values, since they
540 * cannot be found again (although they would be displayed in REGEDIT)
541 * End of list-pointers are filled with 0xFFFFFFFF
543 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
544 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
545 * structure) and reading another RGDB_section.
547 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
548 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
549 * The remaining space between last_dke and the offset calculated from
550 * rgkn->size seems to be free for use for more dke:s.
551 * So it seems if more dke:s are added, they are added to that space and
552 * last_dke is grown, and in case that "free" space is out, the space
553 * gets grown and rgkn->size gets adjusted.
555 * there is a one to one relationship between dke and dkh
557 /* key struct, once per key */
559 DWORD x1
; /* Free entry indicator(?) */
560 DWORD hash
; /* sum of bytes of keyname */
561 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
562 DWORD prevlvl
; /* offset of previous key */
563 DWORD nextsub
; /* offset of child key */
564 DWORD next
; /* offset of sibling key */
565 WORD nrLS
; /* id inside the rgdb block */
566 WORD nrMS
; /* number of the rgdb block */
569 /* SECTION 3: key information, values and data
572 * section: [blocks]* (repeat creg->rgdb_num times)
573 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
574 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
576 * An interesting relationship exists in RGDB_section. The DWORD value
577 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
578 * I have no idea at the moment what this means. (Kevin Cozens)
581 /* block header, once per block */
582 #define W95_REG_RGDB_ID 0x42444752
585 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
586 DWORD size
; /* 0x04 */
587 DWORD uk1
; /* 0x08 */
588 DWORD uk2
; /* 0x0c */
589 DWORD uk3
; /* 0x10 */
590 DWORD uk4
; /* 0x14 */
591 DWORD uk5
; /* 0x18 */
592 DWORD uk6
; /* 0x1c */
596 /* Disk Key Header structure (RGDB part), once per key */
598 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
599 WORD nrLS
; /* 0x04 id inside the rgdb block */
600 WORD nrMS
; /* 0x06 number of the rgdb block */
601 DWORD bytesused
; /* 0x08 */
602 WORD keynamelen
; /* 0x0c len of name */
603 WORD values
; /* 0x0e number of values */
604 DWORD xx1
; /* 0x10 */
605 char name
[1]; /* 0x14 */
606 /* dkv */ /* 0x14 + keynamelen */
609 /* Disk Key Value structure, once per value */
611 DWORD type
; /* 0x00 */
613 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
614 WORD valdatalen
; /* 0x0A length of data */
615 char name
[1]; /* 0x0c */
616 /* raw data */ /* 0x0c + valnamelen */
619 /******************************************************************************
620 * _w95_lookup_dkh [Internal]
622 * seeks the dkh belonging to a dke
624 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
630 /* get the beginning of the rgdb datastore */
631 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
633 /* check: requested block < last_block) */
634 if (creg
->rgdb_num
<= nrMS
) {
635 ERR("registry file corrupt! requested block no. beyond end.\n");
639 /* find the right block */
640 for(i
=0; i
<nrMS
;i
++) {
641 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
642 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
645 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
648 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
651 if(nrLS
==dkh
->nrLS
) return dkh
;
652 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
653 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
659 /******************************************************************************
660 * _w95_dump_dkv [Internal]
662 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
667 /* first value block */
668 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
670 /* loop through the values */
671 for (i
=0; i
< dkh
->values
; i
++) {
672 struct key_value value
;
675 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
676 value
.type
= dkv
->type
;
677 value
.len
= dkv
->valdatalen
;
679 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
681 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
682 pdata
= _strdupnAtoW(value
.data
,value
.len
);
685 if (pdata
!= NULL
) value
.data
= pdata
;
687 _dump_value(&value
,f
);
689 if (pdata
!= NULL
) free(pdata
);
692 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
697 /******************************************************************************
698 * _w95_dump_dke [Internal]
700 static int _w95_dump_dke(LPCSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
703 LPSTR new_key_name
= NULL
;
705 /* special root key */
706 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
708 /* parse the one subkey */
709 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
710 /* has no sibling keys */
714 /* search subblock */
715 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
716 ERR("dke pointing to missing dkh !\n");
721 /* create new subkey name */
722 size_t len
= strlen(key_name
);
723 new_key_name
= _xmalloc(len
+dkh
->keynamelen
+2);
724 memcpy( new_key_name
, key_name
, len
);
725 if (len
) new_key_name
[len
++] = '\\';
726 memcpy( new_key_name
+ len
, dkh
->name
, dkh
->keynamelen
);
727 new_key_name
[len
+ dkh
->keynamelen
] = 0;
729 /* walk sibling keys */
730 if (dke
->next
!= 0xffffffff ) {
731 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
737 /* write the key path (something like [Software\\Microsoft\\..]) only if:
738 1) key has some values
739 2) key has no values and no subkeys
741 if (dkh
->values
> 0) {
742 /* there are some values */
744 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
746 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
751 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
752 /* no subkeys and no values */
754 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
757 } else new_key_name
= _xstrdup(key_name
);
760 if (dke
->nextsub
!= 0xffffffff) {
761 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
770 /* end windows 95 loader */
772 /***********************************************************************************/
773 /* windows NT registry loader */
774 /***********************************************************************************/
776 /* NT REGISTRY LOADER */
778 #ifdef HAVE_SYS_MMAN_H
779 # include <sys/mman.h>
783 #define MAP_FAILED ((LPVOID)-1)
786 #define NT_REG_BLOCK_SIZE 0x1000
788 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
789 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
790 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
791 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
793 /* subblocks of nk */
794 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
795 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
796 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
798 #define NT_REG_KEY_BLOCK_TYPE 0x20
799 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
802 DWORD id
; /* 0x66676572 'regf'*/
803 DWORD uk1
; /* 0x04 */
804 DWORD uk2
; /* 0x08 */
805 FILETIME DateModified
; /* 0x0c */
806 DWORD uk3
; /* 0x14 */
807 DWORD uk4
; /* 0x18 */
808 DWORD uk5
; /* 0x1c */
809 DWORD uk6
; /* 0x20 */
810 DWORD RootKeyBlock
; /* 0x24 */
811 DWORD BlockSize
; /* 0x28 */
813 DWORD Checksum
; /* at offset 0x1FC */
822 DWORD id
; /* 0x6E696268 'hbin' */
826 DWORD uk2
; /* 0x10 */
827 DWORD uk3
; /* 0x14 */
828 DWORD uk4
; /* 0x18 */
829 DWORD size
; /* 0x1C */
830 nt_hbin_sub hbin_sub
; /* 0x20 */
834 * the value_list consists of offsets to the values (vk)
837 WORD SubBlockId
; /* 0x00 0x6B6E */
838 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
839 FILETIME writetime
; /* 0x04 */
840 DWORD uk1
; /* 0x0C */
841 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
842 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
843 DWORD uk8
; /* 0x18 */
844 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
845 DWORD uk2
; /* 0x20 */
846 DWORD nr_values
; /* 0x24 number of values */
847 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
848 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
849 DWORD off_class
; /* 0x30 Offset of the Class-Name */
850 DWORD uk3
; /* 0x34 */
851 DWORD uk4
; /* 0x38 */
852 DWORD uk5
; /* 0x3c */
853 DWORD uk6
; /* 0x40 */
854 DWORD uk7
; /* 0x44 */
855 WORD name_len
; /* 0x48 name-length */
856 WORD class_len
; /* 0x4a class-name length */
857 char name
[1]; /* 0x4c key-name */
861 DWORD off_nk
; /* 0x00 */
862 DWORD name
; /* 0x04 */
866 WORD id
; /* 0x00 0x666c */
867 WORD nr_keys
; /* 0x06 */
868 hash_rec hash_rec
[1];
872 list of subkeys without hash
879 WORD id
; /* 0x00 0x696c */
885 this is a intermediate node
896 WORD id
; /* 0x00 0x6972 */
897 WORD nr_li
; /* 0x02 number off offsets */
898 DWORD off_li
[1]; /* 0x04 points to li */
902 WORD id
; /* 0x00 'vk' */
916 * 0 value is a default value
917 * 1 the value has a name
920 * len of the whole data block
922 * bytes including the terminating \0 = 2*(number_of_chars+1)
923 * - reg_dword, reg_binary:
924 * if highest bit of data_len is set data_off contains the value
926 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
928 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
929 struct key_value value
;
931 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
932 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
936 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
937 value
.type
= vk
->type
;
938 value
.len
= (vk
->data_len
& 0x7fffffff);
939 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
941 _dump_value(&value
,f
);
947 /* it's called from _nt_dump_lf() */
948 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
953 * this structure contains the hash of a keyname and points to all
956 * exception: if the id is 'il' there are no hash values and every
959 static int _nt_dump_lf(LPCSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
963 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
964 if (subkeys
!= lf
->nr_keys
) goto error1
;
966 for (i
=0; i
<lf
->nr_keys
; i
++)
967 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
968 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
969 nt_li
* li
= (nt_li
*)lf
;
970 if (subkeys
!= li
->nr_keys
) goto error1
;
972 for (i
=0; i
<li
->nr_keys
; i
++)
973 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
974 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
975 nt_ri
* ri
= (nt_ri
*)lf
;
978 /* count all subkeys */
979 for (i
=0; i
<ri
->nr_li
; i
++) {
980 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
981 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
982 li_subkeys
+= li
->nr_keys
;
986 if (subkeys
!= li_subkeys
) goto error1
;
988 /* loop through the keys */
989 for (i
=0; i
<ri
->nr_li
; i
++) {
990 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
991 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
998 if (lf
->id
== 0x686c)
999 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
1001 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
1005 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
1009 ERR("error reading lf block\n");
1013 /* _nt_dump_nk [Internal] */
1014 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
1018 LPSTR new_key_name
= NULL
;
1020 TRACE("%s\n", key_name
);
1022 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
1023 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
1027 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
1028 ERR("registry file corrupt!\n");
1032 /* create the new key */
1034 /* create new subkey name */
1035 size_t len
= strlen(key_name
);
1036 new_key_name
= _xmalloc( len
+nk
->name_len
+2 );
1037 memcpy( new_key_name
, key_name
, len
);
1038 if (len
) new_key_name
[len
++] = '\\';
1039 memcpy( new_key_name
+ len
, nk
->name
, nk
->name_len
);
1040 new_key_name
[len
+ nk
->name_len
] = 0;
1042 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1043 1) key has some values
1044 2) key has no values and no subkeys
1046 if (nk
->nr_values
> 0) {
1047 /* there are some values */
1049 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1052 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
1053 /* no subkeys and no values */
1055 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1059 /* loop trough the value list */
1060 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
1061 for (n
=0; n
<nk
->nr_values
; n
++) {
1062 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
1063 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
1068 } else new_key_name
= _xstrdup(key_name
);
1070 /* loop through the subkeys */
1071 if (nk
->nr_subkeys
) {
1072 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
1073 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
1085 /**********************************************************************************
1086 * _set_registry_levels [Internal]
1088 * set level to 0 for loading system files
1089 * set level to 1 for loading user files
1091 static void _set_registry_levels(int level
,int saving
,int period
)
1093 SERVER_START_REQ( set_registry_levels
)
1095 req
->current
= level
;
1096 req
->saving
= saving
;
1097 req
->period
= period
;
1098 wine_server_call( req
);
1103 /* _save_at_exit [Internal] */
1104 static void _save_at_exit(HKEY hkey
,LPCSTR path
)
1106 LPCSTR confdir
= wine_get_config_dir();
1108 SERVER_START_REQ( save_registry_atexit
)
1111 wine_server_add_data( req
, confdir
, strlen(confdir
) );
1112 wine_server_add_data( req
, path
, strlen(path
)+1 );
1113 wine_server_call( req
);
1118 /******************************************************************************
1119 * _allocate_default_keys [Internal]
1120 * Registry initialisation, allocates some default keys.
1122 static void _allocate_default_keys(void)
1124 static const WCHAR StatDataW
[] = {'D','y','n','D','a','t','a','\\',
1125 'P','e','r','f','S','t','a','t','s','\\',
1126 'S','t','a','t','D','a','t','a',0};
1128 OBJECT_ATTRIBUTES attr
;
1129 UNICODE_STRING nameW
;
1133 attr
.Length
= sizeof(attr
);
1134 attr
.RootDirectory
= 0;
1135 attr
.ObjectName
= &nameW
;
1136 attr
.Attributes
= 0;
1137 attr
.SecurityDescriptor
= NULL
;
1138 attr
.SecurityQualityOfService
= NULL
;
1140 RtlInitUnicodeString( &nameW
, StatDataW
);
1141 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1144 static void get_windows_dir(WCHAR
* buffer
, unsigned len
)
1146 OBJECT_ATTRIBUTES attr
;
1147 UNICODE_STRING nameW
, keyW
;
1150 attr
.Length
= sizeof(attr
);
1151 attr
.RootDirectory
= 0;
1152 attr
.ObjectName
= &nameW
;
1153 attr
.Attributes
= 0;
1154 attr
.SecurityDescriptor
= NULL
;
1155 attr
.SecurityQualityOfService
= NULL
;
1157 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1159 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
1161 char tmp
[MAX_PATHNAME_LEN
*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1164 RtlCreateUnicodeStringFromAsciiz( &keyW
, "Windows");
1165 if (!NtQueryValueKey( hkey
, &keyW
, KeyValuePartialInformation
,
1166 tmp
, sizeof(tmp
), &count
))
1168 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1169 memcpy(buffer
, str
, min(((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->DataLength
, len
));
1171 RtlFreeUnicodeString( &keyW
);
1173 RtlFreeUnicodeString( &nameW
);
1178 #define REG_DONTLOAD -1
1183 /* return the type of native registry [Internal] */
1184 static int _get_reg_type(const WCHAR
* windir
)
1186 WCHAR tmp
[MAX_PATHNAME_LEN
];
1187 int ret
= REG_WIN31
;
1188 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};
1189 static const WCHAR win9x_reg_pathW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1191 /* test %windir%/system32/config/system --> winnt */
1192 strcpyW(tmp
, windir
);
1193 strcatW(tmp
, nt_reg_pathW
);
1194 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1198 /* test %windir%/system.dat --> win95 */
1199 strcpyW(tmp
, windir
);
1200 strcatW(tmp
, win9x_reg_pathW
);
1201 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1208 /* load the registry file in wine format [Internal] */
1209 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1214 UNICODE_STRING name
;
1215 OBJECT_ATTRIBUTES attr
;
1218 len
= MultiByteToWideChar( CP_UNIXCP
, 0, fn
, -1, NULL
, 0 );
1219 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return;
1220 MultiByteToWideChar( CP_UNIXCP
, 0, fn
, -1, buffer
, len
);
1221 RtlInitUnicodeString( &name
, buffer
);
1223 attr
.Length
= sizeof(attr
);
1224 attr
.RootDirectory
= 0;
1225 attr
.Attributes
= 0;
1226 attr
.ObjectName
= &name
;
1227 attr
.SecurityDescriptor
= NULL
;
1228 attr
.SecurityQualityOfService
= NULL
;
1230 if (!NtOpenFile( &file
, GENERIC_READ
, &attr
, &io
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1231 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
))
1233 SERVER_START_REQ( load_registry
)
1237 wine_server_call( req
);
1240 CloseHandle( file
);
1242 HeapFree( GetProcessHeap(), 0, buffer
);
1245 /* generate and return the name of the tmp file and associated stream [Internal] */
1246 static LPSTR
_get_tmp_fn(FILE **f
)
1253 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1254 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1255 if (errno
!= EEXIST
) {
1256 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1263 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1264 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1273 /* convert win95 native registry file to wine format [Internal] */
1274 static LPSTR
_convert_win95_registry_to_wine_format(LPCWSTR fn
, int level
)
1276 HANDLE hFile
, hMapping
;
1280 OBJECT_ATTRIBUTES attr
;
1281 LARGE_INTEGER lg_int
;
1287 _w95dke
*dke
, *root_dke
;
1289 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1290 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1292 attr
.Length
= sizeof(attr
);
1293 attr
.RootDirectory
= 0;
1294 attr
.ObjectName
= NULL
;
1295 attr
.Attributes
= 0;
1296 attr
.SecurityDescriptor
= NULL
;
1297 attr
.SecurityQualityOfService
= NULL
;
1299 lg_int
.QuadPart
= 0;
1300 nts
= NtCreateSection( &hMapping
,
1301 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1302 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1303 if (nts
!= STATUS_SUCCESS
) goto error1
;
1305 base
= NULL
; len
= 0;
1306 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1307 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1309 NtClose( hMapping
);
1310 if (nts
!= STATUS_SUCCESS
) goto error1
;
1312 /* control signature */
1313 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1314 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1320 /* load the header (rgkn) */
1321 rgkn
= (_w95rgkn
*)(creg
+ 1);
1322 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1323 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1326 if (rgkn
->root_off
!= 0x20) {
1327 ERR("rgkn->root_off not 0x20, please report !\n");
1330 if (rgkn
->last_dke
> rgkn
->size
)
1332 ERR("registry file corrupt! last_dke > size!\n");
1335 /* verify last dke */
1336 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1337 if (dke
->x1
!= 0x80000000)
1339 ERR("last dke invalid !\n");
1342 if (rgkn
->size
> creg
->rgdb_off
)
1344 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1347 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1348 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1350 ERR("registry file corrupt! invalid root dke !\n");
1354 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1355 fprintf(f
,"WINE REGISTRY Version 2");
1356 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1361 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn
));
1362 ERR("Please report this.\n");
1363 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1366 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1372 /* convert winnt native registry file to wine format [Internal] */
1373 static LPSTR
_convert_winnt_registry_to_wine_format(LPCWSTR fn
, int level
)
1380 OBJECT_ATTRIBUTES attr
;
1381 LARGE_INTEGER lg_int
;
1387 nt_hbin_sub
*hbin_sub
;
1390 TRACE("%s\n", debugstr_w(fn
));
1392 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1393 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1394 attr
.Length
= sizeof(attr
);
1395 attr
.RootDirectory
= 0;
1396 attr
.ObjectName
= NULL
;
1397 attr
.Attributes
= 0;
1398 attr
.SecurityDescriptor
= NULL
;
1399 attr
.SecurityQualityOfService
= NULL
;
1401 lg_int
.QuadPart
= 0;
1402 nts
= NtCreateSection( &hMapping
,
1403 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1404 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1405 if (nts
!= STATUS_SUCCESS
) goto error1
;
1407 base
= NULL
; len
= 0;
1408 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1409 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1411 NtClose( hMapping
);
1412 if (nts
!= STATUS_SUCCESS
) goto error1
;
1414 /* control signature */
1415 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1416 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1425 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1426 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1427 ERR( "hbin block invalid\n");
1431 /* hbin_sub block */
1432 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1433 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1434 ERR( "hbin_sub block invalid\n");
1439 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1440 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1441 ERR( "special nk block not found\n");
1445 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1446 fprintf(f
,"WINE REGISTRY Version 2");
1447 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1451 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1457 /* convert native registry to wine format and load it via server call [Internal] */
1458 static void _convert_and_load_native_registry(LPCWSTR fn
, HKEY hkey
, int reg_type
, int level
)
1464 /* FIXME: following function doesn't really convert yet */
1465 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1468 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1471 ERR("Don't know how to convert native 3.1 registry yet.\n");
1474 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1479 load_wine_registry(hkey
,tmp
);
1480 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1481 debugstr_w(fn
), tmp
);
1484 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn
));
1488 /* load all native windows registry files [Internal] */
1489 static void _load_windows_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1490 HKEY hkey_users_default
)
1493 WCHAR windir
[MAX_PATHNAME_LEN
];
1494 WCHAR path
[MAX_PATHNAME_LEN
];
1495 OBJECT_ATTRIBUTES attr
;
1496 UNICODE_STRING nameW
;
1497 HKEY hkey
, profile_key
;
1501 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
1502 'S','o','f','t','w','a','r','e','\\',
1503 'W','i','n','e','\\','W','i','n','e','\\',
1504 'C','o','n','f','i','g','\\','W','i','n','e',0};
1505 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1506 static const WCHAR System
[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1507 static const WCHAR Software
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1508 static const WCHAR Clone
[] = {'M','a','c','h','i','n','e','\\',
1509 'S','y','s','t','e','m','\\',
1510 'C','l','o','n','e',0};
1512 attr
.Length
= sizeof(attr
);
1513 attr
.RootDirectory
= 0;
1514 attr
.ObjectName
= &nameW
;
1515 attr
.Attributes
= 0;
1516 attr
.SecurityDescriptor
= NULL
;
1517 attr
.SecurityQualityOfService
= NULL
;
1519 RtlInitUnicodeString( &nameW
, WineW
);
1520 if (NtCreateKey( &profile_key
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) profile_key
= 0;
1522 get_windows_dir(windir
, sizeof(windir
));
1524 reg_type
= _get_reg_type(windir
);
1527 static const WCHAR ntuser_datW
[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1528 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};
1529 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};
1530 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};
1531 static const WCHAR samW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1532 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};
1534 /* user specific ntuser.dat */
1535 RtlInitUnicodeString( &nameW
, ProfileW
);
1536 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1537 tmp
, sizeof(tmp
), &dummy
))
1539 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1540 strcatW(path
, ntuser_datW
);
1541 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WINNT
,1);
1545 MESSAGE("When you are running with a native NT directory specify\n");
1546 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1547 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1551 /* default user.dat */
1552 if (hkey_users_default
) {
1553 strcpyW(path
, windir
);
1554 strcatW(path
, defaultW
);
1555 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1560 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1562 RtlInitUnicodeString( &nameW
, System
);
1563 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1565 strcpyW(path
, windir
);
1566 strcatW(path
, systemW
);
1567 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1570 RtlInitUnicodeString( &nameW
, Software
);
1571 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1573 strcpyW(path
, windir
);
1574 strcatW(path
, softwareW
);
1575 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1579 strcpyW(path
, windir
);
1580 strcatW(path
, samW
);
1581 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1583 strcpyW(path
,windir
);
1584 strcatW(path
, securityW
);
1585 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1587 /* this key is generated when the nt-core booted successfully */
1588 RtlInitUnicodeString( &nameW
, Clone
);
1589 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1595 static const WCHAR system_1stW
[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1596 static const WCHAR system_datW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1597 static const WCHAR classes_datW
[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1598 static const WCHAR user_datW
[] = {'\\','u','s','e','r','.','d','a','t',0};
1600 _convert_and_load_native_registry(system_1stW
,hkey_local_machine
,REG_WIN95
,0);
1602 strcpyW(path
, windir
);
1603 strcatW(path
, system_datW
);
1604 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WIN95
,0);
1606 RtlInitUnicodeString( &nameW
, ClassesRootW
);
1607 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1609 strcpyW(path
, windir
);
1610 strcatW(path
, classes_datW
);
1611 _convert_and_load_native_registry(path
,hkey
,REG_WIN95
,0);
1615 RtlInitUnicodeString( &nameW
, ProfileW
);
1616 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1617 tmp
, sizeof(tmp
), &dummy
))
1619 /* user specific user.dat */
1620 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1621 strcatW(path
, user_datW
);
1622 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1624 /* default user.dat */
1625 if (hkey_users_default
) {
1626 strcpyW(path
, windir
);
1627 strcatW(path
, user_datW
);
1628 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1631 strcpyW(path
, windir
);
1632 strcatW(path
, user_datW
);
1633 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1639 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1644 TRACE("REG_DONTLOAD\n");
1648 ERR("switch: no match (%d)\n",reg_type
);
1652 if (profile_key
) NtClose( profile_key
);
1655 /* load home registry files (stored in ~/.wine) [Internal] */
1656 static void _load_home_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1657 HKEY hkey_users_default
)
1659 LPCSTR confdir
= wine_get_config_dir();
1660 LPSTR tmp
= _xmalloc(strlen(confdir
)+20);
1662 strcpy(tmp
,confdir
);
1663 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
1664 load_wine_registry(hkey_users_default
,tmp
);
1666 strcpy(tmp
,confdir
);
1667 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
1668 load_wine_registry(hkey_current_user
,tmp
);
1670 strcpy(tmp
,confdir
);
1671 strcat(tmp
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
1672 load_wine_registry(hkey_local_machine
,tmp
);
1678 /******************************************************************
1679 * init_cdrom_registry
1681 * Initializes registry to contain scsi info about the cdrom in NT.
1682 * All devices (even not real scsi ones) have this info in NT.
1683 * TODO: for now it only works for non scsi devices
1684 * NOTE: programs usually read these registry entries after sending the
1685 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1687 static void init_cdrom_registry( HANDLE handle
)
1689 OBJECT_ATTRIBUTES attr
;
1690 UNICODE_STRING nameW
;
1702 SCSI_ADDRESS scsi_addr
;
1704 if (NtDeviceIoControlFile( handle
, 0, NULL
, NULL
, &io
, IOCTL_SCSI_GET_ADDRESS
,
1705 NULL
, 0, &scsi_addr
, sizeof(scsi_addr
) ))
1708 attr
.Length
= sizeof(attr
);
1709 attr
.RootDirectory
= 0;
1710 attr
.ObjectName
= &nameW
;
1711 attr
.Attributes
= 0;
1712 attr
.SecurityDescriptor
= NULL
;
1713 attr
.SecurityQualityOfService
= NULL
;
1715 /* Ensure there is Scsi key */
1716 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1717 NtCreateKey( &scsiKey
, KEY_ALL_ACCESS
, &attr
, 0,
1718 NULL
, REG_OPTION_VOLATILE
, &disp
))
1720 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1723 RtlFreeUnicodeString( &nameW
);
1725 snprintf(buffer
,sizeof(buffer
),"Scsi Port %d",scsi_addr
.PortNumber
);
1726 attr
.RootDirectory
= scsiKey
;
1727 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1728 NtCreateKey( &portKey
, KEY_ALL_ACCESS
, &attr
, 0,
1729 NULL
, REG_OPTION_VOLATILE
, &disp
))
1731 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1734 RtlFreeUnicodeString( &nameW
);
1736 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Driver" );
1738 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1739 NtSetValueKey( portKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1740 RtlFreeUnicodeString( &nameW
);
1742 RtlCreateUnicodeStringFromAsciiz( &nameW
, "FirstBusTimeScanInMs" );
1743 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
1744 RtlFreeUnicodeString( &nameW
);
1749 if (!wine_server_handle_to_fd( handle
, 0, &fd
, NULL
, NULL
))
1751 if (ioctl(fd
,HDIO_GET_DMA
, &dma
) != -1) value
= dma
;
1752 wine_server_release_fd( handle
, fd
);
1756 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DMAEnabled" );
1757 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
1758 RtlFreeUnicodeString( &nameW
);
1760 snprintf(buffer
,40,"Scsi Bus %d", scsi_addr
.PathId
);
1761 attr
.RootDirectory
= portKey
;
1762 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1763 NtCreateKey( &busKey
, KEY_ALL_ACCESS
, &attr
, 0,
1764 NULL
, REG_OPTION_VOLATILE
, &disp
))
1766 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1769 RtlFreeUnicodeString( &nameW
);
1771 attr
.RootDirectory
= busKey
;
1772 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Initiator Id 255" ) ||
1773 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
1774 NULL
, REG_OPTION_VOLATILE
, &disp
))
1776 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1779 RtlFreeUnicodeString( &nameW
);
1780 NtClose( targetKey
);
1782 snprintf(buffer
,40,"Target Id %d", scsi_addr
.TargetId
);
1783 attr
.RootDirectory
= busKey
;
1784 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1785 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
1786 NULL
, REG_OPTION_VOLATILE
, &disp
))
1788 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1791 RtlFreeUnicodeString( &nameW
);
1793 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Type" );
1794 data
= "CdRomPeripheral";
1795 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1796 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1797 RtlFreeUnicodeString( &nameW
);
1798 /* FIXME - maybe read the real identifier?? */
1799 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Identifier" );
1800 data
= "Wine CDROM";
1801 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1802 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1803 RtlFreeUnicodeString( &nameW
);
1804 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1805 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DeviceName" );
1807 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1808 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1809 RtlFreeUnicodeString( &nameW
);
1811 NtClose( targetKey
);
1818 /* create the hardware registry branch */
1819 static void create_hardware_branch(void)
1823 char drive
[] = "\\\\.\\A:";
1825 /* create entries for cdroms */
1826 for (i
= 0; i
< 26; i
++)
1829 handle
= CreateFileA( drive
, 0, 0, NULL
, OPEN_EXISTING
, 0, 0 );
1830 if (handle
== INVALID_HANDLE_VALUE
) continue;
1831 init_cdrom_registry( handle
);
1832 CloseHandle( handle
);
1837 /* convert the drive type entries from the old format to the new one */
1838 static void convert_drive_types(void)
1840 static const WCHAR TypeW
[] = {'T','y','p','e',0};
1841 static const WCHAR drive_types_keyW
[] = {'M','a','c','h','i','n','e','\\',
1842 'S','o','f','t','w','a','r','e','\\',
1843 'W','i','n','e','\\',
1844 'D','r','i','v','e','s',0 };
1845 WCHAR driveW
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1846 'W','i','n','e','\\','W','i','n','e','\\',
1847 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1848 char tmp
[32*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1849 OBJECT_ATTRIBUTES attr
;
1850 UNICODE_STRING nameW
;
1853 HKEY hkey_old
, hkey_new
;
1856 attr
.Length
= sizeof(attr
);
1857 attr
.RootDirectory
= 0;
1858 attr
.ObjectName
= &nameW
;
1859 attr
.Attributes
= 0;
1860 attr
.SecurityDescriptor
= NULL
;
1861 attr
.SecurityQualityOfService
= NULL
;
1862 RtlInitUnicodeString( &nameW
, drive_types_keyW
);
1864 if (NtCreateKey( &hkey_new
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
)) return;
1865 if (disp
!= REG_CREATED_NEW_KEY
) return;
1867 for (i
= 0; i
< 26; i
++)
1869 RtlInitUnicodeString( &nameW
, driveW
);
1870 nameW
.Buffer
[(nameW
.Length
/ sizeof(WCHAR
)) - 1] = 'A' + i
;
1871 if (NtOpenKey( &hkey_old
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
) continue;
1872 RtlInitUnicodeString( &nameW
, TypeW
);
1873 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
1875 WCHAR valueW
[] = {'A',':',0};
1876 WCHAR
*type
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1878 valueW
[0] = 'A' + i
;
1879 RtlInitUnicodeString( &nameW
, valueW
);
1880 NtSetValueKey( hkey_new
, &nameW
, 0, REG_SZ
, type
, (strlenW(type
) + 1) * sizeof(WCHAR
) );
1881 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1882 'A' + i
, debugstr_w(type
) );
1884 NtClose( hkey_old
);
1886 NtClose( hkey_new
);
1890 /* load all registry (native and global and home) */
1891 void SHELL_LoadRegistry( void )
1893 HKEY hkey_local_machine
, hkey_users
, hkey_users_default
, hkey_current_user
, hkey_config
;
1894 OBJECT_ATTRIBUTES attr
;
1895 UNICODE_STRING nameW
;
1902 static const WCHAR MachineW
[] = {'M','a','c','h','i','n','e',0};
1903 static const WCHAR UserW
[] = {'U','s','e','r',0};
1904 static const WCHAR DefaultW
[] = {'.','D','e','f','a','u','l','t',0};
1905 static const WCHAR RegistryW
[] = {'M','a','c','h','i','n','e','\\',
1906 'S','o','f','t','w','a','r','e','\\',
1907 'W','i','n','e','\\',
1908 'W','i','n','e','\\',
1909 'C','o','n','f','i','g','\\',
1910 'R','e','g','i','s','t','r','y',0};
1911 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};
1912 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};
1913 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};
1914 static const WCHAR SaveOnlyUpdatedKeysW
[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1915 static const WCHAR PeriodicSaveW
[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1916 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};
1917 static const WCHAR GlobalRegistryDirW
[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1921 attr
.Length
= sizeof(attr
);
1922 attr
.RootDirectory
= 0;
1923 attr
.ObjectName
= &nameW
;
1924 attr
.Attributes
= 0;
1925 attr
.SecurityDescriptor
= NULL
;
1926 attr
.SecurityQualityOfService
= NULL
;
1928 RtlInitUnicodeString( &nameW
, UserW
);
1929 NtCreateKey( &hkey_users
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &dispos
);
1930 if (dispos
== REG_OPENED_EXISTING_KEY
)
1932 /* someone else already loaded the registry */
1933 NtClose( hkey_users
);
1937 RtlInitUnicodeString( &nameW
, MachineW
);
1938 NtCreateKey( &hkey_local_machine
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
1940 attr
.RootDirectory
= hkey_users
;
1941 RtlInitUnicodeString( &nameW
, DefaultW
);
1942 if (NtCreateKey( &hkey_users_default
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1944 ERR("Cannot create HKEY_USERS/.Default\n" );
1947 RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey_current_user
);
1949 _set_registry_levels(0,0,0);
1950 _allocate_default_keys();
1952 attr
.RootDirectory
= 0;
1953 RtlInitUnicodeString( &nameW
, RegistryW
);
1954 if (NtOpenKey( &hkey_config
, KEY_ALL_ACCESS
, &attr
)) hkey_config
= 0;
1956 /* load windows registry if required */
1959 attr
.RootDirectory
= hkey_config
;
1960 RtlInitUnicodeString( &nameW
, load_win_reg_filesW
);
1961 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1963 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1964 res
= !IS_OPTION_FALSE(str
[0]);
1966 if (res
) _load_windows_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
1968 /* load global registry if required */
1971 RtlInitUnicodeString( &nameW
, load_global_reg_filesW
);
1972 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1974 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1975 res
= !IS_OPTION_FALSE(str
[0]);
1979 /* load global registry files (stored in /etc/wine) */
1980 char *p
, configfile
[MAX_PATHNAME_LEN
];
1982 /* Override ETCDIR? */
1984 RtlInitUnicodeString( &nameW
, GlobalRegistryDirW
);
1985 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
1987 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1988 RtlUnicodeToMultiByteN( configfile
, sizeof(configfile
), NULL
,
1989 str
, (strlenW(str
) + 1) * sizeof(WCHAR
));
1991 if (configfile
[0] != '/') strcpy(configfile
, ETCDIR
);
1993 TRACE("GlobalRegistryDir is '%s'.\n", configfile
);
1995 /* Load the global HKU hive directly from sysconfdir */
1996 p
= configfile
+ strlen(configfile
);
1997 strcpy(p
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
1998 load_wine_registry( hkey_users
, configfile
);
2000 /* Load the global machine defaults directly from sysconfdir */
2001 strcpy(p
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
2002 load_wine_registry( hkey_local_machine
, configfile
);
2005 _set_registry_levels(1,0,0);
2007 /* load home registry if required */
2010 RtlInitUnicodeString( &nameW
, load_home_reg_filesW
);
2011 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2013 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2014 res
= !IS_OPTION_FALSE(str
[0]);
2016 if (res
) _load_home_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
2018 /* create hardware registry branch */
2020 create_hardware_branch();
2022 /* setup registry saving */
2025 RtlInitUnicodeString( &nameW
, SaveOnlyUpdatedKeysW
);
2026 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2028 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2029 all
= IS_OPTION_FALSE(str
[0]);
2033 RtlInitUnicodeString( &nameW
, PeriodicSaveW
);
2034 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2036 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2037 period
= (int)strtolW(str
, NULL
, 10);
2040 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
2041 _set_registry_levels(1,!all
,period
*1000);
2043 /* setup keys to save */
2046 RtlInitUnicodeString( &nameW
, WritetoHomeRegistryFilesW
);
2047 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2049 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2050 res
= !IS_OPTION_FALSE(str
[0]);
2054 _save_at_exit(hkey_current_user
,"/" SAVE_LOCAL_REGBRANCH_CURRENT_USER
);
2055 _save_at_exit(hkey_local_machine
,"/" SAVE_LOCAL_REGBRANCH_LOCAL_MACHINE
);
2056 _save_at_exit(hkey_users_default
,"/" SAVE_LOCAL_REGBRANCH_USER_DEFAULT
);
2059 /* convert keys from config file to new registry format */
2061 convert_drive_types();
2063 NtClose(hkey_users_default
);
2064 NtClose(hkey_current_user
);
2065 NtClose(hkey_users
);
2066 NtClose(hkey_local_machine
);
2067 NtClose(hkey_config
);