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);
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
678 #define NT_REG_VALUE_BLOCK_ID 0x6b76
679 #define NT_REG_HASH_BLOCK_ID 0x666c
680 #define NT_REG_NOHASH_BLOCK_ID 0x696c
681 #define NT_REG_KEY_BLOCK_TYPE 0x20
682 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
686 DWORD id; /* 0x66676572 'regf'*/
687 DWORD uk1; /* 0x04 */
688 DWORD uk2; /* 0x08 */
689 FILETIME DateModified; /* 0x0c */
690 DWORD uk3; /* 0x14 */
691 DWORD uk4; /* 0x18 */
692 DWORD uk5; /* 0x1c */
693 DWORD uk6; /* 0x20 */
694 DWORD RootKeyBlock; /* 0x24 */
695 DWORD BlockSize; /* 0x28 */
697 DWORD Checksum; /* at offset 0x1FC */
708 DWORD id; /* 0x6E696268 'hbin' */
712 DWORD uk2; /* 0x10 */
713 DWORD uk3; /* 0x14 */
714 DWORD uk4; /* 0x18 */
715 DWORD size; /* 0x1C */
716 nt_hbin_sub hbin_sub; /* 0x20 */
720 * the value_list consists of offsets to the values (vk)
724 WORD SubBlockId; /* 0x00 0x6B6E */
725 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
726 FILETIME writetime; /* 0x04 */
727 DWORD uk1; /* 0x0C */
728 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
729 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
730 DWORD uk8; /* 0x18 */
731 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
732 DWORD uk2; /* 0x20 */
733 DWORD nr_values; /* 0x24 number of values */
734 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
735 DWORD off_sk; /* 0x2c Offset of the sk-Record */
736 DWORD off_class; /* 0x30 Offset of the Class-Name */
737 DWORD uk3; /* 0x34 */
738 DWORD uk4; /* 0x38 */
739 DWORD uk5; /* 0x3c */
740 DWORD uk6; /* 0x40 */
741 DWORD uk7; /* 0x44 */
742 WORD name_len; /* 0x48 name-length */
743 WORD class_len; /* 0x4a class-name length */
744 char name[1]; /* 0x4c key-name */
749 DWORD off_nk; /* 0x00 */
750 DWORD name; /* 0x04 */
755 WORD id; /* 0x00 0x666c */
756 WORD nr_keys; /* 0x06 */
757 hash_rec hash_rec[1];
762 WORD id; /* 0x00 0x696c */
769 WORD id; /* 0x00 'vk' */
779 LPSTR _strdupnA( LPCSTR str, int len )
783 if (!str) return NULL;
784 ret = malloc( len + 1 );
785 lstrcpynA( ret, str, len );
790 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
791 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
792 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level);
799 * 0 value is a default value
800 * 1 the value has a name
803 * len of the whole data block
805 * bytes including the terminating \0 = 2*(number_of_chars+1)
806 * - reg_dword, reg_binary:
807 * if highest bit of data_len is set data_off contains the value
809 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
813 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
815 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
817 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
819 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
820 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
821 (vk->data_len & 0x7fffffff) );
822 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
825 ERR_(reg)("vk block invalid\n");
832 * this structure contains the hash of a keyname and points to all
835 * exception: if the id is 'il' there are no hash values and every
838 static int _nt_parse_lf(HKEY hkey, char * base, nt_lf * lf, int level)
842 if (lf->id == NT_REG_HASH_BLOCK_ID)
844 for (i=0; i<lf->nr_keys; i++)
846 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
850 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
852 for (i=0; i<lf->nr_keys; i++)
854 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+((nt_il*)lf)->off_nk[i]+4), level)) goto error;
859 error: ERR_(reg)("error reading lf block\n");
863 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
870 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID) goto error;
871 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
872 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID)) goto error;
874 /* create the new key */
877 name = _strdupnA( nk->name, nk->name_len+1);
878 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
882 /* loop through the subkeys */
885 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
886 if (nk->nr_subkeys != lf->nr_keys) goto error1;
887 if (!_nt_parse_lf(subkey, base, lf, level-1)) goto error1;
890 /* loop trough the value list */
891 vl = (DWORD *)(base+nk->valuelist_off+4);
892 for (i=0; i<nk->nr_values; i++)
894 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
895 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
901 error1: RegCloseKey(subkey);
902 error: ERR_(reg)("error reading nk block\n");
908 /* windows 95 registry loader */
910 /* SECTION 1: main header
914 #define W95_REG_CREG_ID 0x47455243
918 DWORD id; /* "CREG" = W95_REG_CREG_ID */
919 DWORD version; /* ???? 0x00010000 */
920 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
921 DWORD uk2; /* 0x0c */
922 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
928 /* SECTION 2: Directory information (tree structure)
930 * once on offset 0x20
932 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
934 #define W95_REG_RGKN_ID 0x4e4b4752
938 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
939 DWORD size; /* Size of the RGKN-block */
940 DWORD root_off; /* Rel. Offset of the root-record */
944 /* Disk Key Entry Structure
946 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
947 * hive itself. It looks the same like other keys. Even the ID-number can
950 * The "hash"-value is a value representing the key's name. Windows will not
951 * search for the name, but for a matching hash-value. if it finds one, it
952 * will compare the actual string info, otherwise continue with the next key.
953 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
954 * of the string which are smaller than 0x80 (128) to this D-Word.
956 * If you want to modify key names, also modify the hash-values, since they
957 * cannot be found again (although they would be displayed in REGEDIT)
958 * End of list-pointers are filled with 0xFFFFFFFF
960 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
961 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
962 * structure) and reading another RGDB_section.
964 * there is a one to one relationship between dke and dkh
966 /* key struct, once per key */
969 DWORD x1; /* Free entry indicator(?) */
970 DWORD hash; /* sum of bytes of keyname */
971 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
972 DWORD prevlvl; /* offset of previous key */
973 DWORD nextsub; /* offset of child key */
974 DWORD next; /* offset of sibling key */
975 WORD nrLS; /* id inside the rgdb block */
976 WORD nrMS; /* number of the rgdb block */
979 /* SECTION 3: key information, values and data
982 * section: [blocks]* (repeat creg->rgdb_num times)
983 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
984 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
986 * An interesting relationship exists in RGDB_section. The value at offset
987 * 10 equals the value at offset 4 minus the value at offset 8. I have no
988 * idea at the moment what this means. (Kevin Cozens)
991 /* block header, once per block */
992 #define W95_REG_RGDB_ID 0x42444752
996 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
997 DWORD size; /* 0x04 */
998 DWORD uk1; /* 0x08 */
999 DWORD uk2; /* 0x0c */
1000 DWORD uk3; /* 0x10 */
1001 DWORD uk4; /* 0x14 */
1002 DWORD uk5; /* 0x18 */
1003 DWORD uk6; /* 0x1c */
1007 /* Disk Key Header structure (RGDB part), once per key */
1010 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
1011 WORD nrLS; /* 0x04 id inside the rgdb block */
1012 WORD nrMS; /* 0x06 number of the rgdb block */
1013 DWORD bytesused; /* 0x08 */
1014 WORD keynamelen; /* 0x0c len of name */
1015 WORD values; /* 0x0e number of values */
1016 DWORD xx1; /* 0x10 */
1017 char name[1]; /* 0x14 */
1018 /* dkv */ /* 0x14 + keynamelen */
1021 /* Disk Key Value structure, once per value */
1024 DWORD type; /* 0x00 */
1025 DWORD x1; /* 0x04 */
1026 WORD valnamelen; /* 0x08 length of name, 0 is default key */
1027 WORD valdatalen; /* 0x0A length of data */
1028 char name[1]; /* 0x0c */
1029 /* raw data */ /* 0x0c + valnamelen */
1032 /******************************************************************************
1033 * _w95_lookup_dkh [Internal]
1035 * seeks the dkh belonging to a dke
1037 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
1043 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off); /* get the beginning of the rgdb datastore */
1044 assert (creg->rgdb_num > nrMS); /* check: requested block < last_block) */
1046 /* find the right block */
1047 for(i=0; i<nrMS ;i++)
1049 assert(rgdb->id == W95_REG_RGDB_ID); /* check the magic */
1050 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
1053 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
1057 if(nrLS==dkh->nrLS ) return dkh;
1058 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
1059 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
1064 /******************************************************************************
1065 * _w95_parse_dkv [Internal]
1067 static int _w95_parse_dkv (
1078 /* first value block */
1079 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
1081 /* loop trought the values */
1082 for (i=0; i< dkh->values; i++)
1084 name = _strdupnA(dkv->name, dkv->valnamelen+1);
1085 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
1086 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
1090 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
1095 /******************************************************************************
1096 * _w95_parse_dke [Internal]
1098 static int _w95_parse_dke(
1106 HKEY hsubkey = hkey;
1110 /* get start address of root key block */
1111 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1114 if (dke->nrLS != 0xffff && dke->nrMS!=0xffff) /* eg. the root key has no name */
1116 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1118 fprintf(stderr, "dke pointing to missing dkh !\n");
1121 /* subblock found */
1124 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1125 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1128 _w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS);
1132 level++; /* we have to skip the root-block anyway */
1135 /* walk sibling keys */
1136 if (dke->next != 0xffffffff )
1138 _w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level);
1142 if (dke->nextsub != 0xffffffff)
1144 _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1);
1148 if (hsubkey != hkey) RegCloseKey(hsubkey);
1151 /* end windows 95 loader */
1153 /******************************************************************************
1154 * NativeRegLoadKey [Internal]
1156 * Loads a native registry file (win95/nt)
1159 * level number of levels to cut away (eg. ".Default" in user.dat)
1161 * this function intentionally uses unix file functions to make it possible
1162 * to move it to a seperate registry helper programm
1164 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1168 DOS_FULL_NAME full_name;
1172 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1174 /* map the registry into the memory */
1175 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1176 if ((fstat(fd, &st) == -1)) goto error;
1177 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1179 switch (*(LPDWORD)base)
1181 /* windows 95 'creg' */
1182 case W95_REG_CREG_ID:
1187 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1189 /* load the header (rgkn) */
1190 rgkn = (_w95rgkn*)(creg + 1);
1191 if (rgkn->id != W95_REG_RGKN_ID)
1193 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1197 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1201 case NT_REG_HEADER_BLOCK_ID:
1205 nt_hbin_sub * hbin_sub;
1208 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1214 hbin = base + 0x1000;
1215 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1217 ERR_(reg)( "%s hbin block invalid\n", fn);
1221 /* hbin_sub block */
1222 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1223 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1225 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1230 nk = (nt_nk*)&(hbin_sub->data[0]);
1231 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1233 ERR_(reg)( "%s special nk block not found\n", fn);
1237 ret = _nt_parse_nk (hkey, base+0x1000, nk, level);
1242 ERR("unknown signature in registry file %s.\n",fn);
1247 error1: munmap(base, st.st_size);
1252 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1254 reghack - windows 3.11 registry data format demo program.
1256 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1257 a combined hash table and tree description, and finally a text table.
1259 The header is obvious from the struct header. The taboff1 and taboff2
1260 fields are always 0x20, and their usage is unknown.
1262 The 8-byte entry table has various entry types.
1264 tabent[0] is a root index. The second word has the index of the root of
1266 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1267 the index of the key/value that has that hash. Data with the same
1268 hash value are on a circular list. The other three words in the
1269 hash entry are always zero.
1270 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1271 entry: dirent and keyent/valent. They are identified by context.
1272 tabent[freeidx] is the first free entry. The first word in a free entry
1273 is the index of the next free entry. The last has 0 as a link.
1274 The other three words in the free list are probably irrelevant.
1276 Entries in text table are preceeded by a word at offset-2. This word
1277 has the value (2*index)+1, where index is the referring keyent/valent
1278 entry in the table. I have no suggestion for the 2* and the +1.
1279 Following the word, there are N bytes of data, as per the keyent/valent
1280 entry length. The offset of the keyent/valent entry is from the start
1281 of the text table to the first data byte.
1283 This information is not available from Microsoft. The data format is
1284 deduced from the reg.dat file by me. Mistakes may
1285 have been made. I claim no rights and give no guarantees for this program.
1287 Tor Sjøwall, tor@sn.no
1290 /* reg.dat header format */
1291 struct _w31_header {
1292 char cookie[8]; /* 'SHCC3.10' */
1293 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1294 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1295 unsigned long tabcnt; /* number of entries in index table */
1296 unsigned long textoff; /* offset of text part */
1297 unsigned long textsize; /* byte size of text part */
1298 unsigned short hashsize; /* hash size */
1299 unsigned short freeidx; /* free index */
1302 /* generic format of table entries */
1303 struct _w31_tabent {
1304 unsigned short w0, w1, w2, w3;
1307 /* directory tabent: */
1308 struct _w31_dirent {
1309 unsigned short sibling_idx; /* table index of sibling dirent */
1310 unsigned short child_idx; /* table index of child dirent */
1311 unsigned short key_idx; /* table index of key keyent */
1312 unsigned short value_idx; /* table index of value valent */
1316 struct _w31_keyent {
1317 unsigned short hash_idx; /* hash chain index for string */
1318 unsigned short refcnt; /* reference count */
1319 unsigned short length; /* length of string */
1320 unsigned short string_off; /* offset of string in text table */
1324 struct _w31_valent {
1325 unsigned short hash_idx; /* hash chain index for string */
1326 unsigned short refcnt; /* reference count */
1327 unsigned short length; /* length of string */
1328 unsigned short string_off; /* offset of string in text table */
1331 /* recursive helper function to display a directory tree */
1333 __w31_dumptree( unsigned short idx,
1335 struct _w31_tabent *tab,
1336 struct _w31_header *head,
1338 time_t lastmodified,
1341 struct _w31_dirent *dir;
1342 struct _w31_keyent *key;
1343 struct _w31_valent *val;
1345 static char tail[400];
1348 dir=(struct _w31_dirent*)&tab[idx];
1351 key = (struct _w31_keyent*)&tab[dir->key_idx];
1353 memcpy(tail,&txt[key->string_off],key->length);
1354 tail[key->length]='\0';
1355 /* all toplevel entries AND the entries in the
1356 * toplevel subdirectory belong to \SOFTWARE\Classes
1358 if (!level && !lstrcmpA(tail,".classes")) {
1359 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1360 idx=dir->sibling_idx;
1363 if (subkey) RegCloseKey( subkey );
1364 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1365 /* only add if leaf node or valued node */
1366 if (dir->value_idx!=0||dir->child_idx==0) {
1367 if (dir->value_idx) {
1368 val=(struct _w31_valent*)&tab[dir->value_idx];
1369 memcpy(tail,&txt[val->string_off],val->length);
1370 tail[val->length]='\0';
1371 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1375 TRACE("strange: no directory key name, idx=%04x\n", idx);
1377 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1378 idx=dir->sibling_idx;
1380 if (subkey) RegCloseKey( subkey );
1384 /******************************************************************************
1385 * _w31_loadreg [Internal]
1387 void _w31_loadreg(void) {
1389 struct _w31_header head;
1390 struct _w31_tabent *tab;
1394 BY_HANDLE_FILE_INFORMATION hfinfo;
1395 time_t lastmodified;
1399 hf = OpenFile("reg.dat",&ofs,OF_READ);
1400 if (hf==HFILE_ERROR)
1403 /* read & dump header */
1404 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1405 ERR("reg.dat is too short.\n");
1409 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1410 ERR("reg.dat has bad signature.\n");
1415 len = head.tabcnt * sizeof(struct _w31_tabent);
1416 /* read and dump index table */
1418 if (len!=_lread(hf,tab,len)) {
1419 ERR("couldn't read %d bytes.\n",len);
1426 txt = xmalloc(head.textsize);
1427 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1428 ERR("couldn't seek to textblock.\n");
1434 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1435 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1442 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1443 ERR("GetFileInformationByHandle failed?.\n");
1449 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1450 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1457 /**********************************************************************************
1458 * SetLoadLevel [Internal]
1460 * set level to 0 for loading system files
1461 * set level to 1 for loading user files
1463 static void SetLoadLevel(int level)
1465 struct set_registry_levels_request *req = get_req_buffer();
1467 req->current = level;
1470 server_call( REQ_SET_REGISTRY_LEVELS );
1473 /**********************************************************************************
1474 * SHELL_LoadRegistry [Internal]
1476 void SHELL_LoadRegistry( void )
1487 if (PROFILE_GetWineIniBool ("registry", "LoadWin311RegistryFiles", 1))
1489 /* Load windows 3.1 entries */
1492 if (PROFILE_GetWineIniBool ("registry", "LoadWin95RegistryFiles", 1))
1494 /* Load windows 95 entries */
1495 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1496 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "system.dat", 0);
1497 NativeRegLoadKey(HKEY_CURRENT_USER, "user.dat", 1);
1499 if (PROFILE_GetWineIniBool ("registry", "LoadWinNTRegistryFiles", 1))
1501 fn = xmalloc( MAX_PATHNAME_LEN );
1502 home = xmalloc ( MAX_PATHNAME_LEN );
1503 if ( PROFILE_GetWineIniString( "registry", "NTUser", "", home, MAX_PATHNAME_LEN - 1))
1505 GetWindowsDirectoryA( fn, MAX_PATHNAME_LEN );
1506 strncat(fn, "\\Profiles\\", MAX_PATHNAME_LEN - strlen(fn) - 1);
1507 strncat(fn, home, MAX_PATHNAME_LEN - strlen(fn) - 1);
1508 strncat(fn, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(fn) - 1);
1509 NativeRegLoadKey( HKEY_CURRENT_USER, fn, 1 );
1513 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1515 GetSystemDirectoryA( fn, MAX_PATHNAME_LEN );
1518 strncat(home, "\\config\\system", MAX_PATHNAME_LEN - strlen(home) - 1);
1519 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1522 strncat(home, "\\config\\software", MAX_PATHNAME_LEN - strlen(home) - 1);
1523 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1526 strncat(home, "\\config\\sam", MAX_PATHNAME_LEN - strlen(home) - 1);
1527 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1530 strncat(home, "\\config\\security", MAX_PATHNAME_LEN - strlen(home) - 1);
1531 NativeRegLoadKey(HKEY_LOCAL_MACHINE, home, 0);
1535 /* this key is generated when the nt-core booted successfully */
1536 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1540 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1543 * Load the global HKU hive directly from sysconfdir
1545 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1548 * Load the global machine defaults directly form sysconfdir
1550 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1556 * Load the user saved registries
1558 if (!(home = getenv( "HOME" )))
1559 WARN("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1560 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1563 * Load user's personal versions of global HKU/.Default keys
1565 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1566 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1568 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1569 _wine_loadreg( HKEY_USERS, fn );
1572 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
1574 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1575 _wine_loadreg( HKEY_CURRENT_USER, fn );
1579 * Load HKLM, attempt to get the registry location from the config
1580 * file first, if exist, load and keep going.
1582 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
1584 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1585 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1590 * Load HKCU, get the registry location from the config
1591 * file, if exist, load and keep going.
1593 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1595 fn = xmalloc( MAX_PATHNAME_LEN );
1596 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1597 fn, MAX_PATHNAME_LEN - 1))
1599 _wine_loadreg( HKEY_CURRENT_USER, fn );
1603 * Load HKU, get the registry location from the config
1604 * file, if exist, load and keep going.
1606 fn = xmalloc ( MAX_PATHNAME_LEN );
1607 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1608 fn, MAX_PATHNAME_LEN - 1))
1610 _wine_loadreg( HKEY_USERS, fn );
1614 * Load HKLM, get the registry location from the config
1615 * file, if exist, load and keep going.
1617 fn = xmalloc ( MAX_PATHNAME_LEN );
1618 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1619 fn, MAX_PATHNAME_LEN - 1))
1621 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1627 * Make sure the update mode is there
1629 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
1631 DWORD junk,type,len;
1635 if (( RegQueryValueExA(
1641 &len) != ERROR_SUCCESS) || (type != REG_SZ))
1643 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1649 if ((save_timeout = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1651 SERVICE_AddTimer( save_timeout * 1000000, periodic_save, 0 );
1656 /********************* API FUNCTIONS ***************************************/
1661 /******************************************************************************
1662 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1663 * Immediately writes key to registry.
1664 * Only returns after data has been written to disk.
1666 * FIXME: does it really wait until data is written ?
1669 * hkey [I] Handle of key to write
1672 * Success: ERROR_SUCCESS
1673 * Failure: Error code
1675 DWORD WINAPI RegFlushKey( HKEY hkey )
1677 FIXME( "(%x): stub\n", hkey );
1678 return ERROR_SUCCESS;
1681 /******************************************************************************
1682 * RegConnectRegistry32W [ADVAPI32.128]
1685 * lpMachineName [I] Address of name of remote computer
1686 * hHey [I] Predefined registry handle
1687 * phkResult [I] Address of buffer for remote registry handle
1689 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1692 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1694 if (!lpMachineName || !*lpMachineName) {
1695 /* Use the local machine name */
1696 return RegOpenKey16( hKey, "", phkResult );
1699 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1700 return ERROR_BAD_NETPATH;
1704 /******************************************************************************
1705 * RegConnectRegistry32A [ADVAPI32.127]
1707 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1710 LPWSTR machineW = strdupA2W(machine);
1711 ret = RegConnectRegistryW( machineW, hkey, reskey );
1717 /******************************************************************************
1718 * RegGetKeySecurity [ADVAPI32.144]
1719 * Retrieves a copy of security descriptor protecting the registry key
1722 * hkey [I] Open handle of key to set
1723 * SecurityInformation [I] Descriptor contents
1724 * pSecurityDescriptor [O] Address of descriptor for key
1725 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1728 * Success: ERROR_SUCCESS
1729 * Failure: Error code
1731 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1732 SECURITY_INFORMATION SecurityInformation,
1733 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1734 LPDWORD lpcbSecurityDescriptor )
1736 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1737 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1739 /* FIXME: Check for valid SecurityInformation values */
1741 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1742 return ERROR_INSUFFICIENT_BUFFER;
1744 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1745 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1747 return ERROR_SUCCESS;
1751 /******************************************************************************
1752 * RegNotifyChangeKeyValue [ADVAPI32.???]
1755 * hkey [I] Handle of key to watch
1756 * fWatchSubTree [I] Flag for subkey notification
1757 * fdwNotifyFilter [I] Changes to be reported
1758 * hEvent [I] Handle of signaled event
1759 * fAsync [I] Flag for asynchronous reporting
1761 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1762 DWORD fdwNotifyFilter, HANDLE hEvent,
1765 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1767 return ERROR_SUCCESS;
1771 /******************************************************************************
1772 * RegUnLoadKey32W [ADVAPI32.173]
1775 * hkey [I] Handle of open key
1776 * lpSubKey [I] Address of name of subkey to unload
1778 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1780 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1781 return ERROR_SUCCESS;
1785 /******************************************************************************
1786 * RegUnLoadKey32A [ADVAPI32.172]
1788 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1791 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1792 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1793 if(lpSubKeyW) free(lpSubKeyW);
1798 /******************************************************************************
1799 * RegSetKeySecurity [ADVAPI32.167]
1802 * hkey [I] Open handle of key to set
1803 * SecurityInfo [I] Descriptor contents
1804 * pSecurityDesc [I] Address of descriptor for key
1806 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1807 PSECURITY_DESCRIPTOR pSecurityDesc )
1809 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1811 /* It seems to perform this check before the hkey check */
1812 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1813 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1814 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1815 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1818 return ERROR_INVALID_PARAMETER;
1821 return ERROR_INVALID_PARAMETER;
1823 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1825 return ERROR_SUCCESS;
1829 /******************************************************************************
1830 * RegRestoreKey32W [ADVAPI32.164]
1833 * hkey [I] Handle of key where restore begins
1834 * lpFile [I] Address of filename containing saved tree
1835 * dwFlags [I] Optional flags
1837 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1839 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1841 /* It seems to do this check before the hkey check */
1842 if (!lpFile || !*lpFile)
1843 return ERROR_INVALID_PARAMETER;
1845 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1847 /* Check for file existence */
1849 return ERROR_SUCCESS;
1853 /******************************************************************************
1854 * RegRestoreKey32A [ADVAPI32.163]
1856 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1859 LPWSTR lpFileW = strdupA2W(lpFile);
1860 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1861 if(lpFileW) free(lpFileW);
1866 /******************************************************************************
1867 * RegReplaceKey32W [ADVAPI32.162]
1870 * hkey [I] Handle of open key
1871 * lpSubKey [I] Address of name of subkey
1872 * lpNewFile [I] Address of filename for file with new data
1873 * lpOldFile [I] Address of filename for backup file
1875 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1878 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1879 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1880 return ERROR_SUCCESS;
1884 /******************************************************************************
1885 * RegReplaceKey32A [ADVAPI32.161]
1887 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1891 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1892 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1893 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1894 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1906 /* 16-bit functions */
1908 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1909 * some programs. Do not remove those cases. -MM
1911 static inline void fix_win16_hkey( HKEY *hkey )
1913 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1916 /******************************************************************************
1917 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1919 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1921 fix_win16_hkey( &hkey );
1922 return RegEnumKeyA( hkey, index, name, name_len );
1925 /******************************************************************************
1926 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1928 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1930 fix_win16_hkey( &hkey );
1931 return RegOpenKeyA( hkey, name, retkey );
1934 /******************************************************************************
1935 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1937 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1939 fix_win16_hkey( &hkey );
1940 return RegCreateKeyA( hkey, name, retkey );
1943 /******************************************************************************
1944 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1946 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1948 fix_win16_hkey( &hkey );
1949 return RegDeleteKeyA( hkey, name );
1952 /******************************************************************************
1953 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1955 DWORD WINAPI RegCloseKey16( HKEY hkey )
1957 fix_win16_hkey( &hkey );
1958 return RegCloseKey( hkey );
1961 /******************************************************************************
1962 * RegSetValue16 [KERNEL.221] [SHELL.5]
1964 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1966 fix_win16_hkey( &hkey );
1967 return RegSetValueA( hkey, name, type, data, count );
1970 /******************************************************************************
1971 * RegDeleteValue16 [KERNEL.222]
1973 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1975 fix_win16_hkey( &hkey );
1976 return RegDeleteValueA( hkey, name );
1979 /******************************************************************************
1980 * RegEnumValue16 [KERNEL.223]
1982 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1983 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1985 fix_win16_hkey( &hkey );
1986 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1989 /******************************************************************************
1990 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1993 * Is this HACK still applicable?
1996 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1997 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2000 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
2002 fix_win16_hkey( &hkey );
2003 if (count) *count &= 0xffff;
2004 return RegQueryValueA( hkey, name, data, count );
2007 /******************************************************************************
2008 * RegQueryValueEx16 [KERNEL.225]
2010 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2011 LPBYTE data, LPDWORD count )
2013 fix_win16_hkey( &hkey );
2014 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2017 /******************************************************************************
2018 * RegSetValueEx16 [KERNEL.226]
2020 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2021 CONST BYTE *data, DWORD count )
2023 fix_win16_hkey( &hkey );
2024 return RegSetValueExA( hkey, name, reserved, type, data, count );