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*
30 #ifdef HAVE_SYS_ERRNO_H
31 #include <sys/errno.h>
33 #include <sys/types.h>
35 #include <sys/fcntl.h>
41 #include "wine/winbase16.h"
42 #include "wine/winestring.h"
46 #include "debugtools.h"
53 DEFAULT_DEBUG_CHANNEL(reg);
55 static void REGISTRY_Init(void);
56 /* FIXME: following defines should be configured global ... */
58 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
59 #define WINE_PREFIX "/.wine"
60 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
61 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
63 /* relative in ~user/.wine/ : */
64 #define SAVE_CURRENT_USER "user.reg"
65 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
66 #define SAVE_LOCAL_MACHINE "system.reg"
68 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
69 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
72 /* what valuetypes do we need to convert? */
73 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
79 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
80 * If so, can we remove them?
82 * No, the memory handling functions are called very often in here,
83 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
84 * loading 100 times slower. -MM
86 static LPWSTR strdupA2W(LPCSTR src)
89 LPWSTR dest=xmalloc(2*strlen(src)+2);
90 lstrcpyAtoW(dest,src);
96 LPWSTR strcvtA2W(LPCSTR src, int nchars)
99 LPWSTR dest = xmalloc (2 * nchars + 2);
101 lstrcpynAtoW(dest,src,nchars+1);
107 /******************************************************************************
108 * REGISTRY_Init [Internal]
109 * Registry initialisation, allocates some default keys.
111 static void REGISTRY_Init(void) {
117 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
120 /* This was an Open, but since it is called before the real registries
121 are loaded, it was changed to a Create - MTB 980507*/
122 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
123 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
126 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
130 * string RegisteredOwner
131 * string RegisteredOrganization
134 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
139 if (-1!=gethostname(buf,200)) {
140 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
141 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
147 /************************ SAVE Registry Function ****************************/
149 #define REGISTRY_SAVE_VERSION 0x00000001
151 /* Registry saveformat:
152 * If you change it, increase above number by 1, which will flush
153 * old registry database files.
156 * "WINE REGISTRY Version %d"
160 * valuename=lastmodified,type,data
164 * keyname,valuename,stringdata:
165 * the usual ascii characters from 0x00-0xff (well, not 0x00)
166 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
167 * ( "=\\\t" escaped in \uXXXX form.)
171 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
173 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
174 * SaveOnlyUpdatedKeys=yes
177 /* Same as RegSaveKey but with Unix pathnames */
178 static void save_key( HKEY hkey, const char *filename )
180 struct save_registry_request *req = get_req_buffer();
185 char *name = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + 20 );
188 strcpy( name, filename );
189 if ((p = strrchr( name, '/' ))) p++;
194 sprintf( p, "reg%04x.tmp", count++ );
195 handle = FILE_CreateFile( name, GENERIC_WRITE, 0, NULL,
196 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, -1 );
197 if (handle != INVALID_HANDLE_VALUE) break;
198 if ((ret = GetLastError()) != ERROR_FILE_EXISTS) break;
201 if (handle != INVALID_HANDLE_VALUE)
205 ret = server_call_noerr( REQ_SAVE_REGISTRY );
206 CloseHandle( handle );
207 if (ret) unlink( name );
208 else if (rename( name, filename ) == -1)
210 ERR( "Failed to move %s to %s: ", name, filename );
215 HeapFree( GetProcessHeap(), 0, name );
219 /******************************************************************************
220 * SHELL_SaveRegistryBranch [Internal]
222 * Saves main registry branch specified by hkey.
224 static void SHELL_SaveRegistryBranch(HKEY hkey)
228 /* Find out what to save to, get from config file */
229 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
230 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
232 /* FIXME: does this check apply to all keys written below ? */
233 if (!(home = getenv( "HOME" )))
234 ERR("Failed to get homedirectory of UID %ld.\n",(long) getuid());
236 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
237 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
241 case HKEY_CURRENT_USER:
242 fn = xmalloc( MAX_PATHNAME_LEN );
243 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
244 fn, MAX_PATHNAME_LEN - 1))
245 save_key( HKEY_CURRENT_USER, fn );
248 if (home && writeToHome)
250 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
251 strlen(SAVE_CURRENT_USER) + 2 );
253 strcat(fn,WINE_PREFIX);
255 /* create the directory. don't care about errorcodes. */
256 mkdir(fn,0755); /* drwxr-xr-x */
257 strcat(fn,"/"SAVE_CURRENT_USER);
258 save_key( HKEY_CURRENT_USER, fn );
262 case HKEY_LOCAL_MACHINE:
263 /* Try first saving according to the defined location in .winerc */
264 fn = xmalloc ( MAX_PATHNAME_LEN);
265 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
266 fn, MAX_PATHNAME_LEN - 1))
267 save_key( HKEY_LOCAL_MACHINE, fn );
270 if (home && writeToHome)
272 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
273 strlen(SAVE_LOCAL_MACHINE) + 2);
275 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
276 save_key( HKEY_LOCAL_MACHINE, fn );
281 fn = xmalloc( MAX_PATHNAME_LEN );
282 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
283 fn, MAX_PATHNAME_LEN - 1))
284 save_key( HKEY_USERS, fn );
287 if (home && writeToHome)
289 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
290 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
292 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
293 save_key( HKEY_USERS, fn );
298 ERR("unknown/invalid key handle !\n");
304 /******************************************************************************
305 * SHELL_SaveRegistry [Internal]
307 void SHELL_SaveRegistry( void )
309 struct set_registry_levels_request *req = get_req_buffer();
317 if (RegOpenKeyA(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
326 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
331 &len)) || (type!=REG_SZ))
338 if (lstrcmpiA(buf,"yes")) all = 1;
340 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
343 req->version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
344 server_call( REQ_SET_REGISTRY_LEVELS );
346 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER);
347 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE);
348 SHELL_SaveRegistryBranch(HKEY_USERS);
351 /* Periodic save callback */
352 static void CALLBACK periodic_save( ULONG_PTR dummy )
354 SHELL_SaveRegistry();
357 /************************ LOAD Registry Function ****************************/
361 /******************************************************************************
362 * _find_or_add_key [Internal]
364 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
367 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
368 if (keyname) free( keyname );
372 /******************************************************************************
373 * _find_or_add_value [Internal]
375 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
377 RegSetValueExW( hkey, name, 0, type, data, len );
378 if (name) free( name );
379 if (data) free( data );
383 /******************************************************************************
384 * _wine_read_line [Internal]
386 * reads a line including dynamically enlarging the readbuffer and throwing
389 static int _wine_read_line( FILE *F, char **buf, int *len )
399 s=fgets(curread,mylen,F);
402 if (NULL==(s=strchr(curread,'\n'))) {
403 /* buffer wasn't large enough */
404 curoff = strlen(*buf);
405 *buf = xrealloc(*buf,*len*2);
406 curread = *buf + curoff;
407 mylen = *len; /* we filled up the buffer and
408 * got new '*len' bytes to fill
416 /* throw away comments */
417 if (**buf=='#' || **buf==';') {
422 if (s) /* got end of line */
429 /******************************************************************************
430 * _wine_read_USTRING [Internal]
432 * converts a char* into a UNICODE string (up to a special char)
433 * and returns the position exactly after that string
435 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
440 /* read up to "=" or "\0" or "\n" */
442 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
444 while (*s && (*s!='\n') && (*s!='=')) {
446 *ws++=*((unsigned char*)s++);
450 /* Dangling \ ... may only happen if a registry
451 * write was short. FIXME: What do to?
461 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
469 memcpy(xbuf,s,4);xbuf[4]='\0';
470 if (!sscanf(xbuf,"%x",&wc))
471 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
473 *ws++ =(unsigned short)wc;
482 /******************************************************************************
483 * _wine_loadsubkey [Internal]
486 * It seems like this is returning a boolean. Should it?
492 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
499 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
501 /* Good. We already got a line here ... so parse it */
511 WARN("Got a subhierarchy without resp. key?\n");
514 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
515 if (!_wine_read_line(F,buf,buflen))
520 /* let the caller handle this line */
521 if (i<level || **buf=='\0')
524 /* it can be: a value or a keyname. Parse the name first */
525 s=_wine_read_USTRING(s,&name);
527 /* switch() default: hack to avoid gotos */
531 if (subkey) RegCloseKey( subkey );
532 subkey=_find_or_add_key(hkey,name);
535 int len,lastmodified,type;
538 WARN("Unexpected character: %c\n",*s);
542 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
543 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
550 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
553 if (type == REG_SZ || type == REG_EXPAND_SZ) {
554 s=_wine_read_USTRING(s,(LPWSTR*)&data);
555 len = lstrlenW((LPWSTR)data)*2+2;
558 data = (LPBYTE)xmalloc(len+1);
559 for (i=0;i<len;i++) {
561 if (*s>='0' && *s<='9')
563 if (*s>='a' && *s<='f')
564 data[i]=(*s-'a'+'\xa')<<4;
565 if (*s>='A' && *s<='F')
566 data[i]=(*s-'A'+'\xa')<<4;
568 if (*s>='0' && *s<='9')
570 if (*s>='a' && *s<='f')
571 data[i]|=*s-'a'+'\xa';
572 if (*s>='A' && *s<='F')
573 data[i]|=*s-'A'+'\xa';
577 _find_or_add_value(hkey,name,type,data,len);
580 /* read the next line */
581 if (!_wine_read_line(F,buf,buflen))
585 if (subkey) RegCloseKey( subkey );
590 /******************************************************************************
591 * _wine_loadsubreg [Internal]
593 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
599 buf=xmalloc(10);buflen=10;
600 if (!_wine_read_line(F,&buf,&buflen)) {
604 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
608 if (ver!=REGISTRY_SAVE_VERSION) {
609 if (ver == 2) /* new version */
612 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
613 FILE_ATTRIBUTE_NORMAL, -1 )) != INVALID_HANDLE_VALUE)
615 struct load_registry_request *req = get_req_buffer();
619 server_call( REQ_LOAD_REGISTRY );
627 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
632 if (!_wine_read_line(F,&buf,&buflen)) {
636 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
645 /******************************************************************************
646 * _wine_loadreg [Internal]
648 static void _wine_loadreg( HKEY hkey, char *fn )
652 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
656 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
659 _wine_loadsubreg(F,hkey,fn);
663 /* NT REGISTRY LOADER */
665 #ifdef HAVE_SYS_MMAN_H
666 # include <sys/mman.h>
670 #define MAP_FAILED ((LPVOID)-1)
673 #define NT_REG_BLOCK_SIZE 0x1000
675 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
676 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
677 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
678 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
680 /* subblocks of nk */
681 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
682 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
683 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
685 #define NT_REG_KEY_BLOCK_TYPE 0x20
686 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
690 DWORD id; /* 0x66676572 'regf'*/
691 DWORD uk1; /* 0x04 */
692 DWORD uk2; /* 0x08 */
693 FILETIME DateModified; /* 0x0c */
694 DWORD uk3; /* 0x14 */
695 DWORD uk4; /* 0x18 */
696 DWORD uk5; /* 0x1c */
697 DWORD uk6; /* 0x20 */
698 DWORD RootKeyBlock; /* 0x24 */
699 DWORD BlockSize; /* 0x28 */
701 DWORD Checksum; /* at offset 0x1FC */
712 DWORD id; /* 0x6E696268 'hbin' */
716 DWORD uk2; /* 0x10 */
717 DWORD uk3; /* 0x14 */
718 DWORD uk4; /* 0x18 */
719 DWORD size; /* 0x1C */
720 nt_hbin_sub hbin_sub; /* 0x20 */
724 * the value_list consists of offsets to the values (vk)
728 WORD SubBlockId; /* 0x00 0x6B6E */
729 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
730 FILETIME writetime; /* 0x04 */
731 DWORD uk1; /* 0x0C */
732 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
733 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
734 DWORD uk8; /* 0x18 */
735 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
736 DWORD uk2; /* 0x20 */
737 DWORD nr_values; /* 0x24 number of values */
738 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
739 DWORD off_sk; /* 0x2c Offset of the sk-Record */
740 DWORD off_class; /* 0x30 Offset of the Class-Name */
741 DWORD uk3; /* 0x34 */
742 DWORD uk4; /* 0x38 */
743 DWORD uk5; /* 0x3c */
744 DWORD uk6; /* 0x40 */
745 DWORD uk7; /* 0x44 */
746 WORD name_len; /* 0x48 name-length */
747 WORD class_len; /* 0x4a class-name length */
748 char name[1]; /* 0x4c key-name */
753 DWORD off_nk; /* 0x00 */
754 DWORD name; /* 0x04 */
759 WORD id; /* 0x00 0x666c */
760 WORD nr_keys; /* 0x06 */
761 hash_rec hash_rec[1];
765 list of subkeys without hash
773 WORD id; /* 0x00 0x696c */
779 this is a intermediate node
791 WORD id; /* 0x00 0x6972 */
792 WORD nr_li; /* 0x02 number off offsets */
793 DWORD off_li[1]; /* 0x04 points to li */
798 WORD id; /* 0x00 'vk' */
808 LPSTR _strdupnA( LPCSTR str, int len )
812 if (!str) return NULL;
813 ret = malloc( len + 1 );
814 lstrcpynA( ret, str, len );
819 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
820 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
821 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
828 * 0 value is a default value
829 * 1 the value has a name
832 * len of the whole data block
834 * bytes including the terminating \0 = 2*(number_of_chars+1)
835 * - reg_dword, reg_binary:
836 * if highest bit of data_len is set data_off contains the value
838 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
842 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
844 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
846 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
848 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
849 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
850 (vk->data_len & 0x7fffffff) );
851 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
854 ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
861 * this structure contains the hash of a keyname and points to all
864 * exception: if the id is 'il' there are no hash values and every
867 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
871 if (lf->id == NT_REG_HASH_BLOCK_ID)
873 if (subkeys != lf->nr_keys) goto error1;
875 for (i=0; i<lf->nr_keys; i++)
877 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
880 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
882 nt_li * li = (nt_li*)lf;
883 if (subkeys != li->nr_keys) goto error1;
885 for (i=0; i<li->nr_keys; i++)
887 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
890 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
892 nt_ri * ri = (nt_ri*)lf;
895 /* count all subkeys */
896 for (i=0; i<ri->nr_li; i++)
898 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
899 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
900 li_subkeys += li->nr_keys;
904 if (subkeys != li_subkeys) goto error1;
906 /* loop through the keys */
907 for (i=0; i<ri->nr_li; i++)
909 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
910 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
919 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
922 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
925 error: ERR_(reg)("error reading lf block\n");
929 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
936 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
938 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
942 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
943 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
945 ERR_(reg)("registry file corrupt!\n");
949 /* create the new key */
952 name = _strdupnA( nk->name, nk->name_len+1);
953 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
957 /* loop through the subkeys */
960 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
961 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
964 /* loop trough the value list */
965 vl = (DWORD *)(base+nk->valuelist_off+4);
966 for (i=0; i<nk->nr_values; i++)
968 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
969 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
975 error1: RegCloseKey(subkey);
981 /* windows 95 registry loader */
983 /* SECTION 1: main header
987 #define W95_REG_CREG_ID 0x47455243
991 DWORD id; /* "CREG" = W95_REG_CREG_ID */
992 DWORD version; /* ???? 0x00010000 */
993 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
994 DWORD uk2; /* 0x0c */
995 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
1001 /* SECTION 2: Directory information (tree structure)
1003 * once on offset 0x20
1005 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
1007 #define W95_REG_RGKN_ID 0x4e4b4752
1011 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
1012 DWORD size; /* Size of the RGKN-block */
1013 DWORD root_off; /* Rel. Offset of the root-record */
1017 /* Disk Key Entry Structure
1019 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
1020 * hive itself. It looks the same like other keys. Even the ID-number can
1023 * The "hash"-value is a value representing the key's name. Windows will not
1024 * search for the name, but for a matching hash-value. if it finds one, it
1025 * will compare the actual string info, otherwise continue with the next key.
1026 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
1027 * of the string which are smaller than 0x80 (128) to this D-Word.
1029 * If you want to modify key names, also modify the hash-values, since they
1030 * cannot be found again (although they would be displayed in REGEDIT)
1031 * End of list-pointers are filled with 0xFFFFFFFF
1033 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1034 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1035 * structure) and reading another RGDB_section.
1037 * there is a one to one relationship between dke and dkh
1039 /* key struct, once per key */
1042 DWORD x1; /* Free entry indicator(?) */
1043 DWORD hash; /* sum of bytes of keyname */
1044 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
1045 DWORD prevlvl; /* offset of previous key */
1046 DWORD nextsub; /* offset of child key */
1047 DWORD next; /* offset of sibling key */
1048 WORD nrLS; /* id inside the rgdb block */
1049 WORD nrMS; /* number of the rgdb block */
1052 /* SECTION 3: key information, values and data
1055 * section: [blocks]* (repeat creg->rgdb_num times)
1056 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
1057 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
1059 * An interesting relationship exists in RGDB_section. The value at offset
1060 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1061 * idea at the moment what this means. (Kevin Cozens)
1064 /* block header, once per block */
1065 #define W95_REG_RGDB_ID 0x42444752
1069 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
1070 DWORD size; /* 0x04 */
1071 DWORD uk1; /* 0x08 */
1072 DWORD uk2; /* 0x0c */
1073 DWORD uk3; /* 0x10 */
1074 DWORD uk4; /* 0x14 */
1075 DWORD uk5; /* 0x18 */
1076 DWORD uk6; /* 0x1c */
1080 /* Disk Key Header structure (RGDB part), once per key */
1083 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
1084 WORD nrLS; /* 0x04 id inside the rgdb block */
1085 WORD nrMS; /* 0x06 number of the rgdb block */
1086 DWORD bytesused; /* 0x08 */
1087 WORD keynamelen; /* 0x0c len of name */
1088 WORD values; /* 0x0e number of values */
1089 DWORD xx1; /* 0x10 */
1090 char name[1]; /* 0x14 */
1091 /* dkv */ /* 0x14 + keynamelen */
1094 /* Disk Key Value structure, once per value */
1097 DWORD type; /* 0x00 */
1098 DWORD x1; /* 0x04 */
1099 WORD valnamelen; /* 0x08 length of name, 0 is default key */
1100 WORD valdatalen; /* 0x0A length of data */
1101 char name[1]; /* 0x0c */
1102 /* raw data */ /* 0x0c + valnamelen */
1105 /******************************************************************************
1106 * _w95_lookup_dkh [Internal]
1108 * seeks the dkh belonging to a dke
1110 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1116 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
1117 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
1119 /* find the right block */
1120 for(i=0; i<nrMS ;i++)
1122 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
1123 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
1126 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
1130 if(nrLS==dkh->nrLS ) return dkh;
1131 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
1132 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1137 /******************************************************************************
1138 * _w95_parse_dkv [Internal]
1140 static int _w95_parse_dkv (
1151 /* first value block */
1152 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1154 /* loop trought the values */
1155 for (i=0; i< dkh->values; i++)
1157 name = _strdupnA(dkv->name, dkv->valnamelen+1);
1158 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
1159 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1163 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1168 /******************************************************************************
1169 * _w95_parse_dke [Internal]
1171 static int _w95_parse_dke(
1179 HKEY hsubkey = hkey;
1183 /* get start address of root key block */
1184 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1186 /* special root key */
1187 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
1189 /* parse the one subkey*/
1190 if (dke->nextsub != 0xffffffff)
1192 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1194 /* has no sibling keys */
1198 /* search subblock */
1199 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1201 fprintf(stderr, "dke pointing to missing dkh !\n");
1207 /* walk sibling keys */
1208 if (dke->next != 0xffffffff )
1210 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1213 /* create subkey and insert values */
1214 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1215 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1217 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1221 if (dke->nextsub != 0xffffffff)
1223 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1227 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1230 /* end windows 95 loader */
1232 /******************************************************************************
1233 * NativeRegLoadKey [Internal]
1235 * Loads a native registry file (win95/nt)
1238 * level number of levels to cut away (eg. ".Default" in user.dat)
1240 * this function intentionally uses unix file functions to make it possible
1241 * to move it to a seperate registry helper programm
1243 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1247 DOS_FULL_NAME full_name;
1251 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1253 /* map the registry into the memory */
1254 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1255 if ((fstat(fd, &st) == -1)) goto error;
1256 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1258 switch (*(LPDWORD)base)
1260 /* windows 95 'creg' */
1261 case W95_REG_CREG_ID:
1266 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1268 /* load the header (rgkn) */
1269 rgkn = (_w95rgkn*)(creg + 1);
1270 if (rgkn->id != W95_REG_RGKN_ID)
1272 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1276 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1280 case NT_REG_HEADER_BLOCK_ID:
1284 nt_hbin_sub * hbin_sub;
1287 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1293 hbin = base + 0x1000;
1294 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1296 ERR_(reg)( "%s hbin block invalid\n", fn);
1300 /* hbin_sub block */
1301 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1302 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1304 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1309 nk = (nt_nk*)&(hbin_sub->data[0]);
1310 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1312 ERR_(reg)( "%s special nk block not found\n", fn);
1316 ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
1321 ERR("unknown signature in registry file %s.\n",fn);
1325 if(!ret) ERR("error loading registry file %s\n", fn);
1326 error1: munmap(base, st.st_size);
1331 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1333 reghack - windows 3.11 registry data format demo program.
1335 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1336 a combined hash table and tree description, and finally a text table.
1338 The header is obvious from the struct header. The taboff1 and taboff2
1339 fields are always 0x20, and their usage is unknown.
1341 The 8-byte entry table has various entry types.
1343 tabent[0] is a root index. The second word has the index of the root of
1345 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1346 the index of the key/value that has that hash. Data with the same
1347 hash value are on a circular list. The other three words in the
1348 hash entry are always zero.
1349 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1350 entry: dirent and keyent/valent. They are identified by context.
1351 tabent[freeidx] is the first free entry. The first word in a free entry
1352 is the index of the next free entry. The last has 0 as a link.
1353 The other three words in the free list are probably irrelevant.
1355 Entries in text table are preceeded by a word at offset-2. This word
1356 has the value (2*index)+1, where index is the referring keyent/valent
1357 entry in the table. I have no suggestion for the 2* and the +1.
1358 Following the word, there are N bytes of data, as per the keyent/valent
1359 entry length. The offset of the keyent/valent entry is from the start
1360 of the text table to the first data byte.
1362 This information is not available from Microsoft. The data format is
1363 deduced from the reg.dat file by me. Mistakes may
1364 have been made. I claim no rights and give no guarantees for this program.
1366 Tor Sjøwall, tor@sn.no
1369 /* reg.dat header format */
1370 struct _w31_header {
1371 char cookie[8]; /* 'SHCC3.10' */
1372 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1373 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1374 unsigned long tabcnt; /* number of entries in index table */
1375 unsigned long textoff; /* offset of text part */
1376 unsigned long textsize; /* byte size of text part */
1377 unsigned short hashsize; /* hash size */
1378 unsigned short freeidx; /* free index */
1381 /* generic format of table entries */
1382 struct _w31_tabent {
1383 unsigned short w0, w1, w2, w3;
1386 /* directory tabent: */
1387 struct _w31_dirent {
1388 unsigned short sibling_idx; /* table index of sibling dirent */
1389 unsigned short child_idx; /* table index of child dirent */
1390 unsigned short key_idx; /* table index of key keyent */
1391 unsigned short value_idx; /* table index of value valent */
1395 struct _w31_keyent {
1396 unsigned short hash_idx; /* hash chain index for string */
1397 unsigned short refcnt; /* reference count */
1398 unsigned short length; /* length of string */
1399 unsigned short string_off; /* offset of string in text table */
1403 struct _w31_valent {
1404 unsigned short hash_idx; /* hash chain index for string */
1405 unsigned short refcnt; /* reference count */
1406 unsigned short length; /* length of string */
1407 unsigned short string_off; /* offset of string in text table */
1410 /* recursive helper function to display a directory tree */
1412 __w31_dumptree( unsigned short idx,
1414 struct _w31_tabent *tab,
1415 struct _w31_header *head,
1417 time_t lastmodified,
1420 struct _w31_dirent *dir;
1421 struct _w31_keyent *key;
1422 struct _w31_valent *val;
1424 static char tail[400];
1427 dir=(struct _w31_dirent*)&tab[idx];
1430 key = (struct _w31_keyent*)&tab[dir->key_idx];
1432 memcpy(tail,&txt[key->string_off],key->length);
1433 tail[key->length]='\0';
1434 /* all toplevel entries AND the entries in the
1435 * toplevel subdirectory belong to \SOFTWARE\Classes
1437 if (!level && !lstrcmpA(tail,".classes")) {
1438 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1439 idx=dir->sibling_idx;
1442 if (subkey) RegCloseKey( subkey );
1443 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1444 /* only add if leaf node or valued node */
1445 if (dir->value_idx!=0||dir->child_idx==0) {
1446 if (dir->value_idx) {
1447 val=(struct _w31_valent*)&tab[dir->value_idx];
1448 memcpy(tail,&txt[val->string_off],val->length);
1449 tail[val->length]='\0';
1450 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1454 TRACE("strange: no directory key name, idx=%04x\n", idx);
1456 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1457 idx=dir->sibling_idx;
1459 if (subkey) RegCloseKey( subkey );
1463 /******************************************************************************
1464 * _w31_loadreg [Internal]
1466 void _w31_loadreg(void) {
1468 struct _w31_header head;
1469 struct _w31_tabent *tab;
1473 BY_HANDLE_FILE_INFORMATION hfinfo;
1474 time_t lastmodified;
1478 hf = OpenFile("reg.dat",&ofs,OF_READ);
1479 if (hf==HFILE_ERROR)
1482 /* read & dump header */
1483 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1484 ERR("reg.dat is too short.\n");
1488 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1489 ERR("reg.dat has bad signature.\n");
1494 len = head.tabcnt * sizeof(struct _w31_tabent);
1495 /* read and dump index table */
1497 if (len!=_lread(hf,tab,len)) {
1498 ERR("couldn't read %d bytes.\n",len);
1505 txt = xmalloc(head.textsize);
1506 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1507 ERR("couldn't seek to textblock.\n");
1513 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1514 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1521 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1522 ERR("GetFileInformationByHandle failed?.\n");
1528 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1529 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1536 /**********************************************************************************
1537 * SetLoadLevel [Internal]
1539 * set level to 0 for loading system files
1540 * set level to 1 for loading user files
1542 static void SetLoadLevel(int level)
1544 struct set_registry_levels_request *req = get_req_buffer();
1546 req->current = level;
1549 server_call( REQ_SET_REGISTRY_LEVELS );
1552 /**********************************************************************************
1553 * SHELL_LoadRegistry [Internal]
1555 #define REG_DONTLOAD -1
1560 void SHELL_LoadRegistry( void )
1565 char windir[MAX_PATHNAME_LEN];
1566 char path[MAX_PATHNAME_LEN];
1567 int systemtype = REG_WIN31;
1571 if (!CLIENT_IsBootThread()) return; /* already loaded */
1576 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1578 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1580 /* test %windir%/system32/config/system --> winnt */
1581 strcpy(path, windir);
1582 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1583 if(GetFileAttributesA(path) != -1)
1585 systemtype = REG_WINNT;
1589 /* test %windir%/system.dat --> win95 */
1590 strcpy(path, windir);
1591 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1592 if(GetFileAttributesA(path) != -1)
1594 systemtype = REG_WIN95;
1598 if ((systemtype==REG_WINNT)
1599 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1601 MESSAGE("When you are running with a native NT directory specify\n");
1602 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1603 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1604 systemtype = REG_DONTLOAD;
1609 /* only wine registry */
1610 systemtype = REG_DONTLOAD;
1620 /* Load windows 95 entries */
1621 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1623 strcpy(path, windir);
1624 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1625 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1627 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1629 /* user specific user.dat */
1630 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1631 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1633 MESSAGE("can't load win95 user-registry %s\n", path);
1634 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1636 /* default user.dat */
1637 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1639 strcpy(path, windir);
1640 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1641 NativeRegLoadKey(hkey, path, 1);
1647 /* global user.dat */
1648 strcpy(path, windir);
1649 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1650 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1655 /* default user.dat */
1656 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1658 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1659 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1661 MESSAGE("can't load NT user-registry %s\n", path);
1662 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1666 /* default user.dat */
1667 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1669 strcpy(path, windir);
1670 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1671 NativeRegLoadKey(hkey, path, 1);
1677 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1680 strcpy(path, windir);
1681 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1682 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1684 strcpy(path, windir);
1685 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1686 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1688 strcpy(path, windir);
1689 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1690 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1692 strcpy(path, windir);
1693 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1694 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1696 /* this key is generated when the nt-core booted successfully */
1697 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1702 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1705 * Load the global HKU hive directly from sysconfdir
1707 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1710 * Load the global machine defaults directly form sysconfdir
1712 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1718 * Load the user saved registries
1720 if (!(home = getenv( "HOME" )))
1721 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1722 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1725 * Load user's personal versions of global HKU/.Default keys
1727 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1728 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1730 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1731 _wine_loadreg( HKEY_USERS, fn );
1734 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1736 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1737 _wine_loadreg( HKEY_CURRENT_USER, fn );
1741 * Load HKLM, attempt to get the registry location from the config
1742 * file first, if exist, load and keep going.
1744 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1746 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1747 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1752 * Load HKCU, get the registry location from the config
1753 * file, if exist, load and keep going.
1755 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1757 fn = xmalloc( MAX_PATHNAME_LEN );
1758 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1759 fn, MAX_PATHNAME_LEN - 1))
1761 _wine_loadreg( HKEY_CURRENT_USER, fn );
1765 * Load HKU, get the registry location from the config
1766 * file, if exist, load and keep going.
1768 fn = xmalloc ( MAX_PATHNAME_LEN );
1769 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1770 fn, MAX_PATHNAME_LEN - 1))
1772 _wine_loadreg( HKEY_USERS, fn );
1776 * Load HKLM, get the registry location from the config
1777 * file, if exist, load and keep going.
1779 fn = xmalloc ( MAX_PATHNAME_LEN );
1780 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1781 fn, MAX_PATHNAME_LEN - 1))
1783 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1789 * Make sure the update mode is there
1791 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1793 DWORD junk,type,len;
1797 if (( RegQueryValueExA(
1803 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1805 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1811 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1813 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1818 /********************* API FUNCTIONS ***************************************/
1823 /******************************************************************************
1824 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1825 * Immediately writes key to registry.
1826 * Only returns after data has been written to disk.
1828 * FIXME: does it really wait until data is written ?
1831 * hkey [I] Handle of key to write
1834 * Success: ERROR_SUCCESS
1835 * Failure: Error code
1837 DWORD WINAPI RegFlushKey( HKEY hkey )
1839 FIXME( "(%x): stub\n", hkey );
1840 return ERROR_SUCCESS;
1843 /******************************************************************************
1844 * RegConnectRegistry32W [ADVAPI32.128]
1847 * lpMachineName [I] Address of name of remote computer
1848 * hHey [I] Predefined registry handle
1849 * phkResult [I] Address of buffer for remote registry handle
1851 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1854 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1856 if (!lpMachineName || !*lpMachineName) {
1857 /* Use the local machine name */
1858 return RegOpenKey16( hKey, "", phkResult );
1861 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1862 return ERROR_BAD_NETPATH;
1866 /******************************************************************************
1867 * RegConnectRegistry32A [ADVAPI32.127]
1869 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1872 LPWSTR machineW = strdupA2W(machine);
1873 ret = RegConnectRegistryW( machineW, hkey, reskey );
1879 /******************************************************************************
1880 * RegGetKeySecurity [ADVAPI32.144]
1881 * Retrieves a copy of security descriptor protecting the registry key
1884 * hkey [I] Open handle of key to set
1885 * SecurityInformation [I] Descriptor contents
1886 * pSecurityDescriptor [O] Address of descriptor for key
1887 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1890 * Success: ERROR_SUCCESS
1891 * Failure: Error code
1893 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1894 SECURITY_INFORMATION SecurityInformation,
1895 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1896 LPDWORD lpcbSecurityDescriptor )
1898 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1899 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1901 /* FIXME: Check for valid SecurityInformation values */
1903 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1904 return ERROR_INSUFFICIENT_BUFFER;
1906 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1907 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1909 return ERROR_SUCCESS;
1913 /******************************************************************************
1914 * RegNotifyChangeKeyValue [ADVAPI32.???]
1917 * hkey [I] Handle of key to watch
1918 * fWatchSubTree [I] Flag for subkey notification
1919 * fdwNotifyFilter [I] Changes to be reported
1920 * hEvent [I] Handle of signaled event
1921 * fAsync [I] Flag for asynchronous reporting
1923 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1924 DWORD fdwNotifyFilter, HANDLE hEvent,
1927 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1929 return ERROR_SUCCESS;
1933 /******************************************************************************
1934 * RegUnLoadKey32W [ADVAPI32.173]
1937 * hkey [I] Handle of open key
1938 * lpSubKey [I] Address of name of subkey to unload
1940 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1942 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1943 return ERROR_SUCCESS;
1947 /******************************************************************************
1948 * RegUnLoadKey32A [ADVAPI32.172]
1950 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1953 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1954 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1955 if(lpSubKeyW) free(lpSubKeyW);
1960 /******************************************************************************
1961 * RegSetKeySecurity [ADVAPI32.167]
1964 * hkey [I] Open handle of key to set
1965 * SecurityInfo [I] Descriptor contents
1966 * pSecurityDesc [I] Address of descriptor for key
1968 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1969 PSECURITY_DESCRIPTOR pSecurityDesc )
1971 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1973 /* It seems to perform this check before the hkey check */
1974 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1975 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1976 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1977 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1980 return ERROR_INVALID_PARAMETER;
1983 return ERROR_INVALID_PARAMETER;
1985 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1987 return ERROR_SUCCESS;
1991 /******************************************************************************
1992 * RegRestoreKey32W [ADVAPI32.164]
1995 * hkey [I] Handle of key where restore begins
1996 * lpFile [I] Address of filename containing saved tree
1997 * dwFlags [I] Optional flags
1999 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
2001 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
2003 /* It seems to do this check before the hkey check */
2004 if (!lpFile || !*lpFile)
2005 return ERROR_INVALID_PARAMETER;
2007 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
2009 /* Check for file existence */
2011 return ERROR_SUCCESS;
2015 /******************************************************************************
2016 * RegRestoreKey32A [ADVAPI32.163]
2018 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
2021 LPWSTR lpFileW = strdupA2W(lpFile);
2022 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
2023 if(lpFileW) free(lpFileW);
2028 /******************************************************************************
2029 * RegReplaceKey32W [ADVAPI32.162]
2032 * hkey [I] Handle of open key
2033 * lpSubKey [I] Address of name of subkey
2034 * lpNewFile [I] Address of filename for file with new data
2035 * lpOldFile [I] Address of filename for backup file
2037 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
2040 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
2041 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
2042 return ERROR_SUCCESS;
2046 /******************************************************************************
2047 * RegReplaceKey32A [ADVAPI32.161]
2049 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
2053 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
2054 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
2055 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
2056 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
2068 /* 16-bit functions */
2070 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
2071 * some programs. Do not remove those cases. -MM
2073 static inline void fix_win16_hkey( HKEY *hkey )
2075 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
2078 /******************************************************************************
2079 * RegEnumKey16 [KERNEL.216] [SHELL.7]
2081 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
2083 fix_win16_hkey( &hkey );
2084 return RegEnumKeyA( hkey, index, name, name_len );
2087 /******************************************************************************
2088 * RegOpenKey16 [KERNEL.217] [SHELL.1]
2090 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2092 fix_win16_hkey( &hkey );
2093 return RegOpenKeyA( hkey, name, retkey );
2096 /******************************************************************************
2097 * RegCreateKey16 [KERNEL.218] [SHELL.2]
2099 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
2101 fix_win16_hkey( &hkey );
2102 return RegCreateKeyA( hkey, name, retkey );
2105 /******************************************************************************
2106 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
2108 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
2110 fix_win16_hkey( &hkey );
2111 return RegDeleteKeyA( hkey, name );
2114 /******************************************************************************
2115 * RegCloseKey16 [KERNEL.220] [SHELL.3]
2117 DWORD WINAPI RegCloseKey16( HKEY hkey )
2119 fix_win16_hkey( &hkey );
2120 return RegCloseKey( hkey );
2123 /******************************************************************************
2124 * RegSetValue16 [KERNEL.221] [SHELL.5]
2126 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
2128 fix_win16_hkey( &hkey );
2129 return RegSetValueA( hkey, name, type, data, count );
2132 /******************************************************************************
2133 * RegDeleteValue16 [KERNEL.222]
2135 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
2137 fix_win16_hkey( &hkey );
2138 return RegDeleteValueA( hkey, name );
2141 /******************************************************************************
2142 * RegEnumValue16 [KERNEL.223]
2144 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
2145 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
2147 fix_win16_hkey( &hkey );
2148 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
2151 /******************************************************************************
2152 * RegQueryValue16 [KERNEL.224] [SHELL.6]
2155 * Is this HACK still applicable?
2158 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2159 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2162 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2164 fix_win16_hkey( &hkey );
2165 if (count) *count &= 0xffff;
2166 return RegQueryValueA( hkey, name, data, count );
2169 /******************************************************************************
2170 * RegQueryValueEx16 [KERNEL.225]
2172 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2173 LPBYTE data, LPDWORD count )
2175 fix_win16_hkey( &hkey );
2176 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2179 /******************************************************************************
2180 * RegSetValueEx16 [KERNEL.226]
2182 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2183 CONST BYTE *data, DWORD count )
2185 fix_win16_hkey( &hkey );
2186 return RegSetValueExA( hkey, name, reserved, type, data, count );