4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
34 #include <sys/types.h>
36 #include <sys/fcntl.h>
42 #include "wine/winbase16.h"
43 #include "wine/winestring.h"
47 #include "debugtools.h"
53 DEFAULT_DEBUG_CHANNEL(reg
);
55 static void REGISTRY_Init(void);
56 /* FIXME: following defines should be configured global ... */
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
70 static void *xmalloc( size_t size
)
74 res
= malloc (size
? size
: 1);
76 WARN("Virtual memory exhausted.\n");
84 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
85 * If so, can we remove them?
87 * No, the memory handling functions are called very often in here,
88 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
89 * loading 100 times slower. -MM
91 static LPWSTR
strdupA2W(LPCSTR src
)
94 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
95 lstrcpyAtoW(dest
,src
);
101 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
104 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
106 lstrcpynAtoW(dest
,src
,nchars
+1);
112 /******************************************************************************
113 * REGISTRY_Init [Internal]
114 * Registry initialisation, allocates some default keys.
116 static void REGISTRY_Init(void) {
122 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
125 /* This was an Open, but since it is called before the real registries
126 are loaded, it was changed to a Create - MTB 980507*/
127 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
128 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
131 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
135 * string RegisteredOwner
136 * string RegisteredOrganization
139 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
144 if (-1!=gethostname(buf
,200)) {
145 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
146 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
152 /************************ SAVE Registry Function ****************************/
154 #define REGISTRY_SAVE_VERSION 0x00000001
156 /* Registry saveformat:
157 * If you change it, increase above number by 1, which will flush
158 * old registry database files.
161 * "WINE REGISTRY Version %d"
165 * valuename=lastmodified,type,data
169 * keyname,valuename,stringdata:
170 * the usual ascii characters from 0x00-0xff (well, not 0x00)
171 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
172 * ( "=\\\t" escaped in \uXXXX form.)
176 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
178 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
179 * SaveOnlyUpdatedKeys=yes
182 /* Same as RegSaveKey but with Unix pathnames */
183 static void save_key( HKEY hkey
, const char *filename
)
185 struct save_registry_request
*req
= get_req_buffer();
190 char *rname
= HeapAlloc( GetProcessHeap(), 0, PATH_MAX
);
193 /* use realpath to resolve any symlinks
194 * I assume that rname is filled in correctly if the error is ENOENT */
195 if ((realpath(filename
, rname
) == NULL
) && (errno
!= ENOENT
))
197 ERR( "Failed to find real path of %s: ", filename
);
198 perror( "realpath" );
199 HeapFree( GetProcessHeap(), 0, rname
);
203 name
= HeapAlloc( GetProcessHeap(), 0, strlen(rname
) + 20 );
206 strcpy( name
, rname
);
207 if ((p
= strrchr( name
, '/' ))) p
++;
212 sprintf( p
, "reg%04x.tmp", count
++ );
213 handle
= FILE_CreateFile( name
, GENERIC_WRITE
, 0, NULL
,
214 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1, TRUE
);
215 if (handle
!= INVALID_HANDLE_VALUE
) break;
216 if ((ret
= GetLastError()) != ERROR_ALREADY_EXISTS
) break;
219 if (handle
!= INVALID_HANDLE_VALUE
)
223 ret
= server_call_noerr( REQ_SAVE_REGISTRY
);
224 CloseHandle( handle
);
225 if (ret
) unlink( name
);
226 else if (rename( name
, rname
) == -1)
228 ERR( "Failed to move %s to %s: ", name
, rname
);
233 else ERR( "Failed to save registry to %s, err %ld\n", name
, GetLastError() );
235 HeapFree( GetProcessHeap(), 0, rname
);
236 HeapFree( GetProcessHeap(), 0, name
);
240 /******************************************************************************
241 * SHELL_SaveRegistry [Internal]
243 void SHELL_SaveRegistry( void )
245 const char *confdir
= get_config_dir();
246 struct set_registry_levels_request
*req
= get_req_buffer();
249 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
250 int version
= PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
252 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
255 req
->version
= version
;
256 server_call( REQ_SET_REGISTRY_LEVELS
);
258 if (!(fn
= HeapAlloc( GetProcessHeap(), 0, MAX_PATHNAME_LEN
)))
260 ERR( "Not enough memory to save registry\n" );
264 if (PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1))
266 if (PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", fn
, MAX_PATHNAME_LEN
))
267 save_key( HKEY_CURRENT_USER
, fn
);
268 if (PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "", fn
, MAX_PATHNAME_LEN
))
269 save_key( HKEY_LOCAL_MACHINE
, fn
);
270 if (PROFILE_GetWineIniString( "Registry", "AltUserFile", "", fn
, MAX_PATHNAME_LEN
))
271 save_key( HKEY_USERS
, fn
);
275 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
278 strcpy( fn
, confdir
);
279 str
= fn
+ strlen(fn
);
282 strcpy( str
, SAVE_CURRENT_USER
);
283 save_key( HKEY_CURRENT_USER
, fn
);
285 strcpy( str
, SAVE_LOCAL_MACHINE
);
286 save_key( HKEY_LOCAL_MACHINE
, fn
);
288 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
289 save_key( HKEY_USERS
, fn
);
292 HeapFree( GetProcessHeap(), 0, fn
);
295 /* Periodic save callback */
296 static void CALLBACK
periodic_save( ULONG_PTR dummy
)
298 SHELL_SaveRegistry();
301 /************************ LOAD Registry Function ****************************/
305 /******************************************************************************
306 * _find_or_add_key [Internal]
308 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
311 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
312 if (keyname
) free( keyname
);
316 /******************************************************************************
317 * _find_or_add_value [Internal]
319 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
321 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
322 if (name
) free( name
);
323 if (data
) free( data
);
327 /******************************************************************************
328 * _wine_read_line [Internal]
330 * reads a line including dynamically enlarging the readbuffer and throwing
333 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
343 s
=fgets(curread
,mylen
,F
);
346 if (NULL
==(s
=strchr(curread
,'\n'))) {
347 /* buffer wasn't large enough */
348 curoff
= strlen(*buf
);
349 curread
= realloc(*buf
,*len
*2);
350 if(curread
== NULL
) {
351 WARN("Out of memory");
356 mylen
= *len
; /* we filled up the buffer and
357 * got new '*len' bytes to fill
365 /* throw away comments */
366 if (**buf
=='#' || **buf
==';') {
371 if (s
) /* got end of line */
378 /******************************************************************************
379 * _wine_read_USTRING [Internal]
381 * converts a char* into a UNICODE string (up to a special char)
382 * and returns the position exactly after that string
384 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
389 /* read up to "=" or "\0" or "\n" */
391 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
393 while (*s
&& (*s
!='\n') && (*s
!='=')) {
395 *ws
++=*((unsigned char*)s
++);
399 /* Dangling \ ... may only happen if a registry
400 * write was short. FIXME: What do to?
410 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
418 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
419 if (!sscanf(xbuf
,"%x",&wc
))
420 WARN("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
422 *ws
++ =(unsigned short)wc
;
431 /******************************************************************************
432 * _wine_loadsubkey [Internal]
435 * It seems like this is returning a boolean. Should it?
441 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
448 TRACE("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
450 /* Good. We already got a line here ... so parse it */
460 WARN("Got a subhierarchy without resp. key?\n");
463 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
464 if (!_wine_read_line(F
,buf
,buflen
))
469 /* let the caller handle this line */
470 if (i
<level
|| **buf
=='\0')
473 /* it can be: a value or a keyname. Parse the name first */
474 s
=_wine_read_USTRING(s
,&name
);
476 /* switch() default: hack to avoid gotos */
480 if (subkey
) RegCloseKey( subkey
);
481 subkey
=_find_or_add_key(hkey
,name
);
484 int len
,lastmodified
,type
;
487 WARN("Unexpected character: %c\n",*s
);
491 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
492 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
499 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
502 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
503 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
504 len
= lstrlenW((LPWSTR
)data
)*2+2;
507 data
= (LPBYTE
)xmalloc(len
+1);
508 for (i
=0;i
<len
;i
++) {
510 if (*s
>='0' && *s
<='9')
512 if (*s
>='a' && *s
<='f')
513 data
[i
]=(*s
-'a'+'\xa')<<4;
514 if (*s
>='A' && *s
<='F')
515 data
[i
]=(*s
-'A'+'\xa')<<4;
517 if (*s
>='0' && *s
<='9')
519 if (*s
>='a' && *s
<='f')
520 data
[i
]|=*s
-'a'+'\xa';
521 if (*s
>='A' && *s
<='F')
522 data
[i
]|=*s
-'A'+'\xa';
526 _find_or_add_value(hkey
,name
,type
,data
,len
);
529 /* read the next line */
530 if (!_wine_read_line(F
,buf
,buflen
))
534 if (subkey
) RegCloseKey( subkey
);
539 /******************************************************************************
540 * _wine_loadsubreg [Internal]
542 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
548 buf
=xmalloc(10);buflen
=10;
549 if (!_wine_read_line(F
,&buf
,&buflen
)) {
553 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
557 if (ver
!=REGISTRY_SAVE_VERSION
) {
558 if (ver
== 2) /* new version */
561 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
562 FILE_ATTRIBUTE_NORMAL
, -1, TRUE
)) != INVALID_HANDLE_VALUE
)
564 struct load_registry_request
*req
= get_req_buffer();
568 server_call( REQ_LOAD_REGISTRY
);
576 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
581 if (!_wine_read_line(F
,&buf
,&buflen
)) {
585 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
594 /******************************************************************************
595 * _wine_loadreg [Internal]
597 static void _wine_loadreg( HKEY hkey
, char *fn
)
601 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
605 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
608 _wine_loadsubreg(F
,hkey
,fn
);
612 /* NT REGISTRY LOADER */
614 #ifdef HAVE_SYS_MMAN_H
615 # include <sys/mman.h>
619 #define MAP_FAILED ((LPVOID)-1)
622 #define NT_REG_BLOCK_SIZE 0x1000
624 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
625 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
626 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
627 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
629 /* subblocks of nk */
630 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
631 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
632 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
634 #define NT_REG_KEY_BLOCK_TYPE 0x20
635 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
639 DWORD id
; /* 0x66676572 'regf'*/
640 DWORD uk1
; /* 0x04 */
641 DWORD uk2
; /* 0x08 */
642 FILETIME DateModified
; /* 0x0c */
643 DWORD uk3
; /* 0x14 */
644 DWORD uk4
; /* 0x18 */
645 DWORD uk5
; /* 0x1c */
646 DWORD uk6
; /* 0x20 */
647 DWORD RootKeyBlock
; /* 0x24 */
648 DWORD BlockSize
; /* 0x28 */
650 DWORD Checksum
; /* at offset 0x1FC */
661 DWORD id
; /* 0x6E696268 'hbin' */
665 DWORD uk2
; /* 0x10 */
666 DWORD uk3
; /* 0x14 */
667 DWORD uk4
; /* 0x18 */
668 DWORD size
; /* 0x1C */
669 nt_hbin_sub hbin_sub
; /* 0x20 */
673 * the value_list consists of offsets to the values (vk)
677 WORD SubBlockId
; /* 0x00 0x6B6E */
678 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
679 FILETIME writetime
; /* 0x04 */
680 DWORD uk1
; /* 0x0C */
681 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
682 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
683 DWORD uk8
; /* 0x18 */
684 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
685 DWORD uk2
; /* 0x20 */
686 DWORD nr_values
; /* 0x24 number of values */
687 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
688 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
689 DWORD off_class
; /* 0x30 Offset of the Class-Name */
690 DWORD uk3
; /* 0x34 */
691 DWORD uk4
; /* 0x38 */
692 DWORD uk5
; /* 0x3c */
693 DWORD uk6
; /* 0x40 */
694 DWORD uk7
; /* 0x44 */
695 WORD name_len
; /* 0x48 name-length */
696 WORD class_len
; /* 0x4a class-name length */
697 char name
[1]; /* 0x4c key-name */
702 DWORD off_nk
; /* 0x00 */
703 DWORD name
; /* 0x04 */
708 WORD id
; /* 0x00 0x666c */
709 WORD nr_keys
; /* 0x06 */
710 hash_rec hash_rec
[1];
714 list of subkeys without hash
722 WORD id
; /* 0x00 0x696c */
728 this is a intermediate node
740 WORD id
; /* 0x00 0x6972 */
741 WORD nr_li
; /* 0x02 number off offsets */
742 DWORD off_li
[1]; /* 0x04 points to li */
747 WORD id
; /* 0x00 'vk' */
757 LPSTR
_strdupnA( LPCSTR str
, int len
)
761 if (!str
) return NULL
;
762 ret
= malloc( len
+ 1 );
763 lstrcpynA( ret
, str
, len
);
768 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
);
769 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
);
770 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
);
777 * 0 value is a default value
778 * 1 the value has a name
781 * len of the whole data block
783 * bytes including the terminating \0 = 2*(number_of_chars+1)
784 * - reg_dword, reg_binary:
785 * if highest bit of data_len is set data_off contains the value
787 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
)
791 BYTE
* pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
793 if(vk
->id
!= NT_REG_VALUE_BLOCK_ID
) goto error
;
795 lstrcpynAtoW(name
, vk
->name
, vk
->nam_len
+1);
797 ret
= RegSetValueExW( hkey
, (vk
->flag
& 0x00000001) ? name
: NULL
, 0, vk
->type
,
798 (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
,
799 (vk
->data_len
& 0x7fffffff) );
800 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
803 ERR_(reg
)("unknown block found (0x%04x), please report!\n", vk
->id
);
810 * this structure contains the hash of a keyname and points to all
813 * exception: if the id is 'il' there are no hash values and every
816 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
)
820 if (lf
->id
== NT_REG_HASH_BLOCK_ID
)
822 if (subkeys
!= lf
->nr_keys
) goto error1
;
824 for (i
=0; i
<lf
->nr_keys
; i
++)
826 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), level
)) goto error
;
829 else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
)
831 nt_li
* li
= (nt_li
*)lf
;
832 if (subkeys
!= li
->nr_keys
) goto error1
;
834 for (i
=0; i
<li
->nr_keys
; i
++)
836 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), level
)) goto error
;
839 else if (lf
->id
== NT_REG_RI_BLOCK_ID
) /* ri */
841 nt_ri
* ri
= (nt_ri
*)lf
;
844 /* count all subkeys */
845 for (i
=0; i
<ri
->nr_li
; i
++)
847 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
848 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
849 li_subkeys
+= li
->nr_keys
;
853 if (subkeys
!= li_subkeys
) goto error1
;
855 /* loop through the keys */
856 for (i
=0; i
<ri
->nr_li
; i
++)
858 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
859 if (!_nt_parse_lf(hkey
, base
, li
->nr_keys
, (nt_lf
*)li
, level
)) goto error
;
868 error2
: ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
871 error1
: ERR_(reg
)("registry file corrupt! (inconsistent number of subkeys)\n");
874 error
: ERR_(reg
)("error reading lf block\n");
878 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
885 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)
887 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
891 if((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) &&
892 (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
))
894 ERR_(reg
)("registry file corrupt!\n");
898 /* create the new key */
901 name
= _strdupnA( nk
->name
, nk
->name_len
+1);
902 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
906 /* loop through the subkeys */
909 nt_lf
* lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
910 if (!_nt_parse_lf(subkey
, base
, nk
->nr_subkeys
, lf
, level
-1)) goto error1
;
913 /* loop trough the value list */
914 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
915 for (i
=0; i
<nk
->nr_values
; i
++)
917 nt_vk
* vk
= (nt_vk
*)(base
+vl
[i
]+4);
918 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
924 error1
: RegCloseKey(subkey
);
930 /* windows 95 registry loader */
932 /* SECTION 1: main header
936 #define W95_REG_CREG_ID 0x47455243
940 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
941 DWORD version
; /* ???? 0x00010000 */
942 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
943 DWORD uk2
; /* 0x0c */
944 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
950 /* SECTION 2: Directory information (tree structure)
952 * once on offset 0x20
954 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
956 #define W95_REG_RGKN_ID 0x4e4b4752
960 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
961 DWORD size
; /* Size of the RGKN-block */
962 DWORD root_off
; /* Rel. Offset of the root-record */
966 /* Disk Key Entry Structure
968 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
969 * hive itself. It looks the same like other keys. Even the ID-number can
972 * The "hash"-value is a value representing the key's name. Windows will not
973 * search for the name, but for a matching hash-value. if it finds one, it
974 * will compare the actual string info, otherwise continue with the next key.
975 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
976 * of the string which are smaller than 0x80 (128) to this D-Word.
978 * If you want to modify key names, also modify the hash-values, since they
979 * cannot be found again (although they would be displayed in REGEDIT)
980 * End of list-pointers are filled with 0xFFFFFFFF
982 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
983 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
984 * structure) and reading another RGDB_section.
986 * there is a one to one relationship between dke and dkh
988 /* key struct, once per key */
991 DWORD x1
; /* Free entry indicator(?) */
992 DWORD hash
; /* sum of bytes of keyname */
993 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
994 DWORD prevlvl
; /* offset of previous key */
995 DWORD nextsub
; /* offset of child key */
996 DWORD next
; /* offset of sibling key */
997 WORD nrLS
; /* id inside the rgdb block */
998 WORD nrMS
; /* number of the rgdb block */
1001 /* SECTION 3: key information, values and data
1004 * section: [blocks]* (repeat creg->rgdb_num times)
1005 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
1006 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
1008 * An interesting relationship exists in RGDB_section. The value at offset
1009 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1010 * idea at the moment what this means. (Kevin Cozens)
1013 /* block header, once per block */
1014 #define W95_REG_RGDB_ID 0x42444752
1018 DWORD id
; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
1019 DWORD size
; /* 0x04 */
1020 DWORD uk1
; /* 0x08 */
1021 DWORD uk2
; /* 0x0c */
1022 DWORD uk3
; /* 0x10 */
1023 DWORD uk4
; /* 0x14 */
1024 DWORD uk5
; /* 0x18 */
1025 DWORD uk6
; /* 0x1c */
1029 /* Disk Key Header structure (RGDB part), once per key */
1032 DWORD nextkeyoff
; /* 0x00 offset to next dkh*/
1033 WORD nrLS
; /* 0x04 id inside the rgdb block */
1034 WORD nrMS
; /* 0x06 number of the rgdb block */
1035 DWORD bytesused
; /* 0x08 */
1036 WORD keynamelen
; /* 0x0c len of name */
1037 WORD values
; /* 0x0e number of values */
1038 DWORD xx1
; /* 0x10 */
1039 char name
[1]; /* 0x14 */
1040 /* dkv */ /* 0x14 + keynamelen */
1043 /* Disk Key Value structure, once per value */
1046 DWORD type
; /* 0x00 */
1047 DWORD x1
; /* 0x04 */
1048 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
1049 WORD valdatalen
; /* 0x0A length of data */
1050 char name
[1]; /* 0x0c */
1051 /* raw data */ /* 0x0c + valnamelen */
1054 /******************************************************************************
1055 * _w95_lookup_dkh [Internal]
1057 * seeks the dkh belonging to a dke
1059 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
1065 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
); /* get the beginning of the rgdb datastore */
1066 assert (creg
->rgdb_num
> nrMS
); /* check: requested block < last_block) */
1068 /* find the right block */
1069 for(i
=0; i
<nrMS
;i
++)
1071 assert(rgdb
->id
== W95_REG_RGDB_ID
); /* check the magic */
1072 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
1075 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
1079 if(nrLS
==dkh
->nrLS
) return dkh
;
1080 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
1081 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
1086 /******************************************************************************
1087 * _w95_parse_dkv [Internal]
1089 static int _w95_parse_dkv (
1100 /* first value block */
1101 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
1103 /* loop trought the values */
1104 for (i
=0; i
< dkh
->values
; i
++)
1106 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
+1);
1107 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
1108 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
1112 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
1117 /******************************************************************************
1118 * _w95_parse_dke [Internal]
1120 static int _w95_parse_dke(
1128 HKEY hsubkey
= hkey
;
1132 /* get start address of root key block */
1133 if (!dke
) dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1135 /* special root key */
1136 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
1138 /* parse the one subkey*/
1139 if (dke
->nextsub
!= 0xffffffff)
1141 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
1143 /* has no sibling keys */
1147 /* search subblock */
1148 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
1150 fprintf(stderr
, "dke pointing to missing dkh !\n");
1156 /* walk sibling keys */
1157 if (dke
->next
!= 0xffffffff )
1159 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1162 /* create subkey and insert values */
1163 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
+1);
1164 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1166 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1170 if (dke
->nextsub
!= 0xffffffff)
1172 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1176 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1179 /* end windows 95 loader */
1181 /******************************************************************************
1182 * NativeRegLoadKey [Internal]
1184 * Loads a native registry file (win95/nt)
1187 * level number of levels to cut away (eg. ".Default" in user.dat)
1189 * this function intentionally uses unix file functions to make it possible
1190 * to move it to a seperate registry helper programm
1192 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1196 DOS_FULL_NAME full_name
;
1200 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1202 /* map the registry into the memory */
1203 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1204 if ((fstat(fd
, &st
) == -1)) goto error
;
1205 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1207 switch (*(LPDWORD
)base
)
1209 /* windows 95 'creg' */
1210 case W95_REG_CREG_ID
:
1215 TRACE_(reg
)("Loading win95 registry '%s' '%s'\n",fn
, full_name
.long_name
);
1217 /* load the header (rgkn) */
1218 rgkn
= (_w95rgkn
*)(creg
+ 1);
1219 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1221 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1225 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1229 case NT_REG_HEADER_BLOCK_ID
:
1233 nt_hbin_sub
* hbin_sub
;
1236 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
1242 hbin
= (nt_hbin
*) ((char *) base
+ 0x1000);
1243 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1245 ERR_(reg
)( "%s hbin block invalid\n", fn
);
1249 /* hbin_sub block */
1250 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1251 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1253 ERR_(reg
)( "%s hbin_sub block invalid\n", fn
);
1258 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1259 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1261 ERR_(reg
)( "%s special nk block not found\n", fn
);
1265 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1270 ERR("unknown signature in registry file %s.\n",fn
);
1274 if(!ret
) ERR("error loading registry file %s\n", fn
);
1275 error1
: munmap(base
, st
.st_size
);
1280 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1282 reghack - windows 3.11 registry data format demo program.
1284 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1285 a combined hash table and tree description, and finally a text table.
1287 The header is obvious from the struct header. The taboff1 and taboff2
1288 fields are always 0x20, and their usage is unknown.
1290 The 8-byte entry table has various entry types.
1292 tabent[0] is a root index. The second word has the index of the root of
1294 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1295 the index of the key/value that has that hash. Data with the same
1296 hash value are on a circular list. The other three words in the
1297 hash entry are always zero.
1298 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1299 entry: dirent and keyent/valent. They are identified by context.
1300 tabent[freeidx] is the first free entry. The first word in a free entry
1301 is the index of the next free entry. The last has 0 as a link.
1302 The other three words in the free list are probably irrelevant.
1304 Entries in text table are preceeded by a word at offset-2. This word
1305 has the value (2*index)+1, where index is the referring keyent/valent
1306 entry in the table. I have no suggestion for the 2* and the +1.
1307 Following the word, there are N bytes of data, as per the keyent/valent
1308 entry length. The offset of the keyent/valent entry is from the start
1309 of the text table to the first data byte.
1311 This information is not available from Microsoft. The data format is
1312 deduced from the reg.dat file by me. Mistakes may
1313 have been made. I claim no rights and give no guarantees for this program.
1315 Tor Sjøwall, tor@sn.no
1318 /* reg.dat header format */
1319 struct _w31_header
{
1320 char cookie
[8]; /* 'SHCC3.10' */
1321 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1322 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1323 unsigned long tabcnt
; /* number of entries in index table */
1324 unsigned long textoff
; /* offset of text part */
1325 unsigned long textsize
; /* byte size of text part */
1326 unsigned short hashsize
; /* hash size */
1327 unsigned short freeidx
; /* free index */
1330 /* generic format of table entries */
1331 struct _w31_tabent
{
1332 unsigned short w0
, w1
, w2
, w3
;
1335 /* directory tabent: */
1336 struct _w31_dirent
{
1337 unsigned short sibling_idx
; /* table index of sibling dirent */
1338 unsigned short child_idx
; /* table index of child dirent */
1339 unsigned short key_idx
; /* table index of key keyent */
1340 unsigned short value_idx
; /* table index of value valent */
1344 struct _w31_keyent
{
1345 unsigned short hash_idx
; /* hash chain index for string */
1346 unsigned short refcnt
; /* reference count */
1347 unsigned short length
; /* length of string */
1348 unsigned short string_off
; /* offset of string in text table */
1352 struct _w31_valent
{
1353 unsigned short hash_idx
; /* hash chain index for string */
1354 unsigned short refcnt
; /* reference count */
1355 unsigned short length
; /* length of string */
1356 unsigned short string_off
; /* offset of string in text table */
1359 /* recursive helper function to display a directory tree */
1361 __w31_dumptree( unsigned short idx
,
1363 struct _w31_tabent
*tab
,
1364 struct _w31_header
*head
,
1366 time_t lastmodified
,
1369 struct _w31_dirent
*dir
;
1370 struct _w31_keyent
*key
;
1371 struct _w31_valent
*val
;
1373 static char tail
[400];
1376 dir
=(struct _w31_dirent
*)&tab
[idx
];
1379 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1381 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1382 tail
[key
->length
]='\0';
1383 /* all toplevel entries AND the entries in the
1384 * toplevel subdirectory belong to \SOFTWARE\Classes
1386 if (!level
&& !lstrcmpA(tail
,".classes")) {
1387 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1388 idx
=dir
->sibling_idx
;
1391 if (subkey
) RegCloseKey( subkey
);
1392 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1393 /* only add if leaf node or valued node */
1394 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1395 if (dir
->value_idx
) {
1396 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1397 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1398 tail
[val
->length
]='\0';
1399 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1403 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1405 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1406 idx
=dir
->sibling_idx
;
1408 if (subkey
) RegCloseKey( subkey
);
1412 /******************************************************************************
1413 * _w31_loadreg [Internal]
1415 void _w31_loadreg(void) {
1417 struct _w31_header head
;
1418 struct _w31_tabent
*tab
;
1422 BY_HANDLE_FILE_INFORMATION hfinfo
;
1423 time_t lastmodified
;
1427 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1428 if (hf
==HFILE_ERROR
)
1431 /* read & dump header */
1432 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1433 ERR("reg.dat is too short.\n");
1437 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1438 ERR("reg.dat has bad signature.\n");
1443 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1444 /* read and dump index table */
1446 if (len
!=_lread(hf
,tab
,len
)) {
1447 ERR("couldn't read %d bytes.\n",len
);
1454 txt
= xmalloc(head
.textsize
);
1455 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1456 ERR("couldn't seek to textblock.\n");
1462 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1463 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1470 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1471 ERR("GetFileInformationByHandle failed?.\n");
1477 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1478 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1485 /**********************************************************************************
1486 * SetLoadLevel [Internal]
1488 * set level to 0 for loading system files
1489 * set level to 1 for loading user files
1491 static void SetLoadLevel(int level
)
1493 struct set_registry_levels_request
*req
= get_req_buffer();
1495 req
->current
= level
;
1498 server_call( REQ_SET_REGISTRY_LEVELS
);
1501 /**********************************************************************************
1502 * SHELL_LoadRegistry [Internal]
1504 #define REG_DONTLOAD -1
1509 void SHELL_LoadRegistry( void )
1512 char windir
[MAX_PATHNAME_LEN
];
1513 char path
[MAX_PATHNAME_LEN
];
1514 int systemtype
= REG_WIN31
;
1518 if (!CLIENT_IsBootThread()) return; /* already loaded */
1523 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1525 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1527 /* test %windir%/system32/config/system --> winnt */
1528 strcpy(path
, windir
);
1529 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1530 if(GetFileAttributesA(path
) != -1)
1532 systemtype
= REG_WINNT
;
1536 /* test %windir%/system.dat --> win95 */
1537 strcpy(path
, windir
);
1538 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1539 if(GetFileAttributesA(path
) != -1)
1541 systemtype
= REG_WIN95
;
1545 if ((systemtype
==REG_WINNT
)
1546 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1548 MESSAGE("When you are running with a native NT directory specify\n");
1549 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1550 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1551 systemtype
= REG_DONTLOAD
;
1556 /* only wine registry */
1557 systemtype
= REG_DONTLOAD
;
1567 /* Load windows 95 entries */
1568 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1570 strcpy(path
, windir
);
1571 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1572 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1574 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1576 /* user specific user.dat */
1577 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1578 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1580 MESSAGE("can't load win95 user-registry %s\n", path
);
1581 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1583 /* default user.dat */
1584 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1586 strcpy(path
, windir
);
1587 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1588 NativeRegLoadKey(hkey
, path
, 1);
1594 /* global user.dat */
1595 strcpy(path
, windir
);
1596 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1597 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1602 /* default user.dat */
1603 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1605 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1606 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1608 MESSAGE("can't load NT user-registry %s\n", path
);
1609 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1613 /* default user.dat */
1614 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1616 strcpy(path
, windir
);
1617 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1618 NativeRegLoadKey(hkey
, path
, 1);
1624 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1627 strcpy(path
, windir
);
1628 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1629 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1631 strcpy(path
, windir
);
1632 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1633 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1635 strcpy(path
, windir
);
1636 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1637 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1639 strcpy(path
, windir
);
1640 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1641 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1643 /* this key is generated when the nt-core booted successfully */
1644 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1649 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1652 * Load the global HKU hive directly from sysconfdir
1654 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1657 * Load the global machine defaults directly form sysconfdir
1659 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1665 * Load the user saved registries
1667 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1669 const char *confdir
= get_config_dir();
1670 int len
= strlen(confdir
) + 20;
1673 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1675 * Load user's personal versions of global HKU/.Default keys
1680 strcpy( fn
, confdir
);
1681 str
= fn
+ strlen(fn
);
1684 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1685 _wine_loadreg( HKEY_USERS
, fn
);
1687 strcpy( str
, SAVE_CURRENT_USER
);
1688 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1690 strcpy( str
, SAVE_LOCAL_MACHINE
);
1691 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1693 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1698 * Load HKCU, get the registry location from the config
1699 * file, if exist, load and keep going.
1701 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1703 if (PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "", path
, sizeof(path
) ))
1704 _wine_loadreg( HKEY_CURRENT_USER
, path
);
1707 * Load HKU, get the registry location from the config
1708 * file, if exist, load and keep going.
1710 if (PROFILE_GetWineIniString ( "registry", "AltUserFile", "", path
, sizeof(path
) ))
1711 _wine_loadreg( HKEY_USERS
, path
);
1714 * Load HKLM, get the registry location from the config
1715 * file, if exist, load and keep going.
1717 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "", path
, sizeof(path
) ))
1718 _wine_loadreg( HKEY_LOCAL_MACHINE
, path
);
1722 /* start the periodic saving timer */
1723 void SHELL_InitRegistrySaving(void)
1727 if (!CLIENT_IsBootThread()) return;
1729 if ((save_timeout
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1731 SERVICE_AddTimer( save_timeout
* 1000000, periodic_save
, 0 );
1736 /********************* API FUNCTIONS ***************************************/
1741 /******************************************************************************
1742 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1743 * Immediately writes key to registry.
1744 * Only returns after data has been written to disk.
1746 * FIXME: does it really wait until data is written ?
1749 * hkey [I] Handle of key to write
1752 * Success: ERROR_SUCCESS
1753 * Failure: Error code
1755 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1757 FIXME( "(%x): stub\n", hkey
);
1758 return ERROR_SUCCESS
;
1761 /******************************************************************************
1762 * RegConnectRegistryW [ADVAPI32.128]
1765 * lpMachineName [I] Address of name of remote computer
1766 * hHey [I] Predefined registry handle
1767 * phkResult [I] Address of buffer for remote registry handle
1769 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1772 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1774 if (!lpMachineName
|| !*lpMachineName
) {
1775 /* Use the local machine name */
1776 return RegOpenKey16( hKey
, "", phkResult
);
1779 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1780 return ERROR_BAD_NETPATH
;
1784 /******************************************************************************
1785 * RegConnectRegistryA [ADVAPI32.127]
1787 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1790 LPWSTR machineW
= strdupA2W(machine
);
1791 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1797 /******************************************************************************
1798 * RegGetKeySecurity [ADVAPI32.144]
1799 * Retrieves a copy of security descriptor protecting the registry key
1802 * hkey [I] Open handle of key to set
1803 * SecurityInformation [I] Descriptor contents
1804 * pSecurityDescriptor [O] Address of descriptor for key
1805 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1808 * Success: ERROR_SUCCESS
1809 * Failure: Error code
1811 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1812 SECURITY_INFORMATION SecurityInformation
,
1813 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1814 LPDWORD lpcbSecurityDescriptor
)
1816 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1817 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1819 /* FIXME: Check for valid SecurityInformation values */
1821 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1822 return ERROR_INSUFFICIENT_BUFFER
;
1824 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1825 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1827 return ERROR_SUCCESS
;
1831 /******************************************************************************
1832 * RegNotifyChangeKeyValue [ADVAPI32.???]
1835 * hkey [I] Handle of key to watch
1836 * fWatchSubTree [I] Flag for subkey notification
1837 * fdwNotifyFilter [I] Changes to be reported
1838 * hEvent [I] Handle of signaled event
1839 * fAsync [I] Flag for asynchronous reporting
1841 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1842 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1845 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1847 return ERROR_SUCCESS
;
1851 /******************************************************************************
1852 * RegUnLoadKeyW [ADVAPI32.173]
1855 * hkey [I] Handle of open key
1856 * lpSubKey [I] Address of name of subkey to unload
1858 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1860 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1861 return ERROR_SUCCESS
;
1865 /******************************************************************************
1866 * RegUnLoadKeyA [ADVAPI32.172]
1868 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1871 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1872 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1873 if(lpSubKeyW
) free(lpSubKeyW
);
1878 /******************************************************************************
1879 * RegSetKeySecurity [ADVAPI32.167]
1882 * hkey [I] Open handle of key to set
1883 * SecurityInfo [I] Descriptor contents
1884 * pSecurityDesc [I] Address of descriptor for key
1886 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1887 PSECURITY_DESCRIPTOR pSecurityDesc
)
1889 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1891 /* It seems to perform this check before the hkey check */
1892 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1893 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1894 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1895 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1898 return ERROR_INVALID_PARAMETER
;
1901 return ERROR_INVALID_PARAMETER
;
1903 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1905 return ERROR_SUCCESS
;
1909 /******************************************************************************
1910 * RegRestoreKeyW [ADVAPI32.164]
1913 * hkey [I] Handle of key where restore begins
1914 * lpFile [I] Address of filename containing saved tree
1915 * dwFlags [I] Optional flags
1917 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1919 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1921 /* It seems to do this check before the hkey check */
1922 if (!lpFile
|| !*lpFile
)
1923 return ERROR_INVALID_PARAMETER
;
1925 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1927 /* Check for file existence */
1929 return ERROR_SUCCESS
;
1933 /******************************************************************************
1934 * RegRestoreKeyA [ADVAPI32.163]
1936 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1939 LPWSTR lpFileW
= strdupA2W(lpFile
);
1940 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1941 if(lpFileW
) free(lpFileW
);
1946 /******************************************************************************
1947 * RegReplaceKeyW [ADVAPI32.162]
1950 * hkey [I] Handle of open key
1951 * lpSubKey [I] Address of name of subkey
1952 * lpNewFile [I] Address of filename for file with new data
1953 * lpOldFile [I] Address of filename for backup file
1955 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1958 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1959 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1960 return ERROR_SUCCESS
;
1964 /******************************************************************************
1965 * RegReplaceKeyA [ADVAPI32.161]
1967 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1971 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1972 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1973 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1974 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1986 /* 16-bit functions */
1988 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1989 * some programs. Do not remove those cases. -MM
1991 static inline void fix_win16_hkey( HKEY
*hkey
)
1993 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1996 /******************************************************************************
1997 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1999 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
2001 fix_win16_hkey( &hkey
);
2002 return RegEnumKeyA( hkey
, index
, name
, name_len
);
2005 /******************************************************************************
2006 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2008 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
2010 fix_win16_hkey( &hkey
);
2011 return RegOpenKeyA( hkey
, name
, retkey
);
2014 /******************************************************************************
2015 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2017 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
2019 fix_win16_hkey( &hkey
);
2020 return RegCreateKeyA( hkey
, name
, retkey
);
2023 /******************************************************************************
2024 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2026 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
2028 fix_win16_hkey( &hkey
);
2029 return RegDeleteKeyA( hkey
, name
);
2032 /******************************************************************************
2033 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2035 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
2037 fix_win16_hkey( &hkey
);
2038 return RegCloseKey( hkey
);
2041 /******************************************************************************
2042 * RegSetValue16 [KERNEL.221] [SHELL.5]
2044 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
2046 fix_win16_hkey( &hkey
);
2047 return RegSetValueA( hkey
, name
, type
, data
, count
);
2050 /******************************************************************************
2051 * RegDeleteValue16 [KERNEL.222]
2053 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
2055 fix_win16_hkey( &hkey
);
2056 return RegDeleteValueA( hkey
, name
);
2059 /******************************************************************************
2060 * RegEnumValue16 [KERNEL.223]
2062 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2063 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2065 fix_win16_hkey( &hkey
);
2066 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2069 /******************************************************************************
2070 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2073 * Is this HACK still applicable?
2076 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2077 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2080 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
2082 fix_win16_hkey( &hkey
);
2083 if (count
) *count
&= 0xffff;
2084 return RegQueryValueA( hkey
, name
, data
, count
);
2087 /******************************************************************************
2088 * RegQueryValueEx16 [KERNEL.225]
2090 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
2091 LPBYTE data
, LPDWORD count
)
2093 fix_win16_hkey( &hkey
);
2094 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
2097 /******************************************************************************
2098 * RegSetValueEx16 [KERNEL.226]
2100 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
2101 CONST BYTE
*data
, DWORD count
)
2103 fix_win16_hkey( &hkey
);
2104 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);