Change xterm mouse tracking mode to BTN_EVENT_MOUSE (track if pressed).
[wine.git] / misc / registry.c
blobddf2fc1487b65ed69c20cdd4190fb6f6b12849ff
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
33 #endif
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/fcntl.h>
37 #include <sys/stat.h>
38 #include <time.h>
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "wine/winbase16.h"
43 #include "winerror.h"
44 #include "file.h"
45 #include "heap.h"
46 #include "debugtools.h"
47 #include "options.h"
48 #include "winreg.h"
49 #include "server.h"
50 #include "services.h"
52 DEFAULT_DEBUG_CHANNEL(reg);
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
57 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
58 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
60 /* relative in ~user/.wine/ : */
61 #define SAVE_CURRENT_USER "user.reg"
62 #define SAVE_DEFAULT_USER "userdef.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
67 static void *xmalloc( size_t size )
69 void *res;
71 res = malloc (size ? size : 1);
72 if (res == NULL) {
73 WARN("Virtual memory exhausted.\n");
74 exit (1);
76 return res;
80 /******************************************************************************
81 * REGISTRY_Init [Internal]
82 * Registry initialisation, allocates some default keys.
84 static void REGISTRY_Init(void) {
85 HKEY hkey;
86 char buf[200];
88 TRACE("(void)\n");
90 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
91 RegCloseKey(hkey);
93 /* This was an Open, but since it is called before the real registries
94 are loaded, it was changed to a Create - MTB 980507*/
95 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
96 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
97 RegCloseKey(hkey);
99 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
100 * CurrentVersion
101 * CurrentBuildNumber
102 * CurrentType
103 * string RegisteredOwner
104 * string RegisteredOrganization
107 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
108 * string SysContact
109 * string SysLocation
110 * SysServices
112 if (-1!=gethostname(buf,200)) {
113 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
114 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
115 RegCloseKey(hkey);
120 /************************ LOAD Registry Function ****************************/
124 /******************************************************************************
125 * _find_or_add_key [Internal]
127 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
129 HKEY subkey;
130 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
131 if (keyname) free( keyname );
132 return subkey;
135 /******************************************************************************
136 * _find_or_add_value [Internal]
138 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
140 RegSetValueExW( hkey, name, 0, type, data, len );
141 if (name) free( name );
142 if (data) free( data );
146 /******************************************************************************
147 * _wine_read_line [Internal]
149 * reads a line including dynamically enlarging the readbuffer and throwing
150 * away comments
152 static int _wine_read_line( FILE *F, char **buf, int *len )
154 char *s,*curread;
155 int mylen,curoff;
157 curread = *buf;
158 mylen = *len;
159 **buf = '\0';
160 while (1) {
161 while (1) {
162 s=fgets(curread,mylen,F);
163 if (s==NULL)
164 return 0; /* EOF */
165 if (NULL==(s=strchr(curread,'\n'))) {
166 /* buffer wasn't large enough */
167 curoff = strlen(*buf);
168 curread = realloc(*buf,*len*2);
169 if(curread == NULL) {
170 WARN("Out of memory");
171 return 0;
173 *buf = curread;
174 curread+= curoff;
175 mylen = *len; /* we filled up the buffer and
176 * got new '*len' bytes to fill
178 *len = *len * 2;
179 } else {
180 *s='\0';
181 break;
184 /* throw away comments */
185 if (**buf=='#' || **buf==';') {
186 curread = *buf;
187 mylen = *len;
188 continue;
190 if (s) /* got end of line */
191 break;
193 return 1;
197 /******************************************************************************
198 * _wine_read_USTRING [Internal]
200 * converts a char* into a UNICODE string (up to a special char)
201 * and returns the position exactly after that string
203 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
205 char *s;
206 LPWSTR ws;
208 /* read up to "=" or "\0" or "\n" */
209 s = buf;
210 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
211 ws = *str;
212 while (*s && (*s!='\n') && (*s!='=')) {
213 if (*s!='\\')
214 *ws++=*((unsigned char*)s++);
215 else {
216 s++;
217 if (!*s) {
218 /* Dangling \ ... may only happen if a registry
219 * write was short. FIXME: What to do?
221 break;
223 if (*s=='\\') {
224 *ws++='\\';
225 s++;
226 continue;
228 if (*s!='u') {
229 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
230 *ws++='\\';
231 *ws++=*s++;
232 } else {
233 char xbuf[5];
234 int wc;
236 s++;
237 memcpy(xbuf,s,4);xbuf[4]='\0';
238 if (!sscanf(xbuf,"%x",&wc))
239 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
240 s+=4;
241 *ws++ =(unsigned short)wc;
245 *ws = 0;
246 return s;
250 /******************************************************************************
251 * _wine_loadsubkey [Internal]
253 * NOTES
254 * It seems like this is returning a boolean. Should it?
256 * RETURNS
257 * Success: 1
258 * Failure: 0
260 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
262 HKEY subkey;
263 int i;
264 char *s;
265 LPWSTR name;
267 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
269 /* Good. We already got a line here ... so parse it */
270 subkey = 0;
271 while (1) {
272 i=0;s=*buf;
273 while (*s=='\t') {
274 s++;
275 i++;
277 if (i>level) {
278 if (!subkey) {
279 WARN("Got a subhierarchy without resp. key?\n");
280 return 0;
282 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
283 if (!_wine_read_line(F,buf,buflen))
284 goto done;
285 continue;
288 /* let the caller handle this line */
289 if (i<level || **buf=='\0')
290 goto done;
292 /* it can be: a value or a keyname. Parse the name first */
293 s=_wine_read_USTRING(s,&name);
295 /* switch() default: hack to avoid gotos */
296 switch (0) {
297 default:
298 if (*s=='\0') {
299 if (subkey) RegCloseKey( subkey );
300 subkey=_find_or_add_key(hkey,name);
301 } else {
302 LPBYTE data;
303 int len,lastmodified,type;
305 if (*s!='=') {
306 WARN("Unexpected character: %c\n",*s);
307 break;
309 s++;
310 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
311 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
312 break;
314 /* skip the 2 , */
315 s=strchr(s,',');s++;
316 s=strchr(s,',');
317 if (!s++) {
318 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
319 break;
321 if (type == REG_SZ || type == REG_EXPAND_SZ) {
322 s=_wine_read_USTRING(s,(LPWSTR*)&data);
323 len = lstrlenW((LPWSTR)data)*2+2;
324 } else {
325 len=strlen(s)/2;
326 data = (LPBYTE)xmalloc(len+1);
327 for (i=0;i<len;i++) {
328 data[i]=0;
329 if (*s>='0' && *s<='9')
330 data[i]=(*s-'0')<<4;
331 if (*s>='a' && *s<='f')
332 data[i]=(*s-'a'+'\xa')<<4;
333 if (*s>='A' && *s<='F')
334 data[i]=(*s-'A'+'\xa')<<4;
335 s++;
336 if (*s>='0' && *s<='9')
337 data[i]|=*s-'0';
338 if (*s>='a' && *s<='f')
339 data[i]|=*s-'a'+'\xa';
340 if (*s>='A' && *s<='F')
341 data[i]|=*s-'A'+'\xa';
342 s++;
345 _find_or_add_value(hkey,name,type,data,len);
348 /* read the next line */
349 if (!_wine_read_line(F,buf,buflen))
350 goto done;
352 done:
353 if (subkey) RegCloseKey( subkey );
354 return 1;
358 /******************************************************************************
359 * _wine_loadsubreg [Internal]
361 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
363 int ver;
364 char *buf;
365 int buflen;
367 buf=xmalloc(10);buflen=10;
368 if (!_wine_read_line(F,&buf,&buflen)) {
369 free(buf);
370 return 0;
372 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
373 free(buf);
374 return 0;
376 if (ver!=1) {
377 if (ver == 2) /* new version */
379 HANDLE file;
380 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
381 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
383 struct load_registry_request *req = get_req_buffer();
384 req->hkey = hkey;
385 req->file = file;
386 req->name[0] = 0;
387 server_call( REQ_LOAD_REGISTRY );
388 CloseHandle( file );
390 free( buf );
391 return 1;
393 else
395 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
396 free(buf);
397 return 0;
400 if (!_wine_read_line(F,&buf,&buflen)) {
401 free(buf);
402 return 0;
404 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
405 free(buf);
406 return 0;
408 free(buf);
409 return 1;
413 /******************************************************************************
414 * _wine_loadreg [Internal]
416 static int _wine_loadreg( HKEY hkey, char *fn )
418 FILE *F;
420 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
422 F = fopen(fn,"rb");
423 if (F==NULL) {
424 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
425 return -1;
427 _wine_loadsubreg(F,hkey,fn);
428 fclose(F);
429 return 0;
432 /* NT REGISTRY LOADER */
434 #ifdef HAVE_SYS_MMAN_H
435 # include <sys/mman.h>
436 #endif
438 #ifndef MAP_FAILED
439 #define MAP_FAILED ((LPVOID)-1)
440 #endif
442 #define NT_REG_BLOCK_SIZE 0x1000
444 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
445 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
446 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
447 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
449 /* subblocks of nk */
450 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
451 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
452 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
454 #define NT_REG_KEY_BLOCK_TYPE 0x20
455 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
457 typedef struct
459 DWORD id; /* 0x66676572 'regf'*/
460 DWORD uk1; /* 0x04 */
461 DWORD uk2; /* 0x08 */
462 FILETIME DateModified; /* 0x0c */
463 DWORD uk3; /* 0x14 */
464 DWORD uk4; /* 0x18 */
465 DWORD uk5; /* 0x1c */
466 DWORD uk6; /* 0x20 */
467 DWORD RootKeyBlock; /* 0x24 */
468 DWORD BlockSize; /* 0x28 */
469 DWORD uk7[116];
470 DWORD Checksum; /* at offset 0x1FC */
471 } nt_regf;
473 typedef struct
475 DWORD blocksize;
476 BYTE data[1];
477 } nt_hbin_sub;
479 typedef struct
481 DWORD id; /* 0x6E696268 'hbin' */
482 DWORD off_prev;
483 DWORD off_next;
484 DWORD uk1;
485 DWORD uk2; /* 0x10 */
486 DWORD uk3; /* 0x14 */
487 DWORD uk4; /* 0x18 */
488 DWORD size; /* 0x1C */
489 nt_hbin_sub hbin_sub; /* 0x20 */
490 } nt_hbin;
493 * the value_list consists of offsets to the values (vk)
495 typedef struct
497 WORD SubBlockId; /* 0x00 0x6B6E */
498 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
499 FILETIME writetime; /* 0x04 */
500 DWORD uk1; /* 0x0C */
501 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
502 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
503 DWORD uk8; /* 0x18 */
504 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
505 DWORD uk2; /* 0x20 */
506 DWORD nr_values; /* 0x24 number of values */
507 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
508 DWORD off_sk; /* 0x2c Offset of the sk-Record */
509 DWORD off_class; /* 0x30 Offset of the Class-Name */
510 DWORD uk3; /* 0x34 */
511 DWORD uk4; /* 0x38 */
512 DWORD uk5; /* 0x3c */
513 DWORD uk6; /* 0x40 */
514 DWORD uk7; /* 0x44 */
515 WORD name_len; /* 0x48 name-length */
516 WORD class_len; /* 0x4a class-name length */
517 char name[1]; /* 0x4c key-name */
518 } nt_nk;
520 typedef struct
522 DWORD off_nk; /* 0x00 */
523 DWORD name; /* 0x04 */
524 } hash_rec;
526 typedef struct
528 WORD id; /* 0x00 0x666c */
529 WORD nr_keys; /* 0x06 */
530 hash_rec hash_rec[1];
531 } nt_lf;
534 list of subkeys without hash
536 li --+-->nk
538 +-->nk
540 typedef struct
542 WORD id; /* 0x00 0x696c */
543 WORD nr_keys;
544 DWORD off_nk[1];
545 } nt_li;
548 this is a intermediate node
550 ri --+-->li--+-->nk
552 | +-->nk
554 +-->li--+-->nk
556 +-->nk
558 typedef struct
560 WORD id; /* 0x00 0x6972 */
561 WORD nr_li; /* 0x02 number off offsets */
562 DWORD off_li[1]; /* 0x04 points to li */
563 } nt_ri;
565 typedef struct
567 WORD id; /* 0x00 'vk' */
568 WORD nam_len;
569 DWORD data_len;
570 DWORD data_off;
571 DWORD type;
572 WORD flag;
573 WORD uk1;
574 char name[1];
575 } nt_vk;
577 LPSTR _strdupnA( LPCSTR str, int len )
579 LPSTR ret;
581 if (!str) return NULL;
582 ret = xmalloc( len + 1 );
583 memcpy( ret, str, len );
584 ret[len] = 0x00;
585 return ret;
588 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
589 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
590 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
594 * gets a value
596 * vk->flag:
597 * 0 value is a default value
598 * 1 the value has a name
600 * vk->data_len
601 * len of the whole data block
602 * - reg_sz (unicode)
603 * bytes including the terminating \0 = 2*(number_of_chars+1)
604 * - reg_dword, reg_binary:
605 * if highest bit of data_len is set data_off contains the value
607 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
609 WCHAR name [256];
610 DWORD len, ret;
611 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
613 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
615 if (!(len = MultiByteToWideChar( CP_ACP, 0, vk->name, vk->nam_len, name, 256 )) && vk->nam_len)
617 ERR("name too large '%.*s' (%d)\n", vk->nam_len, vk->name, vk->nam_len );
618 return FALSE;
620 name[len] = 0;
622 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
623 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
624 (vk->data_len & 0x7fffffff) );
625 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
626 return TRUE;
627 error:
628 ERR("unknown block found (0x%04x), please report!\n", vk->id);
629 return FALSE;
633 * get the subkeys
635 * this structure contains the hash of a keyname and points to all
636 * subkeys
638 * exception: if the id is 'il' there are no hash values and every
639 * dword is a offset
641 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
643 int i;
645 if (lf->id == NT_REG_HASH_BLOCK_ID)
647 if (subkeys != lf->nr_keys) goto error1;
649 for (i=0; i<lf->nr_keys; i++)
651 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
654 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
656 nt_li * li = (nt_li*)lf;
657 if (subkeys != li->nr_keys) goto error1;
659 for (i=0; i<li->nr_keys; i++)
661 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
664 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
666 nt_ri * ri = (nt_ri*)lf;
667 int li_subkeys = 0;
669 /* count all subkeys */
670 for (i=0; i<ri->nr_li; i++)
672 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
673 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
674 li_subkeys += li->nr_keys;
677 /* check number */
678 if (subkeys != li_subkeys) goto error1;
680 /* loop through the keys */
681 for (i=0; i<ri->nr_li; i++)
683 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
684 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
687 else
689 goto error2;
691 return TRUE;
693 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
694 return TRUE;
696 error1: ERR("registry file corrupt! (inconsistent number of subkeys)\n");
697 return FALSE;
699 error: ERR("error reading lf block\n");
700 return FALSE;
703 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
705 char * name;
706 int i;
707 DWORD * vl;
708 HKEY subkey = hkey;
710 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
712 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
713 goto error;
716 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
717 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
719 ERR("registry file corrupt!\n");
720 goto error;
723 /* create the new key */
724 if(level <= 0)
726 name = _strdupnA( nk->name, nk->name_len);
727 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
728 free(name);
731 /* loop through the subkeys */
732 if (nk->nr_subkeys)
734 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
735 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
738 /* loop trough the value list */
739 vl = (DWORD *)(base+nk->valuelist_off+4);
740 for (i=0; i<nk->nr_values; i++)
742 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
743 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
746 RegCloseKey(subkey);
747 return TRUE;
749 error1: RegCloseKey(subkey);
750 error: return FALSE;
753 /* end nt loader */
755 /* windows 95 registry loader */
757 /* SECTION 1: main header
759 * once at offset 0
761 #define W95_REG_CREG_ID 0x47455243
763 typedef struct
765 DWORD id; /* "CREG" = W95_REG_CREG_ID */
766 DWORD version; /* ???? 0x00010000 */
767 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
768 DWORD uk2; /* 0x0c */
769 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
770 WORD uk3;
771 DWORD uk[3];
772 /* rgkn */
773 } _w95creg;
775 /* SECTION 2: Directory information (tree structure)
777 * once on offset 0x20
779 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
781 #define W95_REG_RGKN_ID 0x4e4b4752
783 typedef struct
785 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
786 DWORD size; /* Size of the RGKN-block */
787 DWORD root_off; /* Rel. Offset of the root-record */
788 DWORD uk[5];
789 } _w95rgkn;
791 /* Disk Key Entry Structure
793 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
794 * hive itself. It looks the same like other keys. Even the ID-number can
795 * be any value.
797 * The "hash"-value is a value representing the key's name. Windows will not
798 * search for the name, but for a matching hash-value. if it finds one, it
799 * will compare the actual string info, otherwise continue with the next key.
800 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
801 * of the string which are smaller than 0x80 (128) to this D-Word.
803 * If you want to modify key names, also modify the hash-values, since they
804 * cannot be found again (although they would be displayed in REGEDIT)
805 * End of list-pointers are filled with 0xFFFFFFFF
807 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
808 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
809 * structure) and reading another RGDB_section.
811 * there is a one to one relationship between dke and dkh
813 /* key struct, once per key */
814 typedef struct
816 DWORD x1; /* Free entry indicator(?) */
817 DWORD hash; /* sum of bytes of keyname */
818 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
819 DWORD prevlvl; /* offset of previous key */
820 DWORD nextsub; /* offset of child key */
821 DWORD next; /* offset of sibling key */
822 WORD nrLS; /* id inside the rgdb block */
823 WORD nrMS; /* number of the rgdb block */
824 } _w95dke;
826 /* SECTION 3: key information, values and data
828 * structure:
829 * section: [blocks]* (repeat creg->rgdb_num times)
830 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
831 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
833 * An interesting relationship exists in RGDB_section. The value at offset
834 * 10 equals the value at offset 4 minus the value at offset 8. I have no
835 * idea at the moment what this means. (Kevin Cozens)
838 /* block header, once per block */
839 #define W95_REG_RGDB_ID 0x42444752
841 typedef struct
843 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
844 DWORD size; /* 0x04 */
845 DWORD uk1; /* 0x08 */
846 DWORD uk2; /* 0x0c */
847 DWORD uk3; /* 0x10 */
848 DWORD uk4; /* 0x14 */
849 DWORD uk5; /* 0x18 */
850 DWORD uk6; /* 0x1c */
851 /* dkh */
852 } _w95rgdb;
854 /* Disk Key Header structure (RGDB part), once per key */
855 typedef struct
857 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
858 WORD nrLS; /* 0x04 id inside the rgdb block */
859 WORD nrMS; /* 0x06 number of the rgdb block */
860 DWORD bytesused; /* 0x08 */
861 WORD keynamelen; /* 0x0c len of name */
862 WORD values; /* 0x0e number of values */
863 DWORD xx1; /* 0x10 */
864 char name[1]; /* 0x14 */
865 /* dkv */ /* 0x14 + keynamelen */
866 } _w95dkh;
868 /* Disk Key Value structure, once per value */
869 typedef struct
871 DWORD type; /* 0x00 */
872 DWORD x1; /* 0x04 */
873 WORD valnamelen; /* 0x08 length of name, 0 is default key */
874 WORD valdatalen; /* 0x0A length of data */
875 char name[1]; /* 0x0c */
876 /* raw data */ /* 0x0c + valnamelen */
877 } _w95dkv;
879 /******************************************************************************
880 * _w95_lookup_dkh [Internal]
882 * seeks the dkh belonging to a dke
884 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
886 _w95rgdb * rgdb;
887 _w95dkh * dkh;
888 int i;
890 /* get the beginning of the rgdb datastore */
891 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
893 /* check: requested block < last_block) */
894 if (creg->rgdb_num <= nrMS)
896 ERR("registry file corrupt! requested block no. beyond end.\n");
897 goto error;
900 /* find the right block */
901 for(i=0; i<nrMS ;i++)
903 if(rgdb->id != W95_REG_RGDB_ID) /* check the magic */
905 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
906 goto error;
908 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
911 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
915 if(nrLS==dkh->nrLS ) return dkh;
916 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
917 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
919 error: return NULL;
922 /******************************************************************************
923 * _w95_parse_dkv [Internal]
925 static int _w95_parse_dkv (
926 HKEY hkey,
927 _w95dkh * dkh,
928 int nrLS,
929 int nrMS )
931 _w95dkv * dkv;
932 int i;
933 DWORD ret;
934 char * name;
936 /* first value block */
937 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
939 /* loop trought the values */
940 for (i=0; i< dkh->values; i++)
942 name = _strdupnA(dkv->name, dkv->valnamelen);
943 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
944 if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
945 free (name);
947 /* next value */
948 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
950 return TRUE;
953 /******************************************************************************
954 * _w95_parse_dke [Internal]
956 static int _w95_parse_dke(
957 HKEY hkey,
958 _w95creg * creg,
959 _w95rgkn *rgkn,
960 _w95dke * dke,
961 int level )
963 _w95dkh * dkh;
964 HKEY hsubkey = hkey;
965 char * name;
966 int ret = FALSE;
968 /* get start address of root key block */
969 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
971 /* special root key */
972 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
974 /* parse the one subkey*/
975 if (dke->nextsub != 0xffffffff)
977 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
979 /* has no sibling keys */
980 goto error;
983 /* search subblock */
984 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
986 fprintf(stderr, "dke pointing to missing dkh !\n");
987 goto error;
990 if ( level <= 0 )
992 /* walk sibling keys */
993 if (dke->next != 0xffffffff )
995 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
998 /* create subkey and insert values */
999 name = _strdupnA( dkh->name, dkh->keynamelen);
1000 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1001 free(name);
1002 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1005 /* next sub key */
1006 if (dke->nextsub != 0xffffffff)
1008 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1011 ret = TRUE;
1012 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1013 error: return ret;
1015 /* end windows 95 loader */
1017 /******************************************************************************
1018 * NativeRegLoadKey [Internal]
1020 * Loads a native registry file (win95/nt)
1021 * hkey root key
1022 * fn filename
1023 * level number of levels to cut away (eg. ".Default" in user.dat)
1025 * this function intentionally uses unix file functions to make it possible
1026 * to move it to a seperate registry helper programm
1028 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1030 int fd = 0;
1031 struct stat st;
1032 DOS_FULL_NAME full_name;
1033 int ret = FALSE;
1034 void * base;
1036 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1038 /* map the registry into the memory */
1039 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1040 if ((fstat(fd, &st) == -1)) goto error;
1041 if (!st.st_size) goto error;
1042 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1044 switch (*(LPDWORD)base)
1046 /* windows 95 'creg' */
1047 case W95_REG_CREG_ID:
1049 _w95creg * creg;
1050 _w95rgkn * rgkn;
1051 creg = base;
1052 TRACE("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1054 /* load the header (rgkn) */
1055 rgkn = (_w95rgkn*)(creg + 1);
1056 if (rgkn->id != W95_REG_RGKN_ID)
1058 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1059 goto error1;
1062 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1064 break;
1065 /* nt 'regf'*/
1066 case NT_REG_HEADER_BLOCK_ID:
1068 nt_regf * regf;
1069 nt_hbin * hbin;
1070 nt_hbin_sub * hbin_sub;
1071 nt_nk* nk;
1073 TRACE("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1075 /* start block */
1076 regf = base;
1078 /* hbin block */
1079 hbin = (nt_hbin*)((char*) base + 0x1000);
1080 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1082 ERR( "%s hbin block invalid\n", fn);
1083 goto error1;
1086 /* hbin_sub block */
1087 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1088 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1090 ERR( "%s hbin_sub block invalid\n", fn);
1091 goto error1;
1094 /* nk block */
1095 nk = (nt_nk*)&(hbin_sub->data[0]);
1096 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1098 ERR( "%s special nk block not found\n", fn);
1099 goto error1;
1102 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1104 break;
1105 default:
1107 ERR("unknown signature in registry file %s.\n",fn);
1108 goto error1;
1111 if(!ret) ERR("error loading registry file %s\n", fn);
1112 error1: munmap(base, st.st_size);
1113 error: close(fd);
1114 return ret;
1117 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1119 reghack - windows 3.11 registry data format demo program.
1121 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1122 a combined hash table and tree description, and finally a text table.
1124 The header is obvious from the struct header. The taboff1 and taboff2
1125 fields are always 0x20, and their usage is unknown.
1127 The 8-byte entry table has various entry types.
1129 tabent[0] is a root index. The second word has the index of the root of
1130 the directory.
1131 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1132 the index of the key/value that has that hash. Data with the same
1133 hash value are on a circular list. The other three words in the
1134 hash entry are always zero.
1135 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1136 entry: dirent and keyent/valent. They are identified by context.
1137 tabent[freeidx] is the first free entry. The first word in a free entry
1138 is the index of the next free entry. The last has 0 as a link.
1139 The other three words in the free list are probably irrelevant.
1141 Entries in text table are preceeded by a word at offset-2. This word
1142 has the value (2*index)+1, where index is the referring keyent/valent
1143 entry in the table. I have no suggestion for the 2* and the +1.
1144 Following the word, there are N bytes of data, as per the keyent/valent
1145 entry length. The offset of the keyent/valent entry is from the start
1146 of the text table to the first data byte.
1148 This information is not available from Microsoft. The data format is
1149 deduced from the reg.dat file by me. Mistakes may
1150 have been made. I claim no rights and give no guarantees for this program.
1152 Tor Sjøwall, tor@sn.no
1155 /* reg.dat header format */
1156 struct _w31_header {
1157 char cookie[8]; /* 'SHCC3.10' */
1158 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1159 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1160 unsigned long tabcnt; /* number of entries in index table */
1161 unsigned long textoff; /* offset of text part */
1162 unsigned long textsize; /* byte size of text part */
1163 unsigned short hashsize; /* hash size */
1164 unsigned short freeidx; /* free index */
1167 /* generic format of table entries */
1168 struct _w31_tabent {
1169 unsigned short w0, w1, w2, w3;
1172 /* directory tabent: */
1173 struct _w31_dirent {
1174 unsigned short sibling_idx; /* table index of sibling dirent */
1175 unsigned short child_idx; /* table index of child dirent */
1176 unsigned short key_idx; /* table index of key keyent */
1177 unsigned short value_idx; /* table index of value valent */
1180 /* key tabent: */
1181 struct _w31_keyent {
1182 unsigned short hash_idx; /* hash chain index for string */
1183 unsigned short refcnt; /* reference count */
1184 unsigned short length; /* length of string */
1185 unsigned short string_off; /* offset of string in text table */
1188 /* value tabent: */
1189 struct _w31_valent {
1190 unsigned short hash_idx; /* hash chain index for string */
1191 unsigned short refcnt; /* reference count */
1192 unsigned short length; /* length of string */
1193 unsigned short string_off; /* offset of string in text table */
1196 /* recursive helper function to display a directory tree */
1197 void
1198 __w31_dumptree( unsigned short idx,
1199 unsigned char *txt,
1200 struct _w31_tabent *tab,
1201 struct _w31_header *head,
1202 HKEY hkey,
1203 time_t lastmodified,
1204 int level
1206 struct _w31_dirent *dir;
1207 struct _w31_keyent *key;
1208 struct _w31_valent *val;
1209 HKEY subkey = 0;
1210 static char tail[400];
1212 while (idx!=0) {
1213 dir=(struct _w31_dirent*)&tab[idx];
1215 if (dir->key_idx) {
1216 key = (struct _w31_keyent*)&tab[dir->key_idx];
1218 memcpy(tail,&txt[key->string_off],key->length);
1219 tail[key->length]='\0';
1220 /* all toplevel entries AND the entries in the
1221 * toplevel subdirectory belong to \SOFTWARE\Classes
1223 if (!level && !strcmp(tail,".classes")) {
1224 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1225 idx=dir->sibling_idx;
1226 continue;
1228 if (subkey) RegCloseKey( subkey );
1229 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1230 /* only add if leaf node or valued node */
1231 if (dir->value_idx!=0||dir->child_idx==0) {
1232 if (dir->value_idx) {
1233 val=(struct _w31_valent*)&tab[dir->value_idx];
1234 memcpy(tail,&txt[val->string_off],val->length);
1235 tail[val->length]='\0';
1236 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1239 } else {
1240 TRACE("strange: no directory key name, idx=%04x\n", idx);
1242 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1243 idx=dir->sibling_idx;
1245 if (subkey) RegCloseKey( subkey );
1249 /******************************************************************************
1250 * _w31_loadreg [Internal]
1252 void _w31_loadreg(void) {
1253 HFILE hf;
1254 struct _w31_header head;
1255 struct _w31_tabent *tab;
1256 unsigned char *txt;
1257 int len;
1258 OFSTRUCT ofs;
1259 BY_HANDLE_FILE_INFORMATION hfinfo;
1260 time_t lastmodified;
1262 TRACE("(void)\n");
1264 hf = OpenFile("reg.dat",&ofs,OF_READ);
1265 if (hf==HFILE_ERROR)
1266 return;
1268 /* read & dump header */
1269 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1270 ERR("reg.dat is too short.\n");
1271 _lclose(hf);
1272 return;
1274 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1275 ERR("reg.dat has bad signature.\n");
1276 _lclose(hf);
1277 return;
1280 len = head.tabcnt * sizeof(struct _w31_tabent);
1281 /* read and dump index table */
1282 tab = xmalloc(len);
1283 if (len!=_lread(hf,tab,len)) {
1284 ERR("couldn't read %d bytes.\n",len);
1285 free(tab);
1286 _lclose(hf);
1287 return;
1290 /* read text */
1291 txt = xmalloc(head.textsize);
1292 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1293 ERR("couldn't seek to textblock.\n");
1294 free(tab);
1295 free(txt);
1296 _lclose(hf);
1297 return;
1299 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1300 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1301 free(tab);
1302 free(txt);
1303 _lclose(hf);
1304 return;
1307 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1308 ERR("GetFileInformationByHandle failed?.\n");
1309 free(tab);
1310 free(txt);
1311 _lclose(hf);
1312 return;
1314 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1315 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1316 free(tab);
1317 free(txt);
1318 _lclose(hf);
1319 return;
1323 /* configure save files and start the periodic saving timer */
1324 static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
1326 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1327 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1329 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1330 SERVER_START_REQ
1332 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1333 req->current = 1;
1334 req->saving = !all;
1335 req->period = period * 1000;
1336 server_call( REQ_SET_REGISTRY_LEVELS );
1338 SERVER_END_REQ;
1340 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1342 struct save_registry_atexit_request *req = get_req_buffer();
1343 const char *confdir = get_config_dir();
1344 char *str = req->file + strlen(confdir);
1346 if (str + 20 > req->file + server_remaining(req->file))
1348 ERR("config dir '%s' too long\n", confdir );
1349 return;
1352 strcpy( req->file, confdir );
1353 strcpy( str, "/" SAVE_CURRENT_USER );
1354 req->hkey = HKEY_CURRENT_USER;
1355 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1357 strcpy( req->file, confdir );
1358 strcpy( str, "/" SAVE_LOCAL_MACHINE );
1359 req->hkey = HKEY_LOCAL_MACHINE;
1360 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1362 strcpy( req->file, confdir );
1363 strcpy( str, "/" SAVE_DEFAULT_USER );
1364 req->hkey = hkey_users_default;
1365 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1367 strcpy( req->file, confdir );
1368 strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1369 req->hkey = HKEY_USERS;
1370 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1375 /**********************************************************************************
1376 * SetLoadLevel [Internal]
1378 * set level to 0 for loading system files
1379 * set level to 1 for loading user files
1381 static void SetLoadLevel(int level)
1383 SERVER_START_REQ
1385 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1387 req->current = level;
1388 req->saving = 0;
1389 req->period = 0;
1390 server_call( REQ_SET_REGISTRY_LEVELS );
1392 SERVER_END_REQ;
1395 /**********************************************************************************
1396 * SHELL_LoadRegistry [Internal]
1398 #define REG_DONTLOAD -1
1399 #define REG_WIN31 0
1400 #define REG_WIN95 1
1401 #define REG_WINNT 2
1403 void SHELL_LoadRegistry( void )
1405 HKEY hkey;
1406 char windir[MAX_PATHNAME_LEN];
1407 char path[MAX_PATHNAME_LEN];
1408 int systemtype = REG_WIN31;
1409 HKEY hkey_users_default;
1411 TRACE("(void)\n");
1413 if (!CLIENT_IsBootThread()) return; /* already loaded */
1415 REGISTRY_Init();
1416 SetLoadLevel(0);
1418 if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default))
1419 hkey_users_default = 0;
1421 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1423 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1425 /* test %windir%/system32/config/system --> winnt */
1426 strcpy(path, windir);
1427 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1428 if(GetFileAttributesA(path) != -1)
1430 systemtype = REG_WINNT;
1432 else
1434 /* test %windir%/system.dat --> win95 */
1435 strcpy(path, windir);
1436 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1437 if(GetFileAttributesA(path) != -1)
1439 systemtype = REG_WIN95;
1443 if ((systemtype==REG_WINNT)
1444 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1446 MESSAGE("When you are running with a native NT directory specify\n");
1447 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1448 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1449 systemtype = REG_DONTLOAD;
1452 else
1454 /* only wine registry */
1455 systemtype = REG_DONTLOAD;
1458 switch (systemtype)
1460 case REG_WIN31:
1461 _w31_loadreg();
1462 break;
1464 case REG_WIN95:
1465 /* Load windows 95 entries */
1466 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1468 strcpy(path, windir);
1469 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1470 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1472 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1474 /* user specific user.dat */
1475 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1476 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1478 MESSAGE("can't load win95 user-registry %s\n", path);
1479 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1481 /* default user.dat */
1482 if (hkey_users_default)
1484 strcpy(path, windir);
1485 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1486 NativeRegLoadKey(hkey_users_default, path, 1);
1489 else
1491 /* global user.dat */
1492 strcpy(path, windir);
1493 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1494 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1496 break;
1498 case REG_WINNT:
1499 /* default user.dat */
1500 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1502 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1503 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1505 MESSAGE("can't load NT user-registry %s\n", path);
1506 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1510 /* default user.dat */
1511 if (hkey_users_default)
1513 strcpy(path, windir);
1514 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1515 NativeRegLoadKey(hkey_users_default, path, 1);
1519 * FIXME
1520 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1523 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1525 strcpy(path, windir);
1526 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1527 NativeRegLoadKey(hkey, path, 1);
1528 RegCloseKey(hkey);
1531 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1533 strcpy(path, windir);
1534 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1535 NativeRegLoadKey(hkey, path, 1);
1536 RegCloseKey(hkey);
1539 strcpy(path, windir);
1540 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1541 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1543 strcpy(path, windir);
1544 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1545 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1547 /* this key is generated when the nt-core booted successfully */
1548 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1549 RegCloseKey(hkey);
1550 break;
1551 } /* switch */
1553 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1556 * Load the global HKU hive directly from sysconfdir
1558 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1561 * Load the global machine defaults directly from sysconfdir
1563 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1566 SetLoadLevel(1);
1569 * Load the user saved registries
1571 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1573 const char *confdir = get_config_dir();
1574 int len = strlen(confdir) + 20;
1575 char *fn = path;
1577 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1579 * Load user's personal versions of global HKU/.Default keys
1581 if (fn)
1583 char *str;
1584 strcpy( fn, confdir );
1585 str = fn + strlen(fn);
1586 *str++ = '/';
1588 /* try to load HKU\.Default key only */
1589 strcpy( str, SAVE_DEFAULT_USER );
1590 if (_wine_loadreg( hkey_users_default, fn ))
1592 /* if not found load old file containing both HKU\.Default and HKU\user */
1593 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1594 _wine_loadreg( HKEY_USERS, fn );
1597 strcpy( str, SAVE_CURRENT_USER );
1598 _wine_loadreg( HKEY_CURRENT_USER, fn );
1600 strcpy( str, SAVE_LOCAL_MACHINE );
1601 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1603 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1606 SHELL_InitRegistrySaving( hkey_users_default );
1607 RegCloseKey( hkey_users_default );
1610 /********************* API FUNCTIONS ***************************************/
1615 /******************************************************************************
1616 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1617 * Immediately writes key to registry.
1618 * Only returns after data has been written to disk.
1620 * FIXME: does it really wait until data is written ?
1622 * PARAMS
1623 * hkey [I] Handle of key to write
1625 * RETURNS
1626 * Success: ERROR_SUCCESS
1627 * Failure: Error code
1629 DWORD WINAPI RegFlushKey( HKEY hkey )
1631 FIXME( "(%x): stub\n", hkey );
1632 return ERROR_SUCCESS;
1635 /******************************************************************************
1636 * RegConnectRegistryW [ADVAPI32.128]
1638 * PARAMS
1639 * lpMachineName [I] Address of name of remote computer
1640 * hHey [I] Predefined registry handle
1641 * phkResult [I] Address of buffer for remote registry handle
1643 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1644 LPHKEY phkResult )
1646 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1648 if (!lpMachineName || !*lpMachineName) {
1649 /* Use the local machine name */
1650 return RegOpenKey16( hKey, "", phkResult );
1653 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1654 return ERROR_BAD_NETPATH;
1658 /******************************************************************************
1659 * RegConnectRegistryA [ADVAPI32.127]
1661 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1663 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1664 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1665 HeapFree( GetProcessHeap(), 0, machineW );
1666 return ret;
1670 /******************************************************************************
1671 * RegGetKeySecurity [ADVAPI32.144]
1672 * Retrieves a copy of security descriptor protecting the registry key
1674 * PARAMS
1675 * hkey [I] Open handle of key to set
1676 * SecurityInformation [I] Descriptor contents
1677 * pSecurityDescriptor [O] Address of descriptor for key
1678 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1680 * RETURNS
1681 * Success: ERROR_SUCCESS
1682 * Failure: Error code
1684 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1685 SECURITY_INFORMATION SecurityInformation,
1686 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1687 LPDWORD lpcbSecurityDescriptor )
1689 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1690 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1692 /* FIXME: Check for valid SecurityInformation values */
1694 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1695 return ERROR_INSUFFICIENT_BUFFER;
1697 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1698 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1700 return ERROR_SUCCESS;
1704 /******************************************************************************
1705 * RegNotifyChangeKeyValue [ADVAPI32.???]
1707 * PARAMS
1708 * hkey [I] Handle of key to watch
1709 * fWatchSubTree [I] Flag for subkey notification
1710 * fdwNotifyFilter [I] Changes to be reported
1711 * hEvent [I] Handle of signaled event
1712 * fAsync [I] Flag for asynchronous reporting
1714 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1715 DWORD fdwNotifyFilter, HANDLE hEvent,
1716 BOOL fAsync )
1718 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1719 hEvent,fAsync);
1720 return ERROR_SUCCESS;
1724 /******************************************************************************
1725 * RegUnLoadKeyW [ADVAPI32.173]
1727 * PARAMS
1728 * hkey [I] Handle of open key
1729 * lpSubKey [I] Address of name of subkey to unload
1731 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1733 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1734 return ERROR_SUCCESS;
1738 /******************************************************************************
1739 * RegUnLoadKeyA [ADVAPI32.172]
1741 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1743 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1744 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1745 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1746 return ret;
1750 /******************************************************************************
1751 * RegSetKeySecurity [ADVAPI32.167]
1753 * PARAMS
1754 * hkey [I] Open handle of key to set
1755 * SecurityInfo [I] Descriptor contents
1756 * pSecurityDesc [I] Address of descriptor for key
1758 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1759 PSECURITY_DESCRIPTOR pSecurityDesc )
1761 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1763 /* It seems to perform this check before the hkey check */
1764 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1765 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1766 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1767 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1768 /* Param OK */
1769 } else
1770 return ERROR_INVALID_PARAMETER;
1772 if (!pSecurityDesc)
1773 return ERROR_INVALID_PARAMETER;
1775 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1777 return ERROR_SUCCESS;
1781 /******************************************************************************
1782 * RegRestoreKeyW [ADVAPI32.164]
1784 * PARAMS
1785 * hkey [I] Handle of key where restore begins
1786 * lpFile [I] Address of filename containing saved tree
1787 * dwFlags [I] Optional flags
1789 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1791 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1793 /* It seems to do this check before the hkey check */
1794 if (!lpFile || !*lpFile)
1795 return ERROR_INVALID_PARAMETER;
1797 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1799 /* Check for file existence */
1801 return ERROR_SUCCESS;
1805 /******************************************************************************
1806 * RegRestoreKeyA [ADVAPI32.163]
1808 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1810 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1811 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1812 HeapFree( GetProcessHeap(), 0, lpFileW );
1813 return ret;
1817 /******************************************************************************
1818 * RegReplaceKeyW [ADVAPI32.162]
1820 * PARAMS
1821 * hkey [I] Handle of open key
1822 * lpSubKey [I] Address of name of subkey
1823 * lpNewFile [I] Address of filename for file with new data
1824 * lpOldFile [I] Address of filename for backup file
1826 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1827 LPCWSTR lpOldFile )
1829 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1830 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1831 return ERROR_SUCCESS;
1835 /******************************************************************************
1836 * RegReplaceKeyA [ADVAPI32.161]
1838 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1839 LPCSTR lpOldFile )
1841 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1842 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1843 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1844 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1845 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1846 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1847 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1848 return ret;
1856 /* 16-bit functions */
1858 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1859 * some programs. Do not remove those cases. -MM
1861 static inline void fix_win16_hkey( HKEY *hkey )
1863 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1866 /******************************************************************************
1867 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1869 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1871 fix_win16_hkey( &hkey );
1872 return RegEnumKeyA( hkey, index, name, name_len );
1875 /******************************************************************************
1876 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1878 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1880 fix_win16_hkey( &hkey );
1881 return RegOpenKeyA( hkey, name, retkey );
1884 /******************************************************************************
1885 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1887 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1889 fix_win16_hkey( &hkey );
1890 return RegCreateKeyA( hkey, name, retkey );
1893 /******************************************************************************
1894 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1896 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1898 fix_win16_hkey( &hkey );
1899 return RegDeleteKeyA( hkey, name );
1902 /******************************************************************************
1903 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1905 DWORD WINAPI RegCloseKey16( HKEY hkey )
1907 fix_win16_hkey( &hkey );
1908 return RegCloseKey( hkey );
1911 /******************************************************************************
1912 * RegSetValue16 [KERNEL.221] [SHELL.5]
1914 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1916 fix_win16_hkey( &hkey );
1917 return RegSetValueA( hkey, name, type, data, count );
1920 /******************************************************************************
1921 * RegDeleteValue16 [KERNEL.222]
1923 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1925 fix_win16_hkey( &hkey );
1926 return RegDeleteValueA( hkey, name );
1929 /******************************************************************************
1930 * RegEnumValue16 [KERNEL.223]
1932 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1933 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1935 fix_win16_hkey( &hkey );
1936 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1939 /******************************************************************************
1940 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1942 * NOTES
1943 * Is this HACK still applicable?
1945 * HACK
1946 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1947 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1948 * Aldus FH4)
1950 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1952 fix_win16_hkey( &hkey );
1953 if (count) *count &= 0xffff;
1954 return RegQueryValueA( hkey, name, data, count );
1957 /******************************************************************************
1958 * RegQueryValueEx16 [KERNEL.225]
1960 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1961 LPBYTE data, LPDWORD count )
1963 fix_win16_hkey( &hkey );
1964 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1967 /******************************************************************************
1968 * RegSetValueEx16 [KERNEL.226]
1970 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1971 CONST BYTE *data, DWORD count )
1973 fix_win16_hkey( &hkey );
1974 return RegSetValueExA( hkey, name, reserved, type, data, count );