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 #define MAX_PATHNAME_LEN 1024
83 static const WCHAR ClassesRootW
[] = {'M','a','c','h','i','n','e','\\',
84 'S','o','f','t','w','a','r','e','\\',
85 'C','l','a','s','s','e','s',0};
87 #define IS_OPTION_FALSE(ch) \
88 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
90 /* _xmalloc [Internal] */
91 static void *_xmalloc( size_t size
)
95 res
= malloc (size
? size
: 1);
97 WARN("Virtual memory exhausted.\n");
103 /* _xstrdup [Internal] */
104 static LPSTR
_xstrdup(LPCSTR str
)
107 size_t len
= strlen(str
) + 1;
109 if (!str
) return NULL
;
110 ret
= _xmalloc( len
);
111 memcpy( ret
, str
, len
);
115 /* convert ansi string to unicode [Internal] */
116 static LPWSTR
_strdupnAtoW(LPCSTR strA
,size_t lenA
)
121 if (!strA
) return NULL
;
122 if (RtlMultiByteToUnicodeSize( &len
, strA
, lenA
) != STATUS_SUCCESS
) return NULL
;
124 ret
= _xmalloc(len
+sizeof(WCHAR
));
125 RtlMultiByteToUnicodeN(ret
, len
, NULL
, strA
, lenA
);
126 ret
[len
/ sizeof(WCHAR
)] = 0;
130 /* dump a Unicode string with proper escaping [Internal] */
131 /* FIXME: this code duplicates server/unicode.c */
132 static int _dump_strW(const WCHAR
*str
,size_t len
,FILE *f
,const char escape
[2])
134 static const char escapes
[32] = ".......abtnvfr.............e....";
139 for (; len
; str
++, len
--)
141 if (pos
> buffer
+ sizeof(buffer
) - 8)
143 fwrite( buffer
, pos
- buffer
, 1, f
);
144 count
+= pos
- buffer
;
147 if (*str
> 127) /* hex escape */
149 if (len
> 1 && str
[1] < 128 && isxdigit((char)str
[1]))
150 pos
+= sprintf( pos
, "\\x%04x", *str
);
152 pos
+= sprintf( pos
, "\\x%x", *str
);
155 if (*str
< 32) /* octal or C escape */
157 if (!*str
&& len
== 1) continue; /* do not output terminating NULL */
158 if (escapes
[*str
] != '.')
159 pos
+= sprintf( pos
, "\\%c", escapes
[*str
] );
160 else if (len
> 1 && str
[1] >= '0' && str
[1] <= '7')
161 pos
+= sprintf( pos
, "\\%03o", *str
);
163 pos
+= sprintf( pos
, "\\%o", *str
);
166 if (*str
== '\\' || *str
== escape
[0] || *str
== escape
[1]) *pos
++ = '\\';
169 fwrite( buffer
, pos
- buffer
, 1, f
);
170 count
+= pos
- buffer
;
174 /* convert ansi string to unicode and dump with proper escaping [Internal] */
175 static int _dump_strAtoW(LPCSTR strA
,size_t len
,FILE *f
,const char escape
[2])
180 if (strA
== NULL
) return 0;
181 strW
= _strdupnAtoW(strA
,len
);
182 ret
= _dump_strW(strW
,len
,f
,escape
);
188 /* FIXME: this code duplicates server/registry.c */
190 WCHAR
*nameW
; /* value name */
191 int type
; /* value type */
192 size_t len
; /* value data length in bytes */
193 void *data
; /* pointer to value data */
196 /* dump a value to a text file */
197 /* FIXME: this code duplicates server/registry.c */
198 static void _dump_value(struct key_value
*value
,FILE *f
)
202 if (value
->nameW
[0]) {
204 count
= 1 + _dump_strW(value
->nameW
,strlenW(value
->nameW
),f
,"\"\"");
205 count
+= fprintf( f
, "\"=" );
207 else count
= fprintf( f
, "@=" );
209 switch(value
->type
) {
213 if (value
->type
!= REG_SZ
) fprintf( f
, "str(%d):", value
->type
);
215 if (value
->data
) _dump_strW(value
->data
,value
->len
/sizeof(WCHAR
),f
,"\"\"");
219 if (value
->len
== sizeof(DWORD
)) {
221 memcpy( &dw
, value
->data
, sizeof(DWORD
) );
222 fprintf( f
, "dword:%08lx", dw
);
225 /* else fall through */
227 if (value
->type
== REG_BINARY
) count
+= fprintf( f
, "hex:" );
228 else count
+= fprintf( f
, "hex(%x):", value
->type
);
229 for (i
= 0; i
< value
->len
; i
++) {
230 count
+= fprintf( f
, "%02x", *((unsigned char *)value
->data
+ i
) );
231 if (i
< value
->len
-1) {
234 fprintf( f
, "\\\n " );
244 /******************************************************************/
245 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
247 reghack - windows 3.11 registry data format demo program.
249 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
250 a combined hash table and tree description, and finally a text table.
252 The header is obvious from the struct header. The taboff1 and taboff2
253 fields are always 0x20, and their usage is unknown.
255 The 8-byte entry table has various entry types.
257 tabent[0] is a root index. The second word has the index of the root of
259 tabent[1..hashsize] is a hash table. The first word in the hash entry is
260 the index of the key/value that has that hash. Data with the same
261 hash value are on a circular list. The other three words in the
262 hash entry are always zero.
263 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
264 entry: dirent and keyent/valent. They are identified by context.
265 tabent[freeidx] is the first free entry. The first word in a free entry
266 is the index of the next free entry. The last has 0 as a link.
267 The other three words in the free list are probably irrelevant.
269 Entries in text table are preceded by a word at offset-2. This word
270 has the value (2*index)+1, where index is the referring keyent/valent
271 entry in the table. I have no suggestion for the 2* and the +1.
272 Following the word, there are N bytes of data, as per the keyent/valent
273 entry length. The offset of the keyent/valent entry is from the start
274 of the text table to the first data byte.
276 This information is not available from Microsoft. The data format is
277 deduced from the reg.dat file by me. Mistakes may
278 have been made. I claim no rights and give no guarantees for this program.
280 Tor Sjøwall, tor@sn.no
283 /* reg.dat header format */
285 char cookie
[8]; /* 'SHCC3.10' */
286 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
287 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
288 unsigned long tabcnt
; /* number of entries in index table */
289 unsigned long textoff
; /* offset of text part */
290 unsigned long textsize
; /* byte size of text part */
291 unsigned short hashsize
; /* hash size */
292 unsigned short freeidx
; /* free index */
295 /* generic format of table entries */
297 unsigned short w0
, w1
, w2
, w3
;
300 /* directory tabent: */
302 unsigned short sibling_idx
; /* table index of sibling dirent */
303 unsigned short child_idx
; /* table index of child dirent */
304 unsigned short key_idx
; /* table index of key keyent */
305 unsigned short value_idx
; /* table index of value valent */
310 unsigned short hash_idx
; /* hash chain index for string */
311 unsigned short refcnt
; /* reference count */
312 unsigned short length
; /* length of string */
313 unsigned short string_off
; /* offset of string in text table */
318 unsigned short hash_idx
; /* hash chain index for string */
319 unsigned short refcnt
; /* reference count */
320 unsigned short length
; /* length of string */
321 unsigned short string_off
; /* offset of string in text table */
324 /* recursive helper function to display a directory tree [Internal] */
325 static void _w31_dumptree(unsigned short idx
, char *txt
,
326 struct _w31_tabent
*tab
, struct _w31_header
*head
,
327 HKEY hkey
, ULONG lastmodified
, int level
)
329 static const WCHAR classesW
[] = {'.','c','l','a','s','s','e','s',0};
330 struct _w31_dirent
*dir
;
331 struct _w31_keyent
*key
;
332 struct _w31_valent
*val
;
334 OBJECT_ATTRIBUTES attr
;
335 UNICODE_STRING nameW
, valueW
;
336 static WCHAR tail
[400];
338 attr
.Length
= sizeof(attr
);
339 attr
.RootDirectory
= hkey
;
340 attr
.ObjectName
= &nameW
;
342 attr
.SecurityDescriptor
= NULL
;
343 attr
.SecurityQualityOfService
= NULL
;
344 RtlInitUnicodeString( &valueW
, NULL
);
347 dir
=(struct _w31_dirent
*)&tab
[idx
];
351 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
353 RtlMultiByteToUnicodeN( tail
, sizeof(tail
)-sizeof(WCHAR
), &len
,
354 &txt
[key
->string_off
], key
->length
);
355 tail
[len
/sizeof(WCHAR
)] = 0;
357 /* all toplevel entries AND the entries in the
358 * toplevel subdirectory belong to \SOFTWARE\Classes
360 if (!level
&& !strcmpW(tail
,classesW
))
362 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
363 idx
=dir
->sibling_idx
;
367 if (subkey
) NtClose( subkey
);
368 RtlInitUnicodeString( &nameW
, tail
);
369 if (NtCreateKey( &subkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) subkey
= 0;
371 /* only add if leaf node or valued node */
372 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
373 if (dir
->value_idx
) {
375 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
376 RtlMultiByteToUnicodeN( tail
, sizeof(tail
) - sizeof(WCHAR
), &len
,
377 &txt
[val
->string_off
], val
->length
);
378 tail
[len
/sizeof(WCHAR
)] = 0;
379 NtSetValueKey( subkey
, &valueW
, 0, REG_SZ
, tail
, len
+ sizeof(WCHAR
) );
382 } else TRACE("strange: no directory key name, idx=%04x\n", idx
);
383 _w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
384 idx
=dir
->sibling_idx
;
386 if (subkey
) NtClose( subkey
);
390 /******************************************************************************
391 * _w31_loadreg [Internal]
393 static void _w31_loadreg( const WCHAR
*path
)
397 OBJECT_ATTRIBUTES attr
;
398 UNICODE_STRING nameW
;
399 struct _w31_header head
;
400 struct _w31_tabent
* tab
= NULL
;
405 IO_STATUS_BLOCK iosb
;
406 FILE_POSITION_INFORMATION fpi
;
407 FILE_BASIC_INFORMATION fbi
;
411 hf
= CreateFileW( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
412 if (hf
==INVALID_HANDLE_VALUE
) return;
414 /* read & dump header */
415 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
416 &head
, sizeof(head
), NULL
, NULL
) != STATUS_SUCCESS
||
417 iosb
.Information
!= sizeof(head
))
419 ERR("reg.dat is too short.\n");
422 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
)) != 0)
424 ERR("reg.dat has bad signature.\n");
428 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
429 /* read and dump index table */
431 if (NtReadFile(hf
, 0, NULL
, NULL
, &iosb
,
432 tab
, len
, NULL
, NULL
) != STATUS_SUCCESS
||
433 iosb
.Information
!= len
)
435 ERR("couldn't read index table (%d bytes).\n",len
);
440 txt
= _xmalloc(head
.textsize
);
441 fpi
.CurrentByteOffset
.u
.LowPart
= head
.textoff
;
442 fpi
.CurrentByteOffset
.u
.HighPart
= 0;
443 if (NtSetInformationFile(hf
, &iosb
, &fpi
, sizeof(fpi
),
444 FilePositionInformation
) != STATUS_SUCCESS
)
446 ERR("couldn't seek to textblock.\n");
449 status
= NtReadFile(hf
, 0, NULL
, NULL
, &iosb
, txt
, head
.textsize
, NULL
, NULL
);
450 if (!(status
== STATUS_SUCCESS
|| status
== STATUS_END_OF_FILE
) ||
451 iosb
.Information
!= head
.textsize
)
453 ERR("textblock too short (%d instead of %ld).\n", len
, head
.textsize
);
456 if (NtQueryInformationFile(hf
, &iosb
, &fbi
, sizeof(fbi
),
457 FileBasicInformation
) != STATUS_SUCCESS
)
459 ERR("Couldn't get basic information.\n");
462 RtlTimeToSecondsSince1970(&fbi
.LastWriteTime
, &lastmodified
);
464 attr
.Length
= sizeof(attr
);
465 attr
.RootDirectory
= 0;
466 attr
.ObjectName
= &nameW
;
468 attr
.SecurityDescriptor
= NULL
;
469 attr
.SecurityQualityOfService
= NULL
;
470 RtlInitUnicodeString( &nameW
, ClassesRootW
);
472 if (!NtCreateKey( &root
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
474 _w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,root
,lastmodified
,0);
484 /***********************************************************************************/
485 /* windows 95 registry loader */
486 /***********************************************************************************/
488 /* SECTION 1: main header
492 #define W95_REG_CREG_ID 0x47455243
495 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
496 DWORD version
; /* ???? 0x00010000 */
497 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
498 DWORD uk2
; /* 0x0c */
499 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
505 /* SECTION 2: Directory information (tree structure)
507 * once on offset 0x20
509 * structure: [rgkn][dke]* (repeat till last_dke is reached)
511 #define W95_REG_RGKN_ID 0x4e4b4752
514 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
515 DWORD size
; /* Size of the RGKN-block */
516 DWORD root_off
; /* Rel. Offset of the root-record */
517 DWORD last_dke
; /* Offset to last DKE ? */
521 /* Disk Key Entry Structure
523 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
524 * hive itself. It looks the same like other keys. Even the ID-number can
527 * The "hash"-value is a value representing the key's name. Windows will not
528 * search for the name, but for a matching hash-value. if it finds one, it
529 * will compare the actual string info, otherwise continue with the next key.
530 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
531 * of the string which are smaller than 0x80 (128) to this D-Word.
533 * If you want to modify key names, also modify the hash-values, since they
534 * cannot be found again (although they would be displayed in REGEDIT)
535 * End of list-pointers are filled with 0xFFFFFFFF
537 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
538 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
539 * structure) and reading another RGDB_section.
541 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
542 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
543 * The remaining space between last_dke and the offset calculated from
544 * rgkn->size seems to be free for use for more dke:s.
545 * So it seems if more dke:s are added, they are added to that space and
546 * last_dke is grown, and in case that "free" space is out, the space
547 * gets grown and rgkn->size gets adjusted.
549 * there is a one to one relationship between dke and dkh
551 /* key struct, once per key */
553 DWORD x1
; /* Free entry indicator(?) */
554 DWORD hash
; /* sum of bytes of keyname */
555 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
556 DWORD prevlvl
; /* offset of previous key */
557 DWORD nextsub
; /* offset of child key */
558 DWORD next
; /* offset of sibling key */
559 WORD nrLS
; /* id inside the rgdb block */
560 WORD nrMS
; /* number of the rgdb block */
563 /* SECTION 3: key information, values and data
566 * section: [blocks]* (repeat creg->rgdb_num times)
567 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
568 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
570 * An interesting relationship exists in RGDB_section. The DWORD value
571 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
572 * I have no idea at the moment what this means. (Kevin Cozens)
575 /* block header, once per block */
576 #define W95_REG_RGDB_ID 0x42444752
579 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
580 DWORD size
; /* 0x04 */
581 DWORD uk1
; /* 0x08 */
582 DWORD uk2
; /* 0x0c */
583 DWORD uk3
; /* 0x10 */
584 DWORD uk4
; /* 0x14 */
585 DWORD uk5
; /* 0x18 */
586 DWORD uk6
; /* 0x1c */
590 /* Disk Key Header structure (RGDB part), once per key */
592 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
593 WORD nrLS
; /* 0x04 id inside the rgdb block */
594 WORD nrMS
; /* 0x06 number of the rgdb block */
595 DWORD bytesused
; /* 0x08 */
596 WORD keynamelen
; /* 0x0c len of name */
597 WORD values
; /* 0x0e number of values */
598 DWORD xx1
; /* 0x10 */
599 char name
[1]; /* 0x14 */
600 /* dkv */ /* 0x14 + keynamelen */
603 /* Disk Key Value structure, once per value */
605 DWORD type
; /* 0x00 */
607 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
608 WORD valdatalen
; /* 0x0A length of data */
609 char name
[1]; /* 0x0c */
610 /* raw data */ /* 0x0c + valnamelen */
613 /******************************************************************************
614 * _w95_lookup_dkh [Internal]
616 * seeks the dkh belonging to a dke
618 static _w95dkh
*_w95_lookup_dkh(_w95creg
*creg
,int nrLS
,int nrMS
)
624 /* get the beginning of the rgdb datastore */
625 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
627 /* check: requested block < last_block) */
628 if (creg
->rgdb_num
<= nrMS
) {
629 ERR("registry file corrupt! requested block no. beyond end.\n");
633 /* find the right block */
634 for(i
=0; i
<nrMS
;i
++) {
635 if(rgdb
->id
!= W95_REG_RGDB_ID
) { /* check the magic */
636 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
639 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
642 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
645 if(nrLS
==dkh
->nrLS
) return dkh
;
646 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
647 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
653 /******************************************************************************
654 * _w95_dump_dkv [Internal]
656 static int _w95_dump_dkv(_w95dkh
*dkh
,int nrLS
,int nrMS
,FILE *f
)
661 /* first value block */
662 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
664 /* loop through the values */
665 for (i
=0; i
< dkh
->values
; i
++) {
666 struct key_value value
;
669 value
.nameW
= _strdupnAtoW(dkv
->name
,dkv
->valnamelen
);
670 value
.type
= dkv
->type
;
671 value
.len
= dkv
->valdatalen
;
673 value
.data
= &(dkv
->name
[dkv
->valnamelen
]);
675 if ( (value
.type
==REG_SZ
) || (value
.type
==REG_EXPAND_SZ
) || (value
.type
==REG_MULTI_SZ
) ) {
676 pdata
= _strdupnAtoW(value
.data
,value
.len
);
679 if (pdata
!= NULL
) value
.data
= pdata
;
681 _dump_value(&value
,f
);
683 if (pdata
!= NULL
) free(pdata
);
686 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
691 /******************************************************************************
692 * _w95_dump_dke [Internal]
694 static int _w95_dump_dke(LPCSTR key_name
,_w95creg
*creg
,_w95rgkn
*rgkn
,_w95dke
*dke
,FILE *f
,int level
)
697 LPSTR new_key_name
= NULL
;
699 /* special root key */
700 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
702 /* parse the one subkey */
703 if (dke
->nextsub
!= 0xffffffff) return _w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
);
704 /* has no sibling keys */
708 /* search subblock */
709 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
))) {
710 ERR("dke pointing to missing dkh !\n");
715 /* create new subkey name */
716 size_t len
= strlen(key_name
);
717 new_key_name
= _xmalloc(len
+dkh
->keynamelen
+2);
718 memcpy( new_key_name
, key_name
, len
);
719 if (len
) new_key_name
[len
++] = '\\';
720 memcpy( new_key_name
+ len
, dkh
->name
, dkh
->keynamelen
);
721 new_key_name
[len
+ dkh
->keynamelen
] = 0;
723 /* walk sibling keys */
724 if (dke
->next
!= 0xffffffff ) {
725 if (!_w95_dump_dke(key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
),f
,level
)) {
731 /* write the key path (something like [Software\\Microsoft\\..]) only if:
732 1) key has some values
733 2) key has no values and no subkeys
735 if (dkh
->values
> 0) {
736 /* there are some values */
738 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
740 if (!_w95_dump_dkv(dkh
, dke
->nrLS
, dke
->nrMS
,f
)) {
745 if ((dke
->nextsub
== 0xffffffff) && (dkh
->values
== 0)) {
746 /* no subkeys and no values */
748 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
751 } else new_key_name
= _xstrdup(key_name
);
754 if (dke
->nextsub
!= 0xffffffff) {
755 if (!_w95_dump_dke(new_key_name
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
),f
,level
-1)) {
764 /* end windows 95 loader */
766 /***********************************************************************************/
767 /* windows NT registry loader */
768 /***********************************************************************************/
770 /* NT REGISTRY LOADER */
772 #ifdef HAVE_SYS_MMAN_H
773 # include <sys/mman.h>
777 #define MAP_FAILED ((LPVOID)-1)
780 #define NT_REG_BLOCK_SIZE 0x1000
782 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
783 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
784 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
785 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
787 /* subblocks of nk */
788 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
789 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
790 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
792 #define NT_REG_KEY_BLOCK_TYPE 0x20
793 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
796 DWORD id
; /* 0x66676572 'regf'*/
797 DWORD uk1
; /* 0x04 */
798 DWORD uk2
; /* 0x08 */
799 FILETIME DateModified
; /* 0x0c */
800 DWORD uk3
; /* 0x14 */
801 DWORD uk4
; /* 0x18 */
802 DWORD uk5
; /* 0x1c */
803 DWORD uk6
; /* 0x20 */
804 DWORD RootKeyBlock
; /* 0x24 */
805 DWORD BlockSize
; /* 0x28 */
807 DWORD Checksum
; /* at offset 0x1FC */
816 DWORD id
; /* 0x6E696268 'hbin' */
820 DWORD uk2
; /* 0x10 */
821 DWORD uk3
; /* 0x14 */
822 DWORD uk4
; /* 0x18 */
823 DWORD size
; /* 0x1C */
824 nt_hbin_sub hbin_sub
; /* 0x20 */
828 * the value_list consists of offsets to the values (vk)
831 WORD SubBlockId
; /* 0x00 0x6B6E */
832 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
833 FILETIME writetime
; /* 0x04 */
834 DWORD uk1
; /* 0x0C */
835 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
836 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
837 DWORD uk8
; /* 0x18 */
838 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
839 DWORD uk2
; /* 0x20 */
840 DWORD nr_values
; /* 0x24 number of values */
841 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
842 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
843 DWORD off_class
; /* 0x30 Offset of the Class-Name */
844 DWORD uk3
; /* 0x34 */
845 DWORD uk4
; /* 0x38 */
846 DWORD uk5
; /* 0x3c */
847 DWORD uk6
; /* 0x40 */
848 DWORD uk7
; /* 0x44 */
849 WORD name_len
; /* 0x48 name-length */
850 WORD class_len
; /* 0x4a class-name length */
851 char name
[1]; /* 0x4c key-name */
855 DWORD off_nk
; /* 0x00 */
856 DWORD name
; /* 0x04 */
860 WORD id
; /* 0x00 0x666c */
861 WORD nr_keys
; /* 0x06 */
862 hash_rec hash_rec
[1];
866 list of subkeys without hash
873 WORD id
; /* 0x00 0x696c */
879 this is a intermediate node
890 WORD id
; /* 0x00 0x6972 */
891 WORD nr_li
; /* 0x02 number off offsets */
892 DWORD off_li
[1]; /* 0x04 points to li */
896 WORD id
; /* 0x00 'vk' */
910 * 0 value is a default value
911 * 1 the value has a name
914 * len of the whole data block
916 * bytes including the terminating \0 = 2*(number_of_chars+1)
917 * - reg_dword, reg_binary:
918 * if highest bit of data_len is set data_off contains the value
920 static int _nt_dump_vk(LPSTR key_name
, char *base
, nt_vk
*vk
,FILE *f
)
922 BYTE
*pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
923 struct key_value value
;
925 if (vk
->id
!= NT_REG_VALUE_BLOCK_ID
) {
926 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
930 value
.nameW
= _strdupnAtoW(vk
->name
,vk
->nam_len
);
931 value
.type
= vk
->type
;
932 value
.len
= (vk
->data_len
& 0x7fffffff);
933 value
.data
= (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
;
935 _dump_value(&value
,f
);
941 /* it's called from _nt_dump_lf() */
942 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
);
947 * this structure contains the hash of a keyname and points to all
950 * exception: if the id is 'il' there are no hash values and every
953 static int _nt_dump_lf(LPCSTR key_name
, char *base
, int subkeys
, nt_lf
*lf
, FILE *f
, int level
)
957 if (lf
->id
== NT_REG_HASH_BLOCK_ID
) {
958 if (subkeys
!= lf
->nr_keys
) goto error1
;
960 for (i
=0; i
<lf
->nr_keys
; i
++)
961 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), f
, level
)) goto error
;
962 } else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
) {
963 nt_li
* li
= (nt_li
*)lf
;
964 if (subkeys
!= li
->nr_keys
) goto error1
;
966 for (i
=0; i
<li
->nr_keys
; i
++)
967 if (!_nt_dump_nk(key_name
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), f
, level
)) goto error
;
968 } else if (lf
->id
== NT_REG_RI_BLOCK_ID
) { /* ri */
969 nt_ri
* ri
= (nt_ri
*)lf
;
972 /* count all subkeys */
973 for (i
=0; i
<ri
->nr_li
; i
++) {
974 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
975 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
976 li_subkeys
+= li
->nr_keys
;
980 if (subkeys
!= li_subkeys
) goto error1
;
982 /* loop through the keys */
983 for (i
=0; i
<ri
->nr_li
; i
++) {
984 nt_li
*li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
985 if (!_nt_dump_lf(key_name
, base
, li
->nr_keys
, (nt_lf
*)li
, f
, level
)) goto error
;
992 if (lf
->id
== 0x686c)
993 FIXME("unknown Win XP node id 0x686c: do we need to add support for it ?\n");
995 ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
999 ERR("registry file corrupt! (inconsistent number of subkeys)\n");
1003 ERR("error reading lf block\n");
1007 /* _nt_dump_nk [Internal] */
1008 static int _nt_dump_nk(LPCSTR key_name
,char *base
,nt_nk
*nk
,FILE *f
,int level
)
1012 LPSTR new_key_name
= NULL
;
1014 TRACE("%s\n", key_name
);
1016 if (nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) {
1017 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
1021 if ((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) && (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) {
1022 ERR("registry file corrupt!\n");
1026 /* create the new key */
1028 /* create new subkey name */
1029 size_t len
= strlen(key_name
);
1030 new_key_name
= _xmalloc( len
+nk
->name_len
+2 );
1031 memcpy( new_key_name
, key_name
, len
);
1032 if (len
) new_key_name
[len
++] = '\\';
1033 memcpy( new_key_name
+ len
, nk
->name
, nk
->name_len
);
1034 new_key_name
[len
+ nk
->name_len
] = 0;
1036 /* write the key path (something like [Software\\Microsoft\\..]) only if:
1037 1) key has some values
1038 2) key has no values and no subkeys
1040 if (nk
->nr_values
> 0) {
1041 /* there are some values */
1043 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1046 if ((nk
->nr_subkeys
== 0) && (nk
->nr_values
== 0)) {
1047 /* no subkeys and no values */
1049 _dump_strAtoW(new_key_name
,strlen(new_key_name
),f
,"[]");
1053 /* loop trough the value list */
1054 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
1055 for (n
=0; n
<nk
->nr_values
; n
++) {
1056 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
1057 if (!_nt_dump_vk(new_key_name
, base
, vk
, f
)) {
1062 } else new_key_name
= _xstrdup(key_name
);
1064 /* loop through the subkeys */
1065 if (nk
->nr_subkeys
) {
1066 nt_lf
*lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
1067 if (!_nt_dump_lf(new_key_name
, base
, nk
->nr_subkeys
, lf
, f
, level
-1)) {
1079 /******************************************************************************
1080 * _allocate_default_keys [Internal]
1081 * Registry initialisation, allocates some default keys.
1083 static void _allocate_default_keys(void)
1085 static const WCHAR StatDataW
[] = {'D','y','n','D','a','t','a','\\',
1086 'P','e','r','f','S','t','a','t','s','\\',
1087 'S','t','a','t','D','a','t','a',0};
1089 OBJECT_ATTRIBUTES attr
;
1090 UNICODE_STRING nameW
;
1094 attr
.Length
= sizeof(attr
);
1095 attr
.RootDirectory
= 0;
1096 attr
.ObjectName
= &nameW
;
1097 attr
.Attributes
= 0;
1098 attr
.SecurityDescriptor
= NULL
;
1099 attr
.SecurityQualityOfService
= NULL
;
1101 RtlInitUnicodeString( &nameW
, StatDataW
);
1102 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1105 static void get_windows_dir(WCHAR
* buffer
, unsigned len
)
1107 OBJECT_ATTRIBUTES attr
;
1108 UNICODE_STRING nameW
, keyW
;
1111 attr
.Length
= sizeof(attr
);
1112 attr
.RootDirectory
= 0;
1113 attr
.ObjectName
= &nameW
;
1114 attr
.Attributes
= 0;
1115 attr
.SecurityDescriptor
= NULL
;
1116 attr
.SecurityQualityOfService
= NULL
;
1118 if (RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\Software\\Wine\\Wine\\Config\\wine" ))
1120 if (!NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
))
1122 char tmp
[MAX_PATHNAME_LEN
*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1125 RtlCreateUnicodeStringFromAsciiz( &keyW
, "Windows");
1126 if (!NtQueryValueKey( hkey
, &keyW
, KeyValuePartialInformation
,
1127 tmp
, sizeof(tmp
), &count
))
1129 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1130 memcpy(buffer
, str
, min(((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->DataLength
, len
));
1132 RtlFreeUnicodeString( &keyW
);
1134 RtlFreeUnicodeString( &nameW
);
1139 #define REG_DONTLOAD -1
1144 /* return the type of native registry [Internal] */
1145 static int _get_reg_type(const WCHAR
* windir
)
1147 WCHAR tmp
[MAX_PATHNAME_LEN
];
1148 int ret
= REG_WIN31
;
1149 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};
1150 static const WCHAR win9x_reg_pathW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1152 /* test %windir%/system32/config/system --> winnt */
1153 strcpyW(tmp
, windir
);
1154 strcatW(tmp
, nt_reg_pathW
);
1155 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1159 /* test %windir%/system.dat --> win95 */
1160 strcpyW(tmp
, windir
);
1161 strcatW(tmp
, win9x_reg_pathW
);
1162 if(GetFileAttributesW(tmp
) != INVALID_FILE_ATTRIBUTES
)
1169 /* load the registry file in wine format [Internal] */
1170 static void load_wine_registry(HKEY hkey
,LPCSTR fn
)
1175 UNICODE_STRING name
;
1176 OBJECT_ATTRIBUTES attr
;
1179 len
= MultiByteToWideChar( CP_UNIXCP
, 0, fn
, -1, NULL
, 0 );
1180 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return;
1181 MultiByteToWideChar( CP_UNIXCP
, 0, fn
, -1, buffer
, len
);
1182 RtlInitUnicodeString( &name
, buffer
);
1184 attr
.Length
= sizeof(attr
);
1185 attr
.RootDirectory
= 0;
1186 attr
.Attributes
= 0;
1187 attr
.ObjectName
= &name
;
1188 attr
.SecurityDescriptor
= NULL
;
1189 attr
.SecurityQualityOfService
= NULL
;
1191 if (!NtOpenFile( &file
, GENERIC_READ
, &attr
, &io
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1192 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
))
1194 SERVER_START_REQ( load_registry
)
1198 wine_server_call( req
);
1201 CloseHandle( file
);
1203 HeapFree( GetProcessHeap(), 0, buffer
);
1206 /* generate and return the name of the tmp file and associated stream [Internal] */
1207 static LPSTR
_get_tmp_fn(FILE **f
)
1214 sprintf(ret
,"/tmp/reg%lx%04x.tmp",(long)getpid(),count
++);
1215 if ((tmp_fd
= open(ret
,O_CREAT
| O_EXCL
| O_WRONLY
,0666)) != -1) break;
1216 if (errno
!= EEXIST
) {
1217 ERR("Unexpected error while open() call: %s\n",strerror(errno
));
1224 if ((*f
= fdopen(tmp_fd
,"w")) == NULL
) {
1225 ERR("Unexpected error while fdopen() call: %s\n",strerror(errno
));
1234 /* convert win95 native registry file to wine format [Internal] */
1235 static LPSTR
_convert_win95_registry_to_wine_format(LPCWSTR fn
, int level
)
1237 HANDLE hFile
, hMapping
;
1241 OBJECT_ATTRIBUTES attr
;
1242 LARGE_INTEGER lg_int
;
1248 _w95dke
*dke
, *root_dke
;
1250 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1251 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1253 attr
.Length
= sizeof(attr
);
1254 attr
.RootDirectory
= 0;
1255 attr
.ObjectName
= NULL
;
1256 attr
.Attributes
= 0;
1257 attr
.SecurityDescriptor
= NULL
;
1258 attr
.SecurityQualityOfService
= NULL
;
1260 lg_int
.QuadPart
= 0;
1261 nts
= NtCreateSection( &hMapping
,
1262 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1263 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1264 if (nts
!= STATUS_SUCCESS
) goto error1
;
1266 base
= NULL
; len
= 0;
1267 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1268 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1270 NtClose( hMapping
);
1271 if (nts
!= STATUS_SUCCESS
) goto error1
;
1273 /* control signature */
1274 if (*(LPDWORD
)base
!= W95_REG_CREG_ID
) {
1275 ERR("unable to load native win95 registry file %s: unknown signature.\n",
1281 /* load the header (rgkn) */
1282 rgkn
= (_w95rgkn
*)(creg
+ 1);
1283 if (rgkn
->id
!= W95_REG_RGKN_ID
) {
1284 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1287 if (rgkn
->root_off
!= 0x20) {
1288 ERR("rgkn->root_off not 0x20, please report !\n");
1291 if (rgkn
->last_dke
> rgkn
->size
)
1293 ERR("registry file corrupt! last_dke > size!\n");
1296 /* verify last dke */
1297 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1298 if (dke
->x1
!= 0x80000000)
1300 ERR("last dke invalid !\n");
1303 if (rgkn
->size
> creg
->rgdb_off
)
1305 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1308 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1309 if ( (root_dke
->prevlvl
!= 0xffffffff) || (root_dke
->next
!= 0xffffffff) )
1311 ERR("registry file corrupt! invalid root dke !\n");
1315 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1316 fprintf(f
,"WINE REGISTRY Version 2");
1317 _w95_dump_dke("",creg
,rgkn
,root_dke
,f
,level
);
1322 ERR("Unable to load native win95 registry file %s.\n", debugstr_w(fn
));
1323 ERR("Please report this.\n");
1324 ERR("Make a backup of the file, run a good reg cleaner program and try again!\n");
1327 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1333 /* convert winnt native registry file to wine format [Internal] */
1334 static LPSTR
_convert_winnt_registry_to_wine_format(LPCWSTR fn
, int level
)
1341 OBJECT_ATTRIBUTES attr
;
1342 LARGE_INTEGER lg_int
;
1348 nt_hbin_sub
*hbin_sub
;
1351 TRACE("%s\n", debugstr_w(fn
));
1353 hFile
= CreateFileW( fn
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0 );
1354 if ( hFile
== INVALID_HANDLE_VALUE
) return NULL
;
1355 attr
.Length
= sizeof(attr
);
1356 attr
.RootDirectory
= 0;
1357 attr
.ObjectName
= NULL
;
1358 attr
.Attributes
= 0;
1359 attr
.SecurityDescriptor
= NULL
;
1360 attr
.SecurityQualityOfService
= NULL
;
1362 lg_int
.QuadPart
= 0;
1363 nts
= NtCreateSection( &hMapping
,
1364 STANDARD_RIGHTS_REQUIRED
|SECTION_QUERY
|SECTION_MAP_READ
,
1365 &attr
, &lg_int
, PAGE_READONLY
, SEC_COMMIT
, hFile
);
1366 if (nts
!= STATUS_SUCCESS
) goto error1
;
1368 base
= NULL
; len
= 0;
1369 nts
= NtMapViewOfSection( hMapping
, GetCurrentProcess(),
1370 &base
, 0, 0, &lg_int
, &len
, ViewShare
, 0,
1372 NtClose( hMapping
);
1373 if (nts
!= STATUS_SUCCESS
) goto error1
;
1375 /* control signature */
1376 if (*(LPDWORD
)base
!= NT_REG_HEADER_BLOCK_ID
) {
1377 ERR("unable to load native winnt registry file %s: unknown signature.\n",
1386 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1387 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
) {
1388 ERR( "hbin block invalid\n");
1392 /* hbin_sub block */
1393 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1394 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k')) {
1395 ERR( "hbin_sub block invalid\n");
1400 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1401 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
) {
1402 ERR( "special nk block not found\n");
1406 if ( (ret
= _get_tmp_fn(&f
)) == NULL
) goto error
;
1407 fprintf(f
,"WINE REGISTRY Version 2");
1408 _nt_dump_nk("",(char*)base
+0x1000,nk
,f
,level
);
1412 NtUnmapViewOfSection( GetCurrentProcess(), base
);
1418 /* convert native registry to wine format and load it via server call [Internal] */
1419 static void _convert_and_load_native_registry(LPCWSTR fn
, HKEY hkey
, int reg_type
, int level
)
1425 /* FIXME: following function doesn't really convert yet */
1426 tmp
= _convert_winnt_registry_to_wine_format(fn
,level
);
1429 tmp
= _convert_win95_registry_to_wine_format(fn
,level
);
1432 ERR("Don't know how to convert native 3.1 registry yet.\n");
1435 ERR("Unknown registry format parameter (%d)\n",reg_type
);
1440 load_wine_registry(hkey
,tmp
);
1441 TRACE("File %s successfully converted to %s and loaded to registry.\n",
1442 debugstr_w(fn
), tmp
);
1445 else WARN("Unable to convert %s (doesn't exist?)\n", debugstr_w(fn
));
1449 /* load all native windows registry files [Internal] */
1450 static void _load_windows_registry( HKEY hkey_local_machine
, HKEY hkey_current_user
,
1451 HKEY hkey_users_default
)
1454 WCHAR windir
[MAX_PATHNAME_LEN
];
1455 WCHAR path
[MAX_PATHNAME_LEN
];
1456 OBJECT_ATTRIBUTES attr
;
1457 UNICODE_STRING nameW
;
1458 HKEY hkey
, profile_key
;
1462 static const WCHAR WineW
[] = {'M','a','c','h','i','n','e','\\',
1463 'S','o','f','t','w','a','r','e','\\',
1464 'W','i','n','e','\\','W','i','n','e','\\',
1465 'C','o','n','f','i','g','\\','W','i','n','e',0};
1466 static const WCHAR ProfileW
[] = {'P','r','o','f','i','l','e',0};
1467 static const WCHAR System
[] = {'M','a','c','h','i','n','e','\\','S','y','s','t','e','m',0};
1468 static const WCHAR Software
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e',0};
1469 static const WCHAR Clone
[] = {'M','a','c','h','i','n','e','\\',
1470 'S','y','s','t','e','m','\\',
1471 'C','l','o','n','e',0};
1473 attr
.Length
= sizeof(attr
);
1474 attr
.RootDirectory
= 0;
1475 attr
.ObjectName
= &nameW
;
1476 attr
.Attributes
= 0;
1477 attr
.SecurityDescriptor
= NULL
;
1478 attr
.SecurityQualityOfService
= NULL
;
1480 RtlInitUnicodeString( &nameW
, WineW
);
1481 if (NtCreateKey( &profile_key
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) profile_key
= 0;
1483 get_windows_dir(windir
, sizeof(windir
));
1485 reg_type
= _get_reg_type(windir
);
1488 static const WCHAR ntuser_datW
[] = {'\\','n','t','u','s','e','r','.','d','a','t',0};
1489 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};
1490 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};
1491 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};
1492 static const WCHAR samW
[] = {'\\','s','y','s','t','e','m','3','2','\\','c','o','n','f','i','g','\\','s','a','m',0};
1493 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};
1495 /* user specific ntuser.dat */
1496 RtlInitUnicodeString( &nameW
, ProfileW
);
1497 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1498 tmp
, sizeof(tmp
), &dummy
))
1500 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1501 strcatW(path
, ntuser_datW
);
1502 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WINNT
,1);
1506 MESSAGE("When you are running with a native NT directory specify\n");
1507 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1508 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1512 /* default user.dat */
1513 if (hkey_users_default
) {
1514 strcpyW(path
, windir
);
1515 strcatW(path
, defaultW
);
1516 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WINNT
,1);
1521 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1523 RtlInitUnicodeString( &nameW
, System
);
1524 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1526 strcpyW(path
, windir
);
1527 strcatW(path
, systemW
);
1528 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1531 RtlInitUnicodeString( &nameW
, Software
);
1532 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1534 strcpyW(path
, windir
);
1535 strcatW(path
, softwareW
);
1536 _convert_and_load_native_registry(path
,hkey
,REG_WINNT
,1);
1540 strcpyW(path
, windir
);
1541 strcatW(path
, samW
);
1542 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1544 strcpyW(path
,windir
);
1545 strcatW(path
, securityW
);
1546 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WINNT
,0);
1548 /* this key is generated when the nt-core booted successfully */
1549 RtlInitUnicodeString( &nameW
, Clone
);
1550 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
)) NtClose( hkey
);
1556 static const WCHAR system_1stW
[] = {'c',':','\\','s','y','s','t','e','m','.','1','s','t',0};
1557 static const WCHAR system_datW
[] = {'\\','s','y','s','t','e','m','.','d','a','t',0};
1558 static const WCHAR classes_datW
[] = {'\\','c','l','a','s','s','e','s','.','d','a','t',0};
1559 static const WCHAR user_datW
[] = {'\\','u','s','e','r','.','d','a','t',0};
1561 _convert_and_load_native_registry(system_1stW
,hkey_local_machine
,REG_WIN95
,0);
1563 strcpyW(path
, windir
);
1564 strcatW(path
, system_datW
);
1565 _convert_and_load_native_registry(path
,hkey_local_machine
,REG_WIN95
,0);
1567 RtlInitUnicodeString( &nameW
, ClassesRootW
);
1568 if (!NtCreateKey( &hkey
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1570 strcpyW(path
, windir
);
1571 strcatW(path
, classes_datW
);
1572 _convert_and_load_native_registry(path
,hkey
,REG_WIN95
,0);
1576 RtlInitUnicodeString( &nameW
, ProfileW
);
1577 if (profile_key
&& !NtQueryValueKey( profile_key
, &nameW
, KeyValuePartialInformation
,
1578 tmp
, sizeof(tmp
), &dummy
))
1580 /* user specific user.dat */
1581 strcpyW(path
, (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
);
1582 strcatW(path
, user_datW
);
1583 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1585 /* default user.dat */
1586 if (hkey_users_default
) {
1587 strcpyW(path
, windir
);
1588 strcatW(path
, user_datW
);
1589 _convert_and_load_native_registry(path
,hkey_users_default
,REG_WIN95
,1);
1592 strcpyW(path
, windir
);
1593 strcatW(path
, user_datW
);
1594 _convert_and_load_native_registry(path
,hkey_current_user
,REG_WIN95
,1);
1601 static const WCHAR reg_datW
[] = {'\\','r','e','g','.','d','a','t',0};
1602 /* FIXME: here we should convert to *.reg file supported by server and call REQ_LOAD_REGISTRY, see REG_WIN95 case */
1603 strcpyW(path
, windir
);
1604 strcatW(path
, reg_datW
);
1605 _w31_loadreg( path
);
1610 TRACE("REG_DONTLOAD\n");
1614 ERR("switch: no match (%d)\n",reg_type
);
1618 if (profile_key
) NtClose( profile_key
);
1623 /******************************************************************
1624 * init_cdrom_registry
1626 * Initializes registry to contain scsi info about the cdrom in NT.
1627 * All devices (even not real scsi ones) have this info in NT.
1628 * TODO: for now it only works for non scsi devices
1629 * NOTE: programs usually read these registry entries after sending the
1630 * IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
1632 static void init_cdrom_registry( HANDLE handle
)
1634 OBJECT_ATTRIBUTES attr
;
1635 UNICODE_STRING nameW
;
1647 SCSI_ADDRESS scsi_addr
;
1649 if (NtDeviceIoControlFile( handle
, 0, NULL
, NULL
, &io
, IOCTL_SCSI_GET_ADDRESS
,
1650 NULL
, 0, &scsi_addr
, sizeof(scsi_addr
) ))
1653 attr
.Length
= sizeof(attr
);
1654 attr
.RootDirectory
= 0;
1655 attr
.ObjectName
= &nameW
;
1656 attr
.Attributes
= 0;
1657 attr
.SecurityDescriptor
= NULL
;
1658 attr
.SecurityQualityOfService
= NULL
;
1660 /* Ensure there is Scsi key */
1661 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
1662 NtCreateKey( &scsiKey
, KEY_ALL_ACCESS
, &attr
, 0,
1663 NULL
, REG_OPTION_VOLATILE
, &disp
))
1665 ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
1668 RtlFreeUnicodeString( &nameW
);
1670 snprintf(buffer
,sizeof(buffer
),"Scsi Port %d",scsi_addr
.PortNumber
);
1671 attr
.RootDirectory
= scsiKey
;
1672 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1673 NtCreateKey( &portKey
, KEY_ALL_ACCESS
, &attr
, 0,
1674 NULL
, REG_OPTION_VOLATILE
, &disp
))
1676 ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
1679 RtlFreeUnicodeString( &nameW
);
1681 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Driver" );
1683 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1684 NtSetValueKey( portKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1685 RtlFreeUnicodeString( &nameW
);
1687 RtlCreateUnicodeStringFromAsciiz( &nameW
, "FirstBusTimeScanInMs" );
1688 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
1689 RtlFreeUnicodeString( &nameW
);
1694 if (!wine_server_handle_to_fd( handle
, 0, &fd
, NULL
, NULL
))
1696 if (ioctl(fd
,HDIO_GET_DMA
, &dma
) != -1) value
= dma
;
1697 wine_server_release_fd( handle
, fd
);
1701 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DMAEnabled" );
1702 NtSetValueKey( portKey
,&nameW
, 0, REG_DWORD
, (BYTE
*)&value
, sizeof(DWORD
));
1703 RtlFreeUnicodeString( &nameW
);
1705 snprintf(buffer
,40,"Scsi Bus %d", scsi_addr
.PathId
);
1706 attr
.RootDirectory
= portKey
;
1707 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1708 NtCreateKey( &busKey
, KEY_ALL_ACCESS
, &attr
, 0,
1709 NULL
, REG_OPTION_VOLATILE
, &disp
))
1711 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
1714 RtlFreeUnicodeString( &nameW
);
1716 attr
.RootDirectory
= busKey
;
1717 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, "Initiator Id 255" ) ||
1718 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
1719 NULL
, REG_OPTION_VOLATILE
, &disp
))
1721 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
1724 RtlFreeUnicodeString( &nameW
);
1725 NtClose( targetKey
);
1727 snprintf(buffer
,40,"Target Id %d", scsi_addr
.TargetId
);
1728 attr
.RootDirectory
= busKey
;
1729 if (!RtlCreateUnicodeStringFromAsciiz( &nameW
, buffer
) ||
1730 NtCreateKey( &targetKey
, KEY_ALL_ACCESS
, &attr
, 0,
1731 NULL
, REG_OPTION_VOLATILE
, &disp
))
1733 ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
1736 RtlFreeUnicodeString( &nameW
);
1738 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Type" );
1739 data
= "CdRomPeripheral";
1740 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1741 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1742 RtlFreeUnicodeString( &nameW
);
1743 /* FIXME - maybe read the real identifier?? */
1744 RtlCreateUnicodeStringFromAsciiz( &nameW
, "Identifier" );
1745 data
= "Wine CDROM";
1746 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1747 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1748 RtlFreeUnicodeString( &nameW
);
1749 /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
1750 RtlCreateUnicodeStringFromAsciiz( &nameW
, "DeviceName" );
1752 RtlMultiByteToUnicodeN( dataW
, 50, &lenW
, data
, strlen(data
));
1753 NtSetValueKey( targetKey
, &nameW
, 0, REG_SZ
, (BYTE
*)dataW
, lenW
);
1754 RtlFreeUnicodeString( &nameW
);
1756 NtClose( targetKey
);
1763 /* create the hardware registry branch */
1764 static void create_hardware_branch(void)
1768 char drive
[] = "\\\\.\\A:";
1770 /* create entries for cdroms */
1771 for (i
= 0; i
< 26; i
++)
1774 handle
= CreateFileA( drive
, 0, 0, NULL
, OPEN_EXISTING
, 0, 0 );
1775 if (handle
== INVALID_HANDLE_VALUE
) continue;
1776 init_cdrom_registry( handle
);
1777 CloseHandle( handle
);
1782 /* convert the drive type entries from the old format to the new one */
1783 static void convert_drive_types(void)
1785 static const WCHAR TypeW
[] = {'T','y','p','e',0};
1786 static const WCHAR drive_types_keyW
[] = {'M','a','c','h','i','n','e','\\',
1787 'S','o','f','t','w','a','r','e','\\',
1788 'W','i','n','e','\\',
1789 'D','r','i','v','e','s',0 };
1790 WCHAR driveW
[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
1791 'W','i','n','e','\\','W','i','n','e','\\',
1792 'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
1793 char tmp
[32*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1794 OBJECT_ATTRIBUTES attr
;
1795 UNICODE_STRING nameW
;
1798 HKEY hkey_old
, hkey_new
;
1801 attr
.Length
= sizeof(attr
);
1802 attr
.RootDirectory
= 0;
1803 attr
.ObjectName
= &nameW
;
1804 attr
.Attributes
= 0;
1805 attr
.SecurityDescriptor
= NULL
;
1806 attr
.SecurityQualityOfService
= NULL
;
1807 RtlInitUnicodeString( &nameW
, drive_types_keyW
);
1809 if (NtCreateKey( &hkey_new
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
)) return;
1810 if (disp
!= REG_CREATED_NEW_KEY
)
1812 NtClose( hkey_new
);
1816 for (i
= 0; i
< 26; i
++)
1818 RtlInitUnicodeString( &nameW
, driveW
);
1819 nameW
.Buffer
[(nameW
.Length
/ sizeof(WCHAR
)) - 1] = 'A' + i
;
1820 if (NtOpenKey( &hkey_old
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
) continue;
1821 RtlInitUnicodeString( &nameW
, TypeW
);
1822 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &dummy
))
1824 WCHAR valueW
[] = {'A',':',0};
1825 WCHAR
*type
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
1827 valueW
[0] = 'A' + i
;
1828 RtlInitUnicodeString( &nameW
, valueW
);
1829 NtSetValueKey( hkey_new
, &nameW
, 0, REG_SZ
, type
, (strlenW(type
) + 1) * sizeof(WCHAR
) );
1830 MESSAGE( "Converted drive type to new entry HKLM\\Software\\Wine\\Drives \"%c:\" = %s\n",
1831 'A' + i
, debugstr_w(type
) );
1833 NtClose( hkey_old
);
1835 NtClose( hkey_new
);
1839 /* convert the environment variable entries from the old format to the new one */
1840 static void convert_environment( HKEY hkey_current_user
)
1842 static const WCHAR wineW
[] = {'M','a','c','h','i','n','e','\\',
1843 'S','o','f','t','w','a','r','e','\\',
1844 'W','i','n','e','\\','W','i','n','e','\\',
1845 'C','o','n','f','i','g','\\','W','i','n','e',0};
1846 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
1847 static const WCHAR systemW
[] = {'s','y','s','t','e','m',0};
1848 static const WCHAR windirW
[] = {'w','i','n','d','i','r',0};
1849 static const WCHAR winsysdirW
[] = {'w','i','n','s','y','s','d','i','r',0};
1850 static const WCHAR envW
[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
1851 static const WCHAR tempW
[] = {'T','E','M','P',0};
1852 static const WCHAR tmpW
[] = {'T','M','P',0};
1853 static const WCHAR pathW
[] = {'P','A','T','H',0};
1854 static const WCHAR profileW
[] = {'p','r','o','f','i','l','e',0};
1855 static const WCHAR userprofileW
[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
1857 char buffer
[1024*sizeof(WCHAR
) + sizeof(KEY_VALUE_PARTIAL_INFORMATION
)];
1858 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
1859 OBJECT_ATTRIBUTES attr
;
1860 UNICODE_STRING nameW
;
1863 HKEY hkey_old
, hkey_env
;
1865 attr
.Length
= sizeof(attr
);
1866 attr
.RootDirectory
= 0;
1867 attr
.ObjectName
= &nameW
;
1868 attr
.Attributes
= 0;
1869 attr
.SecurityDescriptor
= NULL
;
1870 attr
.SecurityQualityOfService
= NULL
;
1871 RtlInitUnicodeString( &nameW
, wineW
);
1873 if (NtOpenKey( &hkey_old
, KEY_ALL_ACCESS
, &attr
) != STATUS_SUCCESS
) return;
1875 attr
.RootDirectory
= hkey_current_user
;
1876 RtlInitUnicodeString( &nameW
, envW
);
1877 if (NtCreateKey( &hkey_env
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &disp
))
1879 NtClose( hkey_old
);
1882 if (disp
!= REG_CREATED_NEW_KEY
) goto done
;
1885 RtlInitUnicodeString( &nameW
, tempW
);
1886 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &dummy
))
1888 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1889 RtlInitUnicodeString( &nameW
, tmpW
);
1890 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1891 MESSAGE( "Converted temp dir to new entry HKCU\\Environment \"TEMP\" = %s\n",
1892 debugstr_w( (WCHAR
*)info
->Data
) );
1896 RtlInitUnicodeString( &nameW
, pathW
);
1897 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &dummy
))
1899 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1900 MESSAGE( "Converted path dir to new entry HKCU\\Environment \"PATH\" = %s\n",
1901 debugstr_w( (WCHAR
*)info
->Data
) );
1904 /* convert USERPROFILE */
1905 RtlInitUnicodeString( &nameW
, profileW
);
1906 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &dummy
))
1908 RtlInitUnicodeString( &nameW
, userprofileW
);
1909 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1910 MESSAGE( "Converted profile dir to new entry HKCU\\Environment \"USERPROFILE\" = %s\n",
1911 debugstr_w( (WCHAR
*)info
->Data
) );
1914 /* convert windir */
1915 RtlInitUnicodeString( &nameW
, windowsW
);
1916 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &dummy
))
1918 RtlInitUnicodeString( &nameW
, windirW
);
1919 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1920 MESSAGE( "Converted windows dir to new entry HKCU\\Environment \"windir\" = %s\n",
1921 debugstr_w( (WCHAR
*)info
->Data
) );
1924 /* convert winsysdir */
1925 RtlInitUnicodeString( &nameW
, systemW
);
1926 if (!NtQueryValueKey( hkey_old
, &nameW
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &dummy
))
1928 RtlInitUnicodeString( &nameW
, winsysdirW
);
1929 NtSetValueKey( hkey_env
, &nameW
, 0, info
->Type
, info
->Data
, info
->DataLength
);
1930 MESSAGE( "Converted system dir to new entry HKCU\\Environment \"winsysdir\" = %s\n",
1931 debugstr_w( (WCHAR
*)info
->Data
) );
1935 NtClose( hkey_old
);
1936 NtClose( hkey_env
);
1940 /* load all registry (native and global and home) */
1941 void SHELL_LoadRegistry( void )
1943 HKEY hkey_local_machine
, hkey_users
, hkey_users_default
, hkey_current_user
, hkey_config
;
1944 OBJECT_ATTRIBUTES attr
;
1945 UNICODE_STRING nameW
;
1952 static const WCHAR MachineW
[] = {'M','a','c','h','i','n','e',0};
1953 static const WCHAR UserW
[] = {'U','s','e','r',0};
1954 static const WCHAR DefaultW
[] = {'.','D','e','f','a','u','l','t',0};
1955 static const WCHAR RegistryW
[] = {'M','a','c','h','i','n','e','\\',
1956 'S','o','f','t','w','a','r','e','\\',
1957 'W','i','n','e','\\',
1958 'W','i','n','e','\\',
1959 'C','o','n','f','i','g','\\',
1960 'R','e','g','i','s','t','r','y',0};
1961 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};
1962 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};
1963 static const WCHAR SaveOnlyUpdatedKeysW
[] = {'S','a','v','e','O','n','l','y','U','p','d','a','t','e','d','K','e','y','s',0};
1964 static const WCHAR PeriodicSaveW
[] = {'P','e','r','i','o','d','i','c','S','a','v','e',0};
1965 static const WCHAR GlobalRegistryDirW
[] = {'G','l','o','b','a','l','R','e','g','i','s','t','r','y','D','i','r',0};
1969 attr
.Length
= sizeof(attr
);
1970 attr
.RootDirectory
= 0;
1971 attr
.ObjectName
= &nameW
;
1972 attr
.Attributes
= 0;
1973 attr
.SecurityDescriptor
= NULL
;
1974 attr
.SecurityQualityOfService
= NULL
;
1976 RtlInitUnicodeString( &nameW
, UserW
);
1977 NtCreateKey( &hkey_users
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, &dispos
);
1978 if (dispos
== REG_OPENED_EXISTING_KEY
)
1980 /* someone else already loaded the registry */
1981 NtClose( hkey_users
);
1985 RtlInitUnicodeString( &nameW
, MachineW
);
1986 NtCreateKey( &hkey_local_machine
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
);
1988 attr
.RootDirectory
= hkey_users
;
1989 RtlInitUnicodeString( &nameW
, DefaultW
);
1990 if (NtCreateKey( &hkey_users_default
, KEY_ALL_ACCESS
, &attr
, 0, NULL
, 0, NULL
))
1992 ERR("Cannot create HKEY_USERS/.Default\n" );
1995 RtlOpenCurrentUser( KEY_ALL_ACCESS
, &hkey_current_user
);
1997 _allocate_default_keys();
1999 attr
.RootDirectory
= 0;
2000 RtlInitUnicodeString( &nameW
, RegistryW
);
2001 if (NtOpenKey( &hkey_config
, KEY_ALL_ACCESS
, &attr
)) hkey_config
= 0;
2003 /* load windows registry if required */
2006 attr
.RootDirectory
= hkey_config
;
2007 RtlInitUnicodeString( &nameW
, load_win_reg_filesW
);
2008 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2010 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2011 res
= !IS_OPTION_FALSE(str
[0]);
2013 if (res
) _load_windows_registry( hkey_local_machine
, hkey_current_user
, hkey_users_default
);
2015 /* load global registry if required */
2018 RtlInitUnicodeString( &nameW
, load_global_reg_filesW
);
2019 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2021 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2022 res
= !IS_OPTION_FALSE(str
[0]);
2026 /* load global registry files (stored in /etc/wine) */
2027 char *p
, configfile
[MAX_PATHNAME_LEN
];
2029 /* Override ETCDIR? */
2031 RtlInitUnicodeString( &nameW
, GlobalRegistryDirW
);
2032 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2034 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2035 RtlUnicodeToMultiByteN( configfile
, sizeof(configfile
), NULL
,
2036 str
, (strlenW(str
) + 1) * sizeof(WCHAR
));
2038 if (configfile
[0] != '/') strcpy(configfile
, ETCDIR
);
2040 TRACE("GlobalRegistryDir is '%s'.\n", configfile
);
2042 /* Load the global HKU hive directly from sysconfdir */
2043 p
= configfile
+ strlen(configfile
);
2044 strcpy(p
, SAVE_GLOBAL_REGBRANCH_USER_DEFAULT
);
2045 load_wine_registry( hkey_users
, configfile
);
2047 /* Load the global machine defaults directly from sysconfdir */
2048 strcpy(p
, SAVE_GLOBAL_REGBRANCH_LOCAL_MACHINE
);
2049 load_wine_registry( hkey_local_machine
, configfile
);
2052 /* setup registry saving */
2055 RtlInitUnicodeString( &nameW
, SaveOnlyUpdatedKeysW
);
2056 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2058 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2059 all
= IS_OPTION_FALSE(str
[0]);
2063 RtlInitUnicodeString( &nameW
, PeriodicSaveW
);
2064 if (!NtQueryValueKey( hkey_config
, &nameW
, KeyValuePartialInformation
, tmp
, sizeof(tmp
), &count
))
2066 WCHAR
*str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)tmp
)->Data
;
2067 period
= (int)strtolW(str
, NULL
, 10);
2070 /* load home registry and set saving level (0 for saving everything,
2071 * 1 for saving only modified keys) */
2073 SERVER_START_REQ( load_user_registries
)
2075 req
->hkey
= hkey_current_user
;
2077 req
->period
= period
* 1000;
2078 wine_server_call( req
);
2082 /* create hardware registry branch */
2084 create_hardware_branch();
2086 /* convert keys from config file to new registry format */
2088 convert_drive_types();
2089 convert_environment( hkey_current_user
);
2091 NtClose(hkey_users_default
);
2092 NtClose(hkey_current_user
);
2093 NtClose(hkey_users
);
2094 NtClose(hkey_local_machine
);
2095 NtClose(hkey_config
);