4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
32 #include <sys/types.h>
34 #include <sys/fcntl.h>
40 #include "wine/winbase16.h"
41 #include "wine/winestring.h"
45 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(reg
)
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
57 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
58 #define WINE_PREFIX "/.wine"
59 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
60 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
62 /* relative in ~user/.wine/ : */
63 #define SAVE_CURRENT_USER "user.reg"
64 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
65 #define SAVE_LOCAL_MACHINE "system.reg"
67 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
68 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
71 /* what valuetypes do we need to convert? */
72 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
78 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
81 * No, the memory handling functions are called very often in here,
82 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
83 * loading 100 times slower. -MM
85 static LPWSTR
strdupA2W(LPCSTR src
)
88 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
89 lstrcpyAtoW(dest
,src
);
95 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
98 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
100 lstrcpynAtoW(dest
,src
,nchars
+1);
106 /******************************************************************************
107 * REGISTRY_Init [Internal]
108 * Registry initialisation, allocates some default keys.
110 static void REGISTRY_Init(void) {
116 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
119 /* This was an Open, but since it is called before the real registries
120 are loaded, it was changed to a Create - MTB 980507*/
121 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
122 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
125 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
129 * string RegisteredOwner
130 * string RegisteredOrganization
133 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
138 if (-1!=gethostname(buf
,200)) {
139 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
140 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
146 /************************ SAVE Registry Function ****************************/
148 #define REGISTRY_SAVE_VERSION 0x00000001
150 /* Registry saveformat:
151 * If you change it, increase above number by 1, which will flush
152 * old registry database files.
155 * "WINE REGISTRY Version %d"
159 * valuename=lastmodified,type,data
163 * keyname,valuename,stringdata:
164 * the usual ascii characters from 0x00-0xff (well, not 0x00)
165 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
166 * ( "=\\\t" escaped in \uXXXX form.)
170 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
172 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
173 * SaveOnlyUpdatedKeys=yes
176 /* Same as RegSaveKey but with Unix pathnames */
177 static void save_key( HKEY hkey
, const char *filename
)
179 struct save_registry_request
*req
= get_req_buffer();
184 char *name
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
) + 20 );
187 strcpy( name
, filename
);
188 if ((p
= strrchr( name
, '/' ))) p
++;
193 sprintf( p
, "reg%04x.tmp", count
++ );
194 handle
= FILE_CreateFile( name
, GENERIC_WRITE
, 0, NULL
,
195 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1 );
196 if (handle
!= INVALID_HANDLE_VALUE
) break;
197 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) break;
200 if (handle
!= INVALID_HANDLE_VALUE
)
204 ret
= server_call_noerr( REQ_SAVE_REGISTRY
);
205 CloseHandle( handle
);
206 if (ret
) unlink( name
);
207 else if (rename( name
, filename
) == -1)
209 ERR( "Failed to move %s to %s: ", name
, filename
);
214 HeapFree( GetProcessHeap(), 0, name
);
218 /******************************************************************************
219 * SHELL_SaveRegistryBranch [Internal]
221 * Saves main registry branch specified by hkey.
223 static void SHELL_SaveRegistryBranch(HKEY hkey
)
227 /* Find out what to save to, get from config file */
228 BOOL writeToHome
= PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
229 BOOL writeToAlt
= PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
231 /* FIXME: does this check apply to all keys written below ? */
232 if (!(home
= getenv( "HOME" )))
233 ERR("Failed to get homedirectory of UID %ld.\n",(long) getuid());
235 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
236 if (hkey
== HKEY_CLASSES_ROOT
) hkey
= HKEY_LOCAL_MACHINE
;
240 case HKEY_CURRENT_USER
:
241 fn
= xmalloc( MAX_PATHNAME_LEN
);
242 if (writeToAlt
&& PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
243 fn
, MAX_PATHNAME_LEN
- 1))
244 save_key( HKEY_CURRENT_USER
, fn
);
247 if (home
&& writeToHome
)
249 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
250 strlen(SAVE_CURRENT_USER
) + 2 );
252 strcat(fn
,WINE_PREFIX
);
254 /* create the directory. don't care about errorcodes. */
255 mkdir(fn
,0755); /* drwxr-xr-x */
256 strcat(fn
,"/"SAVE_CURRENT_USER
);
257 save_key( HKEY_CURRENT_USER
, fn
);
261 case HKEY_LOCAL_MACHINE
:
262 /* Try first saving according to the defined location in .winerc */
263 fn
= xmalloc ( MAX_PATHNAME_LEN
);
264 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
265 fn
, MAX_PATHNAME_LEN
- 1))
266 save_key( HKEY_LOCAL_MACHINE
, fn
);
269 if (home
&& writeToHome
)
271 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
272 strlen(SAVE_LOCAL_MACHINE
) + 2);
274 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
275 save_key( HKEY_LOCAL_MACHINE
, fn
);
280 fn
= xmalloc( MAX_PATHNAME_LEN
);
281 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
282 fn
, MAX_PATHNAME_LEN
- 1))
283 save_key( HKEY_USERS
, fn
);
286 if (home
&& writeToHome
)
288 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
289 strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
291 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
292 save_key( HKEY_USERS
, fn
);
297 ERR("unknown/invalid key handle !\n");
303 /******************************************************************************
304 * SHELL_SaveRegistry [Internal]
306 void SHELL_SaveRegistry( void )
308 struct set_registry_levels_request
*req
= get_req_buffer();
316 if (RegOpenKeyA(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
325 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
330 &len
)) || (type
!=REG_SZ
))
337 if (lstrcmpiA(buf
,"yes")) all
= 1;
339 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
342 req
->version
= PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
343 server_call( REQ_SET_REGISTRY_LEVELS
);
345 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER
);
346 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE
);
347 SHELL_SaveRegistryBranch(HKEY_USERS
);
350 /* Periodic save callback */
351 static void CALLBACK
periodic_save( ULONG_PTR dummy
)
353 SHELL_SaveRegistry();
356 /************************ LOAD Registry Function ****************************/
360 /******************************************************************************
361 * _find_or_add_key [Internal]
363 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
366 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
367 if (keyname
) free( keyname
);
371 /******************************************************************************
372 * _find_or_add_value [Internal]
374 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
376 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
377 if (name
) free( name
);
378 if (data
) free( data
);
382 /******************************************************************************
383 * _wine_read_line [Internal]
385 * reads a line including dynamically enlarging the readbuffer and throwing
388 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
398 s
=fgets(curread
,mylen
,F
);
401 if (NULL
==(s
=strchr(curread
,'\n'))) {
402 /* buffer wasn't large enough */
403 curoff
= strlen(*buf
);
404 *buf
= xrealloc(*buf
,*len
*2);
405 curread
= *buf
+ curoff
;
406 mylen
= *len
; /* we filled up the buffer and
407 * got new '*len' bytes to fill
415 /* throw away comments */
416 if (**buf
=='#' || **buf
==';') {
421 if (s
) /* got end of line */
428 /******************************************************************************
429 * _wine_read_USTRING [Internal]
431 * converts a char* into a UNICODE string (up to a special char)
432 * and returns the position exactly after that string
434 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
439 /* read up to "=" or "\0" or "\n" */
441 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
443 while (*s
&& (*s
!='\n') && (*s
!='=')) {
445 *ws
++=*((unsigned char*)s
++);
449 /* Dangling \ ... may only happen if a registry
450 * write was short. FIXME: What do to?
460 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
468 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
469 if (!sscanf(xbuf
,"%x",&wc
))
470 WARN("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
472 *ws
++ =(unsigned short)wc
;
481 /******************************************************************************
482 * _wine_loadsubkey [Internal]
485 * It seems like this is returning a boolean. Should it?
491 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
498 TRACE("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
500 /* Good. We already got a line here ... so parse it */
510 WARN("Got a subhierarchy without resp. key?\n");
513 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
514 if (!_wine_read_line(F
,buf
,buflen
))
519 /* let the caller handle this line */
520 if (i
<level
|| **buf
=='\0')
523 /* it can be: a value or a keyname. Parse the name first */
524 s
=_wine_read_USTRING(s
,&name
);
526 /* switch() default: hack to avoid gotos */
530 if (subkey
) RegCloseKey( subkey
);
531 subkey
=_find_or_add_key(hkey
,name
);
534 int len
,lastmodified
,type
;
537 WARN("Unexpected character: %c\n",*s
);
541 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
542 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
549 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
552 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
553 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
554 len
= lstrlenW((LPWSTR
)data
)*2+2;
557 data
= (LPBYTE
)xmalloc(len
+1);
558 for (i
=0;i
<len
;i
++) {
560 if (*s
>='0' && *s
<='9')
562 if (*s
>='a' && *s
<='f')
563 data
[i
]=(*s
-'a'+'\xa')<<4;
564 if (*s
>='A' && *s
<='F')
565 data
[i
]=(*s
-'A'+'\xa')<<4;
567 if (*s
>='0' && *s
<='9')
569 if (*s
>='a' && *s
<='f')
570 data
[i
]|=*s
-'a'+'\xa';
571 if (*s
>='A' && *s
<='F')
572 data
[i
]|=*s
-'A'+'\xa';
576 _find_or_add_value(hkey
,name
,type
,data
,len
);
579 /* read the next line */
580 if (!_wine_read_line(F
,buf
,buflen
))
584 if (subkey
) RegCloseKey( subkey
);
589 /******************************************************************************
590 * _wine_loadsubreg [Internal]
592 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
598 buf
=xmalloc(10);buflen
=10;
599 if (!_wine_read_line(F
,&buf
,&buflen
)) {
603 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
607 if (ver
!=REGISTRY_SAVE_VERSION
) {
608 if (ver
== 2) /* new version */
611 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
612 FILE_ATTRIBUTE_NORMAL
, -1 )) != INVALID_HANDLE_VALUE
)
614 struct load_registry_request
*req
= get_req_buffer();
618 server_call( REQ_LOAD_REGISTRY
);
626 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
631 if (!_wine_read_line(F
,&buf
,&buflen
)) {
635 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
644 /******************************************************************************
645 * _wine_loadreg [Internal]
647 static void _wine_loadreg( HKEY hkey
, char *fn
)
651 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
655 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
658 _wine_loadsubreg(F
,hkey
,fn
);
662 /* NT REGISTRY LOADER */
664 #ifdef HAVE_SYS_MMAN_H
665 # include <sys/mman.h>
669 #define MAP_FAILED ((LPVOID)-1)
672 #define NT_REG_BLOCK_SIZE 0x1000
674 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
675 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
676 #define NT_REG_KEY_BLOCK_ID 0x6b6e
677 #define NT_REG_VALUE_BLOCK_ID 0x6b76
678 #define NT_REG_HASH_BLOCK_ID 0x666c
679 #define NT_REG_NOHASH_BLOCK_ID 0x696c
680 #define NT_REG_KEY_BLOCK_TYPE 0x20
681 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
685 DWORD id
; /* 0x66676572 'regf'*/
686 DWORD uk1
; /* 0x04 */
687 DWORD uk2
; /* 0x08 */
688 FILETIME DateModified
; /* 0x0c */
689 DWORD uk3
; /* 0x14 */
690 DWORD uk4
; /* 0x18 */
691 DWORD uk5
; /* 0x1c */
692 DWORD uk6
; /* 0x20 */
693 DWORD RootKeyBlock
; /* 0x24 */
694 DWORD BlockSize
; /* 0x28 */
696 DWORD Checksum
; /* at offset 0x1FC */
707 DWORD id
; /* 0x6E696268 'hbin' */
711 DWORD uk2
; /* 0x10 */
712 DWORD uk3
; /* 0x14 */
713 DWORD uk4
; /* 0x18 */
714 DWORD size
; /* 0x1C */
715 nt_hbin_sub hbin_sub
; /* 0x20 */
719 * the value_list consists of offsets to the values (vk)
723 WORD SubBlockId
; /* 0x00 0x6B6E */
724 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
725 FILETIME writetime
; /* 0x04 */
726 DWORD uk1
; /* 0x0C */
727 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
728 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
729 DWORD uk8
; /* 0x18 */
730 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
731 DWORD uk2
; /* 0x20 */
732 DWORD nr_values
; /* 0x24 number of values */
733 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
734 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
735 DWORD off_class
; /* 0x30 Offset of the Class-Name */
736 DWORD uk3
; /* 0x34 */
737 DWORD uk4
; /* 0x38 */
738 DWORD uk5
; /* 0x3c */
739 DWORD uk6
; /* 0x40 */
740 DWORD uk7
; /* 0x44 */
741 WORD name_len
; /* 0x48 name-length */
742 WORD class_len
; /* 0x4a class-name length */
743 char name
[1]; /* 0x4c key-name */
748 DWORD off_nk
; /* 0x00 */
749 DWORD name
; /* 0x04 */
754 WORD id
; /* 0x00 0x666c */
755 WORD nr_keys
; /* 0x06 */
756 hash_rec hash_rec
[1];
761 WORD id
; /* 0x00 0x696c */
768 WORD id
; /* 0x00 'vk' */
778 LPSTR
_strdupnA( LPCSTR str
, int len
)
782 if (!str
) return NULL
;
783 ret
= malloc( len
+ 1 );
784 lstrcpynA( ret
, str
, len
);
789 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
);
790 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
);
791 static int _nt_parse_lf(HKEY hkey
, char * base
, nt_lf
* lf
, int level
);
798 * 0 value is a default value
799 * 1 the value has a name
802 * len of the whole data block
804 * bytes including the terminating \0 = 2*(number_of_chars+1)
805 * - reg_dword, reg_binary:
806 * if highest bit of data_len is set data_off contains the value
808 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
)
812 BYTE
* pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
814 if(vk
->id
!= NT_REG_VALUE_BLOCK_ID
) goto error
;
816 lstrcpynAtoW(name
, vk
->name
, vk
->nam_len
+1);
818 ret
= RegSetValueExW( hkey
, (vk
->flag
& 0x00000001) ? name
: NULL
, 0, vk
->type
,
819 (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
,
820 (vk
->data_len
& 0x7fffffff) );
821 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
824 ERR_(reg
)("vk block invalid\n");
831 * this structure contains the hash of a keyname and points to all
834 * exception: if the id is 'il' there are no hash values and every
837 static int _nt_parse_lf(HKEY hkey
, char * base
, nt_lf
* lf
, int level
)
841 if (lf
->id
== NT_REG_HASH_BLOCK_ID
)
843 for (i
=0; i
<lf
->nr_keys
; i
++)
845 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), level
)) goto error
;
849 else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
)
851 for (i
=0; i
<lf
->nr_keys
; i
++)
853 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+((nt_il
*)lf
)->off_nk
[i
]+4), level
)) goto error
;
858 error
: ERR_(reg
)("error reading lf block\n");
862 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
869 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
) goto error
;
870 if((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) &&
871 (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)) goto error
;
873 /* create the new key */
876 name
= _strdupnA( nk
->name
, nk
->name_len
+1);
877 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
881 /* loop through the subkeys */
884 nt_lf
* lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
885 if (nk
->nr_subkeys
!= lf
->nr_keys
) goto error1
;
886 if (!_nt_parse_lf(subkey
, base
, lf
, level
-1)) goto error1
;
889 /* loop trough the value list */
890 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
891 for (i
=0; i
<nk
->nr_values
; i
++)
893 nt_vk
* vk
= (nt_vk
*)(base
+vl
[i
]+4);
894 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
900 error1
: RegCloseKey(subkey
);
901 error
: ERR_(reg
)("error reading nk block\n");
907 /* windows 95 registry loader */
909 /* SECTION 1: main header
913 #define W95_REG_CREG_ID 0x47455243
917 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
918 DWORD version
; /* ???? 0x00010000 */
919 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
920 DWORD uk2
; /* 0x0c */
921 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
927 /* SECTION 2: Directory information (tree structure)
929 * once on offset 0x20
931 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
933 #define W95_REG_RGKN_ID 0x4e4b4752
937 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
938 DWORD size
; /* Size of the RGKN-block */
939 DWORD root_off
; /* Rel. Offset of the root-record */
943 /* Disk Key Entry Structure
945 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
946 * hive itself. It looks the same like other keys. Even the ID-number can
949 * The "hash"-value is a value representing the key's name. Windows will not
950 * search for the name, but for a matching hash-value. if it finds one, it
951 * will compare the actual string info, otherwise continue with the next key.
952 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
953 * of the string which are smaller than 0x80 (128) to this D-Word.
955 * If you want to modify key names, also modify the hash-values, since they
956 * cannot be found again (although they would be displayed in REGEDIT)
957 * End of list-pointers are filled with 0xFFFFFFFF
959 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
960 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
961 * structure) and reading another RGDB_section.
963 * there is a one to one relationship between dke and dkh
965 /* key struct, once per key */
968 DWORD x1
; /* Free entry indicator(?) */
969 DWORD hash
; /* sum of bytes of keyname */
970 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
971 DWORD prevlvl
; /* offset of previous key */
972 DWORD nextsub
; /* offset of child key */
973 DWORD next
; /* offset of sibling key */
974 WORD nrLS
; /* id inside the rgdb block */
975 WORD nrMS
; /* number of the rgdb block */
978 /* SECTION 3: key information, values and data
981 * section: [blocks]* (repeat creg->rgdb_num times)
982 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
983 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
985 * An interesting relationship exists in RGDB_section. The value at offset
986 * 10 equals the value at offset 4 minus the value at offset 8. I have no
987 * idea at the moment what this means. (Kevin Cozens)
990 /* block header, once per block */
991 #define W95_REG_RGDB_ID 0x42444752
995 DWORD id
; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
996 DWORD size
; /* 0x04 */
997 DWORD uk1
; /* 0x08 */
998 DWORD uk2
; /* 0x0c */
999 DWORD uk3
; /* 0x10 */
1000 DWORD uk4
; /* 0x14 */
1001 DWORD uk5
; /* 0x18 */
1002 DWORD uk6
; /* 0x1c */
1006 /* Disk Key Header structure (RGDB part), once per key */
1009 DWORD nextkeyoff
; /* 0x00 offset to next dkh*/
1010 WORD nrLS
; /* 0x04 id inside the rgdb block */
1011 WORD nrMS
; /* 0x06 number of the rgdb block */
1012 DWORD bytesused
; /* 0x08 */
1013 WORD keynamelen
; /* 0x0c len of name */
1014 WORD values
; /* 0x0e number of values */
1015 DWORD xx1
; /* 0x10 */
1016 char name
[1]; /* 0x14 */
1017 /* dkv */ /* 0x14 + keynamelen */
1020 /* Disk Key Value structure, once per value */
1023 DWORD type
; /* 0x00 */
1024 DWORD x1
; /* 0x04 */
1025 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
1026 WORD valdatalen
; /* 0x0A length of data */
1027 char name
[1]; /* 0x0c */
1028 /* raw data */ /* 0x0c + valnamelen */
1031 /******************************************************************************
1032 * _w95_lookup_dkh [Internal]
1034 * seeks the dkh belonging to a dke
1036 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
1042 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
); /* get the beginning of the rgdb datastore */
1043 assert (creg
->rgdb_num
> nrMS
); /* check: requested block < last_block) */
1045 /* find the right block */
1046 for(i
=0; i
<nrMS
;i
++)
1048 assert(rgdb
->id
== W95_REG_RGDB_ID
); /* check the magic */
1049 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
1052 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
1056 if(nrLS
==dkh
->nrLS
) return dkh
;
1057 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
1058 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
1063 /******************************************************************************
1064 * _w95_parse_dkv [Internal]
1066 static int _w95_parse_dkv (
1077 /* first value block */
1078 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
1080 /* loop trought the values */
1081 for (i
=0; i
< dkh
->values
; i
++)
1083 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
+1);
1084 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
1085 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
1089 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
1094 /******************************************************************************
1095 * _w95_parse_dke [Internal]
1097 static int _w95_parse_dke(
1105 HKEY hsubkey
= hkey
;
1109 /* get start address of root key block */
1110 if (!dke
) dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1112 /* special root key */
1113 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
1115 /* parse the one subkey*/
1116 if (dke
->nextsub
!= 0xffffffff)
1118 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
1120 /* has no sibling keys */
1124 /* search subblock */
1125 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
1127 fprintf(stderr
, "dke pointing to missing dkh !\n");
1133 /* walk sibling keys */
1134 if (dke
->next
!= 0xffffffff )
1136 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1139 /* create subkey and insert values */
1140 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
+1);
1141 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1143 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1147 if (dke
->nextsub
!= 0xffffffff)
1149 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1153 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1156 /* end windows 95 loader */
1158 /******************************************************************************
1159 * NativeRegLoadKey [Internal]
1161 * Loads a native registry file (win95/nt)
1164 * level number of levels to cut away (eg. ".Default" in user.dat)
1166 * this function intentionally uses unix file functions to make it possible
1167 * to move it to a seperate registry helper programm
1169 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1173 DOS_FULL_NAME full_name
;
1177 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1179 /* map the registry into the memory */
1180 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1181 if ((fstat(fd
, &st
) == -1)) goto error
;
1182 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1184 switch (*(LPDWORD
)base
)
1186 /* windows 95 'creg' */
1187 case W95_REG_CREG_ID
:
1192 TRACE_(reg
)("Loading win95 registry '%s' '%s'\n",fn
, full_name
.long_name
);
1194 /* load the header (rgkn) */
1195 rgkn
= (_w95rgkn
*)(creg
+ 1);
1196 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1198 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1202 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1206 case NT_REG_HEADER_BLOCK_ID
:
1210 nt_hbin_sub
* hbin_sub
;
1213 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
1219 hbin
= base
+ 0x1000;
1220 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1222 ERR_(reg
)( "%s hbin block invalid\n", fn
);
1226 /* hbin_sub block */
1227 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1228 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1230 ERR_(reg
)( "%s hbin_sub block invalid\n", fn
);
1235 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1236 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1238 ERR_(reg
)( "%s special nk block not found\n", fn
);
1242 ret
= _nt_parse_nk (hkey
, base
+0x1000, nk
, level
);
1247 ERR("unknown signature in registry file %s.\n",fn
);
1251 if(!ret
) ERR("error loading registry file %s\n", fn
);
1252 error1
: munmap(base
, st
.st_size
);
1257 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1259 reghack - windows 3.11 registry data format demo program.
1261 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1262 a combined hash table and tree description, and finally a text table.
1264 The header is obvious from the struct header. The taboff1 and taboff2
1265 fields are always 0x20, and their usage is unknown.
1267 The 8-byte entry table has various entry types.
1269 tabent[0] is a root index. The second word has the index of the root of
1271 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1272 the index of the key/value that has that hash. Data with the same
1273 hash value are on a circular list. The other three words in the
1274 hash entry are always zero.
1275 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1276 entry: dirent and keyent/valent. They are identified by context.
1277 tabent[freeidx] is the first free entry. The first word in a free entry
1278 is the index of the next free entry. The last has 0 as a link.
1279 The other three words in the free list are probably irrelevant.
1281 Entries in text table are preceeded by a word at offset-2. This word
1282 has the value (2*index)+1, where index is the referring keyent/valent
1283 entry in the table. I have no suggestion for the 2* and the +1.
1284 Following the word, there are N bytes of data, as per the keyent/valent
1285 entry length. The offset of the keyent/valent entry is from the start
1286 of the text table to the first data byte.
1288 This information is not available from Microsoft. The data format is
1289 deduced from the reg.dat file by me. Mistakes may
1290 have been made. I claim no rights and give no guarantees for this program.
1292 Tor Sjøwall, tor@sn.no
1295 /* reg.dat header format */
1296 struct _w31_header
{
1297 char cookie
[8]; /* 'SHCC3.10' */
1298 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1299 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1300 unsigned long tabcnt
; /* number of entries in index table */
1301 unsigned long textoff
; /* offset of text part */
1302 unsigned long textsize
; /* byte size of text part */
1303 unsigned short hashsize
; /* hash size */
1304 unsigned short freeidx
; /* free index */
1307 /* generic format of table entries */
1308 struct _w31_tabent
{
1309 unsigned short w0
, w1
, w2
, w3
;
1312 /* directory tabent: */
1313 struct _w31_dirent
{
1314 unsigned short sibling_idx
; /* table index of sibling dirent */
1315 unsigned short child_idx
; /* table index of child dirent */
1316 unsigned short key_idx
; /* table index of key keyent */
1317 unsigned short value_idx
; /* table index of value valent */
1321 struct _w31_keyent
{
1322 unsigned short hash_idx
; /* hash chain index for string */
1323 unsigned short refcnt
; /* reference count */
1324 unsigned short length
; /* length of string */
1325 unsigned short string_off
; /* offset of string in text table */
1329 struct _w31_valent
{
1330 unsigned short hash_idx
; /* hash chain index for string */
1331 unsigned short refcnt
; /* reference count */
1332 unsigned short length
; /* length of string */
1333 unsigned short string_off
; /* offset of string in text table */
1336 /* recursive helper function to display a directory tree */
1338 __w31_dumptree( unsigned short idx
,
1340 struct _w31_tabent
*tab
,
1341 struct _w31_header
*head
,
1343 time_t lastmodified
,
1346 struct _w31_dirent
*dir
;
1347 struct _w31_keyent
*key
;
1348 struct _w31_valent
*val
;
1350 static char tail
[400];
1353 dir
=(struct _w31_dirent
*)&tab
[idx
];
1356 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1358 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1359 tail
[key
->length
]='\0';
1360 /* all toplevel entries AND the entries in the
1361 * toplevel subdirectory belong to \SOFTWARE\Classes
1363 if (!level
&& !lstrcmpA(tail
,".classes")) {
1364 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1365 idx
=dir
->sibling_idx
;
1368 if (subkey
) RegCloseKey( subkey
);
1369 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1370 /* only add if leaf node or valued node */
1371 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1372 if (dir
->value_idx
) {
1373 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1374 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1375 tail
[val
->length
]='\0';
1376 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1380 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1382 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1383 idx
=dir
->sibling_idx
;
1385 if (subkey
) RegCloseKey( subkey
);
1389 /******************************************************************************
1390 * _w31_loadreg [Internal]
1392 void _w31_loadreg(void) {
1394 struct _w31_header head
;
1395 struct _w31_tabent
*tab
;
1399 BY_HANDLE_FILE_INFORMATION hfinfo
;
1400 time_t lastmodified
;
1404 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1405 if (hf
==HFILE_ERROR
)
1408 /* read & dump header */
1409 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1410 ERR("reg.dat is too short.\n");
1414 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1415 ERR("reg.dat has bad signature.\n");
1420 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1421 /* read and dump index table */
1423 if (len
!=_lread(hf
,tab
,len
)) {
1424 ERR("couldn't read %d bytes.\n",len
);
1431 txt
= xmalloc(head
.textsize
);
1432 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1433 ERR("couldn't seek to textblock.\n");
1439 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1440 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1447 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1448 ERR("GetFileInformationByHandle failed?.\n");
1454 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1455 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1462 /**********************************************************************************
1463 * SetLoadLevel [Internal]
1465 * set level to 0 for loading system files
1466 * set level to 1 for loading user files
1468 static void SetLoadLevel(int level
)
1470 struct set_registry_levels_request
*req
= get_req_buffer();
1472 req
->current
= level
;
1475 server_call( REQ_SET_REGISTRY_LEVELS
);
1478 /**********************************************************************************
1479 * SHELL_LoadRegistry [Internal]
1481 #define REG_DONTLOAD -1
1486 void SHELL_LoadRegistry( void )
1491 char windir
[MAX_PATHNAME_LEN
];
1492 char path
[MAX_PATHNAME_LEN
];
1493 int systemtype
= REG_WIN31
;
1497 if (!CLIENT_IsBootThread()) return; /* already loaded */
1502 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1504 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1506 /* test %windir%/system32/config/system --> winnt */
1507 strcpy(path
, windir
);
1508 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1509 if(GetFileAttributesA(path
) != -1)
1511 systemtype
= REG_WINNT
;
1515 /* test %windir%/system.dat --> win95 */
1516 strcpy(path
, windir
);
1517 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1518 if(GetFileAttributesA(path
) != -1)
1520 systemtype
= REG_WIN95
;
1524 if ((systemtype
==REG_WINNT
)
1525 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1527 MESSAGE("When you are running with a native NT directory specify\n");
1528 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1529 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1530 systemtype
= REG_DONTLOAD
;
1535 /* only wine registry */
1536 systemtype
= REG_DONTLOAD
;
1546 /* Load windows 95 entries */
1547 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1549 strcpy(path
, windir
);
1550 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1551 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1553 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1555 /* user specific user.dat */
1556 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1557 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1559 MESSAGE("can't load win95 user-registry %s\n", path
);
1560 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1562 /* default user.dat */
1563 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1565 strcpy(path
, windir
);
1566 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1567 NativeRegLoadKey(hkey
, path
, 1);
1573 /* global user.dat */
1574 strcpy(path
, windir
);
1575 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1576 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1581 /* default user.dat */
1582 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1584 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1585 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1587 MESSAGE("can't load NT user-registry %s\n", path
);
1588 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1592 /* default user.dat */
1593 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1595 strcpy(path
, windir
);
1596 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1597 NativeRegLoadKey(hkey
, path
, 1);
1603 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1606 strcpy(path
, windir
);
1607 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1608 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1610 strcpy(path
, windir
);
1611 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1612 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1614 strcpy(path
, windir
);
1615 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1616 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1618 strcpy(path
, windir
);
1619 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1620 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1622 /* this key is generated when the nt-core booted successfully */
1623 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1628 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1631 * Load the global HKU hive directly from sysconfdir
1633 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1636 * Load the global machine defaults directly form sysconfdir
1638 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1644 * Load the user saved registries
1646 if (!(home
= getenv( "HOME" )))
1647 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1648 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1651 * Load user's personal versions of global HKU/.Default keys
1653 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
) +
1654 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1656 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1657 _wine_loadreg( HKEY_USERS
, fn
);
1660 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) + strlen(SAVE_CURRENT_USER
)+2);
1662 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1663 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1667 * Load HKLM, attempt to get the registry location from the config
1668 * file first, if exist, load and keep going.
1670 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_MACHINE
)+2);
1672 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1673 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1678 * Load HKCU, get the registry location from the config
1679 * file, if exist, load and keep going.
1681 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1683 fn
= xmalloc( MAX_PATHNAME_LEN
);
1684 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1685 fn
, MAX_PATHNAME_LEN
- 1))
1687 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1691 * Load HKU, get the registry location from the config
1692 * file, if exist, load and keep going.
1694 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1695 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1696 fn
, MAX_PATHNAME_LEN
- 1))
1698 _wine_loadreg( HKEY_USERS
, fn
);
1702 * Load HKLM, get the registry location from the config
1703 * file, if exist, load and keep going.
1705 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1706 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1707 fn
, MAX_PATHNAME_LEN
- 1))
1709 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1715 * Make sure the update mode is there
1717 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
1719 DWORD junk
,type
,len
;
1723 if (( RegQueryValueExA(
1729 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
1731 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1737 if ((save_timeout
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1739 SERVICE_AddTimer( save_timeout
* 1000000, periodic_save
, 0 );
1744 /********************* API FUNCTIONS ***************************************/
1749 /******************************************************************************
1750 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1751 * Immediately writes key to registry.
1752 * Only returns after data has been written to disk.
1754 * FIXME: does it really wait until data is written ?
1757 * hkey [I] Handle of key to write
1760 * Success: ERROR_SUCCESS
1761 * Failure: Error code
1763 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1765 FIXME( "(%x): stub\n", hkey
);
1766 return ERROR_SUCCESS
;
1769 /******************************************************************************
1770 * RegConnectRegistry32W [ADVAPI32.128]
1773 * lpMachineName [I] Address of name of remote computer
1774 * hHey [I] Predefined registry handle
1775 * phkResult [I] Address of buffer for remote registry handle
1777 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1780 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1782 if (!lpMachineName
|| !*lpMachineName
) {
1783 /* Use the local machine name */
1784 return RegOpenKey16( hKey
, "", phkResult
);
1787 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1788 return ERROR_BAD_NETPATH
;
1792 /******************************************************************************
1793 * RegConnectRegistry32A [ADVAPI32.127]
1795 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1798 LPWSTR machineW
= strdupA2W(machine
);
1799 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1805 /******************************************************************************
1806 * RegGetKeySecurity [ADVAPI32.144]
1807 * Retrieves a copy of security descriptor protecting the registry key
1810 * hkey [I] Open handle of key to set
1811 * SecurityInformation [I] Descriptor contents
1812 * pSecurityDescriptor [O] Address of descriptor for key
1813 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1816 * Success: ERROR_SUCCESS
1817 * Failure: Error code
1819 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1820 SECURITY_INFORMATION SecurityInformation
,
1821 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1822 LPDWORD lpcbSecurityDescriptor
)
1824 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1825 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1827 /* FIXME: Check for valid SecurityInformation values */
1829 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1830 return ERROR_INSUFFICIENT_BUFFER
;
1832 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1833 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1835 return ERROR_SUCCESS
;
1839 /******************************************************************************
1840 * RegNotifyChangeKeyValue [ADVAPI32.???]
1843 * hkey [I] Handle of key to watch
1844 * fWatchSubTree [I] Flag for subkey notification
1845 * fdwNotifyFilter [I] Changes to be reported
1846 * hEvent [I] Handle of signaled event
1847 * fAsync [I] Flag for asynchronous reporting
1849 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1850 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1853 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1855 return ERROR_SUCCESS
;
1859 /******************************************************************************
1860 * RegUnLoadKey32W [ADVAPI32.173]
1863 * hkey [I] Handle of open key
1864 * lpSubKey [I] Address of name of subkey to unload
1866 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1868 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1869 return ERROR_SUCCESS
;
1873 /******************************************************************************
1874 * RegUnLoadKey32A [ADVAPI32.172]
1876 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1879 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1880 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1881 if(lpSubKeyW
) free(lpSubKeyW
);
1886 /******************************************************************************
1887 * RegSetKeySecurity [ADVAPI32.167]
1890 * hkey [I] Open handle of key to set
1891 * SecurityInfo [I] Descriptor contents
1892 * pSecurityDesc [I] Address of descriptor for key
1894 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1895 PSECURITY_DESCRIPTOR pSecurityDesc
)
1897 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1899 /* It seems to perform this check before the hkey check */
1900 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1901 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1902 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1903 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1906 return ERROR_INVALID_PARAMETER
;
1909 return ERROR_INVALID_PARAMETER
;
1911 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1913 return ERROR_SUCCESS
;
1917 /******************************************************************************
1918 * RegRestoreKey32W [ADVAPI32.164]
1921 * hkey [I] Handle of key where restore begins
1922 * lpFile [I] Address of filename containing saved tree
1923 * dwFlags [I] Optional flags
1925 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1927 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1929 /* It seems to do this check before the hkey check */
1930 if (!lpFile
|| !*lpFile
)
1931 return ERROR_INVALID_PARAMETER
;
1933 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1935 /* Check for file existence */
1937 return ERROR_SUCCESS
;
1941 /******************************************************************************
1942 * RegRestoreKey32A [ADVAPI32.163]
1944 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1947 LPWSTR lpFileW
= strdupA2W(lpFile
);
1948 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1949 if(lpFileW
) free(lpFileW
);
1954 /******************************************************************************
1955 * RegReplaceKey32W [ADVAPI32.162]
1958 * hkey [I] Handle of open key
1959 * lpSubKey [I] Address of name of subkey
1960 * lpNewFile [I] Address of filename for file with new data
1961 * lpOldFile [I] Address of filename for backup file
1963 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1966 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1967 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1968 return ERROR_SUCCESS
;
1972 /******************************************************************************
1973 * RegReplaceKey32A [ADVAPI32.161]
1975 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1979 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1980 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1981 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1982 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1994 /* 16-bit functions */
1996 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1997 * some programs. Do not remove those cases. -MM
1999 static inline void fix_win16_hkey( HKEY
*hkey
)
2001 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
2004 /******************************************************************************
2005 * RegEnumKey16 [KERNEL.216] [SHELL.7]
2007 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
2009 fix_win16_hkey( &hkey
);
2010 return RegEnumKeyA( hkey
, index
, name
, name_len
);
2013 /******************************************************************************
2014 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2016 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
2018 fix_win16_hkey( &hkey
);
2019 return RegOpenKeyA( hkey
, name
, retkey
);
2022 /******************************************************************************
2023 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2025 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
2027 fix_win16_hkey( &hkey
);
2028 return RegCreateKeyA( hkey
, name
, retkey
);
2031 /******************************************************************************
2032 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2034 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
2036 fix_win16_hkey( &hkey
);
2037 return RegDeleteKeyA( hkey
, name
);
2040 /******************************************************************************
2041 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2043 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
2045 fix_win16_hkey( &hkey
);
2046 return RegCloseKey( hkey
);
2049 /******************************************************************************
2050 * RegSetValue16 [KERNEL.221] [SHELL.5]
2052 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
2054 fix_win16_hkey( &hkey
);
2055 return RegSetValueA( hkey
, name
, type
, data
, count
);
2058 /******************************************************************************
2059 * RegDeleteValue16 [KERNEL.222]
2061 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
2063 fix_win16_hkey( &hkey
);
2064 return RegDeleteValueA( hkey
, name
);
2067 /******************************************************************************
2068 * RegEnumValue16 [KERNEL.223]
2070 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
2071 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
2073 fix_win16_hkey( &hkey
);
2074 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
2077 /******************************************************************************
2078 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2081 * Is this HACK still applicable?
2084 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2085 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2088 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
2090 fix_win16_hkey( &hkey
);
2091 if (count
) *count
&= 0xffff;
2092 return RegQueryValueA( hkey
, name
, data
, count
);
2095 /******************************************************************************
2096 * RegQueryValueEx16 [KERNEL.225]
2098 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
2099 LPBYTE data
, LPDWORD count
)
2101 fix_win16_hkey( &hkey
);
2102 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
2105 /******************************************************************************
2106 * RegSetValueEx16 [KERNEL.226]
2108 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
2109 CONST BYTE
*data
, DWORD count
)
2111 fix_win16_hkey( &hkey
);
2112 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);