Added middle mouse button handling.
[wine/multimedia.git] / misc / registry.c
blob7d9117ef36649a4a1c3dafeffd9004ac380380d2
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 SERVER_START_REQ
385 struct load_registry_request *req = server_alloc_req( sizeof(*req), 0 );
386 req->hkey = hkey;
387 req->file = file;
388 server_call( REQ_LOAD_REGISTRY );
390 SERVER_END_REQ;
391 CloseHandle( file );
393 free( buf );
394 return 1;
396 else
398 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
399 free(buf);
400 return 0;
403 if (!_wine_read_line(F,&buf,&buflen)) {
404 free(buf);
405 return 0;
407 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
408 free(buf);
409 return 0;
411 free(buf);
412 return 1;
416 /******************************************************************************
417 * _wine_loadreg [Internal]
419 static int _wine_loadreg( HKEY hkey, char *fn )
421 FILE *F;
423 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
425 F = fopen(fn,"rb");
426 if (F==NULL) {
427 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
428 return -1;
430 _wine_loadsubreg(F,hkey,fn);
431 fclose(F);
432 return 0;
435 /* NT REGISTRY LOADER */
437 #ifdef HAVE_SYS_MMAN_H
438 # include <sys/mman.h>
439 #endif
441 #ifndef MAP_FAILED
442 #define MAP_FAILED ((LPVOID)-1)
443 #endif
445 #define NT_REG_BLOCK_SIZE 0x1000
447 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
448 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
449 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
450 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
452 /* subblocks of nk */
453 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
454 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
455 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
457 #define NT_REG_KEY_BLOCK_TYPE 0x20
458 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
460 typedef struct
462 DWORD id; /* 0x66676572 'regf'*/
463 DWORD uk1; /* 0x04 */
464 DWORD uk2; /* 0x08 */
465 FILETIME DateModified; /* 0x0c */
466 DWORD uk3; /* 0x14 */
467 DWORD uk4; /* 0x18 */
468 DWORD uk5; /* 0x1c */
469 DWORD uk6; /* 0x20 */
470 DWORD RootKeyBlock; /* 0x24 */
471 DWORD BlockSize; /* 0x28 */
472 DWORD uk7[116];
473 DWORD Checksum; /* at offset 0x1FC */
474 } nt_regf;
476 typedef struct
478 DWORD blocksize;
479 BYTE data[1];
480 } nt_hbin_sub;
482 typedef struct
484 DWORD id; /* 0x6E696268 'hbin' */
485 DWORD off_prev;
486 DWORD off_next;
487 DWORD uk1;
488 DWORD uk2; /* 0x10 */
489 DWORD uk3; /* 0x14 */
490 DWORD uk4; /* 0x18 */
491 DWORD size; /* 0x1C */
492 nt_hbin_sub hbin_sub; /* 0x20 */
493 } nt_hbin;
496 * the value_list consists of offsets to the values (vk)
498 typedef struct
500 WORD SubBlockId; /* 0x00 0x6B6E */
501 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
502 FILETIME writetime; /* 0x04 */
503 DWORD uk1; /* 0x0C */
504 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
505 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
506 DWORD uk8; /* 0x18 */
507 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
508 DWORD uk2; /* 0x20 */
509 DWORD nr_values; /* 0x24 number of values */
510 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
511 DWORD off_sk; /* 0x2c Offset of the sk-Record */
512 DWORD off_class; /* 0x30 Offset of the Class-Name */
513 DWORD uk3; /* 0x34 */
514 DWORD uk4; /* 0x38 */
515 DWORD uk5; /* 0x3c */
516 DWORD uk6; /* 0x40 */
517 DWORD uk7; /* 0x44 */
518 WORD name_len; /* 0x48 name-length */
519 WORD class_len; /* 0x4a class-name length */
520 char name[1]; /* 0x4c key-name */
521 } nt_nk;
523 typedef struct
525 DWORD off_nk; /* 0x00 */
526 DWORD name; /* 0x04 */
527 } hash_rec;
529 typedef struct
531 WORD id; /* 0x00 0x666c */
532 WORD nr_keys; /* 0x06 */
533 hash_rec hash_rec[1];
534 } nt_lf;
537 list of subkeys without hash
539 li --+-->nk
541 +-->nk
543 typedef struct
545 WORD id; /* 0x00 0x696c */
546 WORD nr_keys;
547 DWORD off_nk[1];
548 } nt_li;
551 this is a intermediate node
553 ri --+-->li--+-->nk
555 | +-->nk
557 +-->li--+-->nk
559 +-->nk
561 typedef struct
563 WORD id; /* 0x00 0x6972 */
564 WORD nr_li; /* 0x02 number off offsets */
565 DWORD off_li[1]; /* 0x04 points to li */
566 } nt_ri;
568 typedef struct
570 WORD id; /* 0x00 'vk' */
571 WORD nam_len;
572 DWORD data_len;
573 DWORD data_off;
574 DWORD type;
575 WORD flag;
576 WORD uk1;
577 char name[1];
578 } nt_vk;
580 LPSTR _strdupnA( LPCSTR str, int len )
582 LPSTR ret;
584 if (!str) return NULL;
585 ret = xmalloc( len + 1 );
586 memcpy( ret, str, len );
587 ret[len] = 0x00;
588 return ret;
591 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
592 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
593 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
597 * gets a value
599 * vk->flag:
600 * 0 value is a default value
601 * 1 the value has a name
603 * vk->data_len
604 * len of the whole data block
605 * - reg_sz (unicode)
606 * bytes including the terminating \0 = 2*(number_of_chars+1)
607 * - reg_dword, reg_binary:
608 * if highest bit of data_len is set data_off contains the value
610 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
612 WCHAR name [256];
613 DWORD len, ret;
614 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
616 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
618 if (!(len = MultiByteToWideChar( CP_ACP, 0, vk->name, vk->nam_len, name, 256 )) && vk->nam_len)
620 ERR("name too large '%.*s' (%d)\n", vk->nam_len, vk->name, vk->nam_len );
621 return FALSE;
623 name[len] = 0;
625 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
626 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
627 (vk->data_len & 0x7fffffff) );
628 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
629 return TRUE;
630 error:
631 ERR("unknown block found (0x%04x), please report!\n", vk->id);
632 return FALSE;
636 * get the subkeys
638 * this structure contains the hash of a keyname and points to all
639 * subkeys
641 * exception: if the id is 'il' there are no hash values and every
642 * dword is a offset
644 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
646 int i;
648 if (lf->id == NT_REG_HASH_BLOCK_ID)
650 if (subkeys != lf->nr_keys) goto error1;
652 for (i=0; i<lf->nr_keys; i++)
654 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
657 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
659 nt_li * li = (nt_li*)lf;
660 if (subkeys != li->nr_keys) goto error1;
662 for (i=0; i<li->nr_keys; i++)
664 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
667 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
669 nt_ri * ri = (nt_ri*)lf;
670 int li_subkeys = 0;
672 /* count all subkeys */
673 for (i=0; i<ri->nr_li; i++)
675 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
676 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
677 li_subkeys += li->nr_keys;
680 /* check number */
681 if (subkeys != li_subkeys) goto error1;
683 /* loop through the keys */
684 for (i=0; i<ri->nr_li; i++)
686 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
687 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
690 else
692 goto error2;
694 return TRUE;
696 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
697 return TRUE;
699 error1: ERR("registry file corrupt! (inconsistent number of subkeys)\n");
700 return FALSE;
702 error: ERR("error reading lf block\n");
703 return FALSE;
706 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
708 char * name;
709 unsigned int n;
710 DWORD * vl;
711 HKEY subkey = hkey;
713 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
715 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
716 goto error;
719 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
720 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
722 ERR("registry file corrupt!\n");
723 goto error;
726 /* create the new key */
727 if(level <= 0)
729 name = _strdupnA( nk->name, nk->name_len);
730 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
731 free(name);
734 /* loop through the subkeys */
735 if (nk->nr_subkeys)
737 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
738 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
741 /* loop trough the value list */
742 vl = (DWORD *)(base+nk->valuelist_off+4);
743 for (n=0; n<nk->nr_values; n++)
745 nt_vk * vk = (nt_vk*)(base+vl[n]+4);
746 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
749 /* Don't close the subkey if it is the hkey that was passed
750 * (i.e. Level was <= 0)
752 if( subkey!=hkey ) RegCloseKey(subkey);
753 return TRUE;
755 error1: RegCloseKey(subkey);
756 error: return FALSE;
759 /* end nt loader */
761 /* windows 95 registry loader */
763 /* SECTION 1: main header
765 * once at offset 0
767 #define W95_REG_CREG_ID 0x47455243
769 typedef struct
771 DWORD id; /* "CREG" = W95_REG_CREG_ID */
772 DWORD version; /* ???? 0x00010000 */
773 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
774 DWORD uk2; /* 0x0c */
775 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
776 WORD uk3;
777 DWORD uk[3];
778 /* rgkn */
779 } _w95creg;
781 /* SECTION 2: Directory information (tree structure)
783 * once on offset 0x20
785 * structure: [rgkn][dke]* (repeat till last_dke is reached)
787 #define W95_REG_RGKN_ID 0x4e4b4752
789 typedef struct
791 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
792 DWORD size; /* Size of the RGKN-block */
793 DWORD root_off; /* Rel. Offset of the root-record */
794 DWORD last_dke; /* Offset to last DKE ? */
795 DWORD uk[4];
796 } _w95rgkn;
798 /* Disk Key Entry Structure
800 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
801 * hive itself. It looks the same like other keys. Even the ID-number can
802 * be any value.
804 * The "hash"-value is a value representing the key's name. Windows will not
805 * search for the name, but for a matching hash-value. if it finds one, it
806 * will compare the actual string info, otherwise continue with the next key.
807 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
808 * of the string which are smaller than 0x80 (128) to this D-Word.
810 * If you want to modify key names, also modify the hash-values, since they
811 * cannot be found again (although they would be displayed in REGEDIT)
812 * End of list-pointers are filled with 0xFFFFFFFF
814 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
815 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
816 * structure) and reading another RGDB_section.
818 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
819 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
820 * The remaining space between last_dke and the offset calculated from
821 * rgkn->size seems to be free for use for more dke:s.
822 * So it seems if more dke:s are added, they are added to that space and
823 * last_dke is grown, and in case that "free" space is out, the space
824 * gets grown and rgkn->size gets adjusted.
826 * there is a one to one relationship between dke and dkh
828 /* key struct, once per key */
829 typedef struct
831 DWORD x1; /* Free entry indicator(?) */
832 DWORD hash; /* sum of bytes of keyname */
833 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
834 DWORD prevlvl; /* offset of previous key */
835 DWORD nextsub; /* offset of child key */
836 DWORD next; /* offset of sibling key */
837 WORD nrLS; /* id inside the rgdb block */
838 WORD nrMS; /* number of the rgdb block */
839 } _w95dke;
841 /* SECTION 3: key information, values and data
843 * structure:
844 * section: [blocks]* (repeat creg->rgdb_num times)
845 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
846 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
848 * An interesting relationship exists in RGDB_section. The DWORD value
849 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
850 * I have no idea at the moment what this means. (Kevin Cozens)
853 /* block header, once per block */
854 #define W95_REG_RGDB_ID 0x42444752
856 typedef struct
858 DWORD id; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
859 DWORD size; /* 0x04 */
860 DWORD uk1; /* 0x08 */
861 DWORD uk2; /* 0x0c */
862 DWORD uk3; /* 0x10 */
863 DWORD uk4; /* 0x14 */
864 DWORD uk5; /* 0x18 */
865 DWORD uk6; /* 0x1c */
866 /* dkh */
867 } _w95rgdb;
869 /* Disk Key Header structure (RGDB part), once per key */
870 typedef struct
872 DWORD nextkeyoff; /* 0x00 offset to next dkh */
873 WORD nrLS; /* 0x04 id inside the rgdb block */
874 WORD nrMS; /* 0x06 number of the rgdb block */
875 DWORD bytesused; /* 0x08 */
876 WORD keynamelen; /* 0x0c len of name */
877 WORD values; /* 0x0e number of values */
878 DWORD xx1; /* 0x10 */
879 char name[1]; /* 0x14 */
880 /* dkv */ /* 0x14 + keynamelen */
881 } _w95dkh;
883 /* Disk Key Value structure, once per value */
884 typedef struct
886 DWORD type; /* 0x00 */
887 DWORD x1; /* 0x04 */
888 WORD valnamelen; /* 0x08 length of name, 0 is default key */
889 WORD valdatalen; /* 0x0A length of data */
890 char name[1]; /* 0x0c */
891 /* raw data */ /* 0x0c + valnamelen */
892 } _w95dkv;
894 /******************************************************************************
895 * _w95_lookup_dkh [Internal]
897 * seeks the dkh belonging to a dke
899 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
901 _w95rgdb * rgdb;
902 _w95dkh * dkh;
903 int i;
905 /* get the beginning of the rgdb datastore */
906 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
908 /* check: requested block < last_block) */
909 if (creg->rgdb_num <= nrMS)
911 ERR("registry file corrupt! requested block no. beyond end.\n");
912 goto error;
915 /* find the right block */
916 for(i=0; i<nrMS ;i++)
918 if(rgdb->id != W95_REG_RGDB_ID) /* check the magic */
920 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
921 goto error;
923 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
926 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
930 if(nrLS==dkh->nrLS ) return dkh;
931 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
932 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
934 error: return NULL;
937 /******************************************************************************
938 * _w95_parse_dkv [Internal]
940 static int _w95_parse_dkv (
941 HKEY hkey,
942 _w95dkh * dkh,
943 int nrLS,
944 int nrMS )
946 _w95dkv * dkv;
947 int i;
948 DWORD ret;
949 char * name;
951 /* first value block */
952 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
954 /* loop trought the values */
955 for (i=0; i< dkh->values; i++)
957 name = _strdupnA(dkv->name, dkv->valnamelen);
958 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
959 if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
960 free (name);
962 /* next value */
963 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
965 return TRUE;
968 /******************************************************************************
969 * _w95_parse_dke [Internal]
971 static int _w95_parse_dke(
972 HKEY hkey,
973 _w95creg * creg,
974 _w95rgkn *rgkn,
975 _w95dke * dke,
976 int level )
978 _w95dkh * dkh;
979 HKEY hsubkey = hkey;
980 char * name;
981 int ret = FALSE;
983 /* special root key */
984 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
986 /* parse the one subkey */
987 if (dke->nextsub != 0xffffffff)
989 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
991 /* has no sibling keys */
992 goto error;
995 /* search subblock */
996 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
998 fprintf(stderr, "dke pointing to missing dkh !\n");
999 goto error;
1002 if ( level <= 0 )
1004 /* walk sibling keys */
1005 if (dke->next != 0xffffffff )
1007 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1010 /* create subkey and insert values */
1011 name = _strdupnA( dkh->name, dkh->keynamelen);
1012 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1013 free(name);
1014 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1017 /* next sub key */
1018 if (dke->nextsub != 0xffffffff)
1020 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1023 ret = TRUE;
1024 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1025 error: return ret;
1027 /* end windows 95 loader */
1029 /******************************************************************************
1030 * NativeRegLoadKey [Internal]
1032 * Loads a native registry file (win95/nt)
1033 * hkey root key
1034 * fn filename
1035 * level number of levels to cut away (eg. ".Default" in user.dat)
1037 * this function intentionally uses unix file functions to make it possible
1038 * to move it to a seperate registry helper programm
1040 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1042 int fd = 0;
1043 struct stat st;
1044 DOS_FULL_NAME full_name;
1045 int ret = FALSE;
1046 void * base;
1047 char *filetype = "unknown";
1049 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1051 /* map the registry into the memory */
1052 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1053 if ((fstat(fd, &st) == -1)) goto error;
1054 if (!st.st_size) goto error;
1055 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1057 switch (*(LPDWORD)base)
1059 /* windows 95 'CREG' */
1060 case W95_REG_CREG_ID:
1062 _w95creg *creg;
1063 _w95rgkn *rgkn;
1064 _w95dke *dke, *root_dke;
1065 creg = base;
1066 filetype = "win95";
1067 TRACE("Loading %s registry '%s' '%s'\n", filetype, fn, full_name.long_name);
1069 /* load the header (rgkn) */
1070 rgkn = (_w95rgkn*)(creg + 1);
1071 if (rgkn->id != W95_REG_RGKN_ID)
1073 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1074 goto error1;
1076 if (rgkn->root_off != 0x20)
1078 ERR("rgkn->root_off not 0x20, please report !\n");
1079 goto error1;
1081 if (rgkn->last_dke > rgkn->size)
1083 ERR("registry file corrupt! last_dke > size!\n");
1084 goto error1;
1086 /* verify last dke */
1087 dke = (_w95dke*)((char*)rgkn + rgkn->last_dke);
1088 if (dke->x1 != 0x80000000)
1089 { /* wrong magic */
1090 ERR("last dke invalid !\n");
1091 goto error1;
1093 if (rgkn->size > creg->rgdb_off)
1095 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1096 goto error1;
1098 root_dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
1099 if ( (root_dke->prevlvl != 0xffffffff)
1100 || (root_dke->next != 0xffffffff) )
1102 ERR("registry file corrupt! invalid root dke !\n");
1103 goto error1;
1106 ret = _w95_parse_dke(hkey, creg, rgkn, root_dke, level);
1108 break;
1109 /* nt 'regf'*/
1110 case NT_REG_HEADER_BLOCK_ID:
1112 nt_regf * regf;
1113 nt_hbin * hbin;
1114 nt_hbin_sub * hbin_sub;
1115 nt_nk* nk;
1117 filetype = "NT";
1118 TRACE("Loading %s registry '%s' '%s'\n", filetype, fn, full_name.long_name);
1120 /* start block */
1121 regf = base;
1123 /* hbin block */
1124 hbin = (nt_hbin*)((char*) base + 0x1000);
1125 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1127 ERR( "hbin block invalid\n");
1128 goto error1;
1131 /* hbin_sub block */
1132 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1133 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1135 ERR( "hbin_sub block invalid\n");
1136 goto error1;
1139 /* nk block */
1140 nk = (nt_nk*)&(hbin_sub->data[0]);
1141 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1143 ERR( "special nk block not found\n");
1144 goto error1;
1147 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1149 break;
1150 default:
1152 ERR("unknown registry signature !\n");
1153 goto error1;
1156 error1: if(!ret)
1158 ERR("error loading %s registry file %s\n",
1159 filetype, full_name.long_name);
1160 if (!strcmp(filetype, "win95"))
1161 ERR("Please report to a.mohr@mailto.de.\n");
1162 ERR("Make a backup of the file, run a good reg cleaner program and try again !\n");
1164 munmap(base, st.st_size);
1165 error: close(fd);
1166 return ret;
1169 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1171 reghack - windows 3.11 registry data format demo program.
1173 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1174 a combined hash table and tree description, and finally a text table.
1176 The header is obvious from the struct header. The taboff1 and taboff2
1177 fields are always 0x20, and their usage is unknown.
1179 The 8-byte entry table has various entry types.
1181 tabent[0] is a root index. The second word has the index of the root of
1182 the directory.
1183 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1184 the index of the key/value that has that hash. Data with the same
1185 hash value are on a circular list. The other three words in the
1186 hash entry are always zero.
1187 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1188 entry: dirent and keyent/valent. They are identified by context.
1189 tabent[freeidx] is the first free entry. The first word in a free entry
1190 is the index of the next free entry. The last has 0 as a link.
1191 The other three words in the free list are probably irrelevant.
1193 Entries in text table are preceeded by a word at offset-2. This word
1194 has the value (2*index)+1, where index is the referring keyent/valent
1195 entry in the table. I have no suggestion for the 2* and the +1.
1196 Following the word, there are N bytes of data, as per the keyent/valent
1197 entry length. The offset of the keyent/valent entry is from the start
1198 of the text table to the first data byte.
1200 This information is not available from Microsoft. The data format is
1201 deduced from the reg.dat file by me. Mistakes may
1202 have been made. I claim no rights and give no guarantees for this program.
1204 Tor Sjøwall, tor@sn.no
1207 /* reg.dat header format */
1208 struct _w31_header {
1209 char cookie[8]; /* 'SHCC3.10' */
1210 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1211 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1212 unsigned long tabcnt; /* number of entries in index table */
1213 unsigned long textoff; /* offset of text part */
1214 unsigned long textsize; /* byte size of text part */
1215 unsigned short hashsize; /* hash size */
1216 unsigned short freeidx; /* free index */
1219 /* generic format of table entries */
1220 struct _w31_tabent {
1221 unsigned short w0, w1, w2, w3;
1224 /* directory tabent: */
1225 struct _w31_dirent {
1226 unsigned short sibling_idx; /* table index of sibling dirent */
1227 unsigned short child_idx; /* table index of child dirent */
1228 unsigned short key_idx; /* table index of key keyent */
1229 unsigned short value_idx; /* table index of value valent */
1232 /* key tabent: */
1233 struct _w31_keyent {
1234 unsigned short hash_idx; /* hash chain index for string */
1235 unsigned short refcnt; /* reference count */
1236 unsigned short length; /* length of string */
1237 unsigned short string_off; /* offset of string in text table */
1240 /* value tabent: */
1241 struct _w31_valent {
1242 unsigned short hash_idx; /* hash chain index for string */
1243 unsigned short refcnt; /* reference count */
1244 unsigned short length; /* length of string */
1245 unsigned short string_off; /* offset of string in text table */
1248 /* recursive helper function to display a directory tree */
1249 void
1250 __w31_dumptree( unsigned short idx,
1251 unsigned char *txt,
1252 struct _w31_tabent *tab,
1253 struct _w31_header *head,
1254 HKEY hkey,
1255 time_t lastmodified,
1256 int level
1258 struct _w31_dirent *dir;
1259 struct _w31_keyent *key;
1260 struct _w31_valent *val;
1261 HKEY subkey = 0;
1262 static char tail[400];
1264 while (idx!=0) {
1265 dir=(struct _w31_dirent*)&tab[idx];
1267 if (dir->key_idx) {
1268 key = (struct _w31_keyent*)&tab[dir->key_idx];
1270 memcpy(tail,&txt[key->string_off],key->length);
1271 tail[key->length]='\0';
1272 /* all toplevel entries AND the entries in the
1273 * toplevel subdirectory belong to \SOFTWARE\Classes
1275 if (!level && !strcmp(tail,".classes")) {
1276 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1277 idx=dir->sibling_idx;
1278 continue;
1280 if (subkey) RegCloseKey( subkey );
1281 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1282 /* only add if leaf node or valued node */
1283 if (dir->value_idx!=0||dir->child_idx==0) {
1284 if (dir->value_idx) {
1285 val=(struct _w31_valent*)&tab[dir->value_idx];
1286 memcpy(tail,&txt[val->string_off],val->length);
1287 tail[val->length]='\0';
1288 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1291 } else {
1292 TRACE("strange: no directory key name, idx=%04x\n", idx);
1294 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1295 idx=dir->sibling_idx;
1297 if (subkey) RegCloseKey( subkey );
1301 /******************************************************************************
1302 * _w31_loadreg [Internal]
1304 void _w31_loadreg(void) {
1305 HFILE hf;
1306 struct _w31_header head;
1307 struct _w31_tabent *tab;
1308 unsigned char *txt;
1309 unsigned int len;
1310 OFSTRUCT ofs;
1311 BY_HANDLE_FILE_INFORMATION hfinfo;
1312 time_t lastmodified;
1314 TRACE("(void)\n");
1316 hf = OpenFile("reg.dat",&ofs,OF_READ);
1317 if (hf==HFILE_ERROR)
1318 return;
1320 /* read & dump header */
1321 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1322 ERR("reg.dat is too short.\n");
1323 _lclose(hf);
1324 return;
1326 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1327 ERR("reg.dat has bad signature.\n");
1328 _lclose(hf);
1329 return;
1332 len = head.tabcnt * sizeof(struct _w31_tabent);
1333 /* read and dump index table */
1334 tab = xmalloc(len);
1335 if (len!=_lread(hf,tab,len)) {
1336 ERR("couldn't read %d bytes.\n",len);
1337 free(tab);
1338 _lclose(hf);
1339 return;
1342 /* read text */
1343 txt = xmalloc(head.textsize);
1344 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1345 ERR("couldn't seek to textblock.\n");
1346 free(tab);
1347 free(txt);
1348 _lclose(hf);
1349 return;
1351 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1352 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1353 free(tab);
1354 free(txt);
1355 _lclose(hf);
1356 return;
1359 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1360 ERR("GetFileInformationByHandle failed?.\n");
1361 free(tab);
1362 free(txt);
1363 _lclose(hf);
1364 return;
1366 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1367 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1368 free(tab);
1369 free(txt);
1370 _lclose(hf);
1371 return;
1375 static void save_at_exit( HKEY hkey, const char *path )
1377 const char *confdir = get_config_dir();
1378 size_t len = strlen(confdir) + strlen(path) + 2;
1379 if (len > REQUEST_MAX_VAR_SIZE)
1381 ERR( "config dir '%s' too long\n", confdir );
1382 return;
1384 SERVER_START_REQ
1386 struct save_registry_atexit_request *req = server_alloc_req( sizeof(*req), len );
1387 sprintf( server_data_ptr(req), "%s/%s", confdir, path );
1388 req->hkey = hkey;
1389 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1391 SERVER_END_REQ;
1394 /* configure save files and start the periodic saving timer */
1395 static void SHELL_InitRegistrySaving( HKEY hkey_users_default )
1397 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1398 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1400 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1401 SERVER_START_REQ
1403 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1404 req->current = 1;
1405 req->saving = !all;
1406 req->period = period * 1000;
1407 server_call( REQ_SET_REGISTRY_LEVELS );
1409 SERVER_END_REQ;
1411 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1413 save_at_exit( HKEY_CURRENT_USER, SAVE_CURRENT_USER );
1414 save_at_exit( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE );
1415 save_at_exit( hkey_users_default, SAVE_DEFAULT_USER );
1420 /**********************************************************************************
1421 * SetLoadLevel [Internal]
1423 * set level to 0 for loading system files
1424 * set level to 1 for loading user files
1426 static void SetLoadLevel(int level)
1428 SERVER_START_REQ
1430 struct set_registry_levels_request *req = server_alloc_req( sizeof(*req), 0 );
1432 req->current = level;
1433 req->saving = 0;
1434 req->period = 0;
1435 server_call( REQ_SET_REGISTRY_LEVELS );
1437 SERVER_END_REQ;
1440 /**********************************************************************************
1441 * SHELL_LoadRegistry [Internal]
1443 #define REG_DONTLOAD -1
1444 #define REG_WIN31 0
1445 #define REG_WIN95 1
1446 #define REG_WINNT 2
1448 void SHELL_LoadRegistry( void )
1450 HKEY hkey;
1451 char windir[MAX_PATHNAME_LEN];
1452 char path[MAX_PATHNAME_LEN];
1453 int systemtype = REG_WIN31;
1454 HKEY hkey_users_default;
1456 TRACE("(void)\n");
1458 if (!CLIENT_IsBootThread()) return; /* already loaded */
1460 REGISTRY_Init();
1461 SetLoadLevel(0);
1463 if (RegCreateKeyA(HKEY_USERS, ".Default", &hkey_users_default))
1464 hkey_users_default = 0;
1466 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1468 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1470 /* test %windir%/system32/config/system --> winnt */
1471 strcpy(path, windir);
1472 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1473 if(GetFileAttributesA(path) != (DWORD)-1)
1475 systemtype = REG_WINNT;
1477 else
1479 /* test %windir%/system.dat --> win95 */
1480 strcpy(path, windir);
1481 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1482 if(GetFileAttributesA(path) != (DWORD)-1)
1484 systemtype = REG_WIN95;
1488 if ((systemtype==REG_WINNT)
1489 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1491 MESSAGE("When you are running with a native NT directory specify\n");
1492 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1493 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1494 systemtype = REG_DONTLOAD;
1497 else
1499 /* only wine registry */
1500 systemtype = REG_DONTLOAD;
1503 switch (systemtype)
1505 case REG_WIN31:
1506 _w31_loadreg();
1507 break;
1509 case REG_WIN95:
1510 /* Load windows 95 entries */
1511 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1513 strcpy(path, windir);
1514 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1515 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1517 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1519 /* user specific user.dat */
1520 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1521 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1523 MESSAGE("can't load win95 user-registry %s\n", path);
1524 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1526 /* default user.dat */
1527 if (hkey_users_default)
1529 strcpy(path, windir);
1530 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1531 NativeRegLoadKey(hkey_users_default, path, 1);
1534 else
1536 /* global user.dat */
1537 strcpy(path, windir);
1538 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1539 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1541 break;
1543 case REG_WINNT:
1544 /* default user.dat */
1545 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1547 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1548 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1550 MESSAGE("can't load NT user-registry %s\n", path);
1551 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1555 /* default user.dat */
1556 if (hkey_users_default)
1558 strcpy(path, windir);
1559 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1560 NativeRegLoadKey(hkey_users_default, path, 1);
1564 * FIXME
1565 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1568 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1570 strcpy(path, windir);
1571 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1572 NativeRegLoadKey(hkey, path, 1);
1573 RegCloseKey(hkey);
1576 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1578 strcpy(path, windir);
1579 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1580 NativeRegLoadKey(hkey, path, 1);
1581 RegCloseKey(hkey);
1584 strcpy(path, windir);
1585 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1586 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1588 strcpy(path, windir);
1589 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1590 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1592 /* this key is generated when the nt-core booted successfully */
1593 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1594 RegCloseKey(hkey);
1595 break;
1596 } /* switch */
1598 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1601 * Load the global HKU hive directly from sysconfdir
1603 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1606 * Load the global machine defaults directly from sysconfdir
1608 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1611 SetLoadLevel(1);
1614 * Load the user saved registries
1616 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1618 const char *confdir = get_config_dir();
1619 unsigned int len = strlen(confdir) + 20;
1620 char *fn = path;
1622 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1624 * Load user's personal versions of global HKU/.Default keys
1626 if (fn)
1628 char *str;
1629 strcpy( fn, confdir );
1630 str = fn + strlen(fn);
1631 *str++ = '/';
1633 /* try to load HKU\.Default key only */
1634 strcpy( str, SAVE_DEFAULT_USER );
1635 if (_wine_loadreg( hkey_users_default, fn ))
1637 /* if not found load old file containing both HKU\.Default and HKU\user */
1638 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1639 _wine_loadreg( HKEY_USERS, fn );
1642 strcpy( str, SAVE_CURRENT_USER );
1643 _wine_loadreg( HKEY_CURRENT_USER, fn );
1645 strcpy( str, SAVE_LOCAL_MACHINE );
1646 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1648 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1651 SHELL_InitRegistrySaving( hkey_users_default );
1652 RegCloseKey( hkey_users_default );
1655 /********************* API FUNCTIONS ***************************************/
1660 /******************************************************************************
1661 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1662 * Immediately writes key to registry.
1663 * Only returns after data has been written to disk.
1665 * FIXME: does it really wait until data is written ?
1667 * PARAMS
1668 * hkey [I] Handle of key to write
1670 * RETURNS
1671 * Success: ERROR_SUCCESS
1672 * Failure: Error code
1674 DWORD WINAPI RegFlushKey( HKEY hkey )
1676 FIXME( "(%x): stub\n", hkey );
1677 return ERROR_SUCCESS;
1680 /******************************************************************************
1681 * RegConnectRegistryW [ADVAPI32.128]
1683 * PARAMS
1684 * lpMachineName [I] Address of name of remote computer
1685 * hHey [I] Predefined registry handle
1686 * phkResult [I] Address of buffer for remote registry handle
1688 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1689 LPHKEY phkResult )
1691 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1693 if (!lpMachineName || !*lpMachineName) {
1694 /* Use the local machine name */
1695 return RegOpenKey16( hKey, "", phkResult );
1698 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1699 return ERROR_BAD_NETPATH;
1703 /******************************************************************************
1704 * RegConnectRegistryA [ADVAPI32.127]
1706 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1708 LPWSTR machineW = HEAP_strdupAtoW( GetProcessHeap(), 0, machine );
1709 DWORD ret = RegConnectRegistryW( machineW, hkey, reskey );
1710 HeapFree( GetProcessHeap(), 0, machineW );
1711 return ret;
1715 /******************************************************************************
1716 * RegGetKeySecurity [ADVAPI32.144]
1717 * Retrieves a copy of security descriptor protecting the registry key
1719 * PARAMS
1720 * hkey [I] Open handle of key to set
1721 * SecurityInformation [I] Descriptor contents
1722 * pSecurityDescriptor [O] Address of descriptor for key
1723 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1725 * RETURNS
1726 * Success: ERROR_SUCCESS
1727 * Failure: Error code
1729 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1730 SECURITY_INFORMATION SecurityInformation,
1731 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1732 LPDWORD lpcbSecurityDescriptor )
1734 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1735 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1737 /* FIXME: Check for valid SecurityInformation values */
1739 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1740 return ERROR_INSUFFICIENT_BUFFER;
1742 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1743 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1745 return ERROR_SUCCESS;
1749 /******************************************************************************
1750 * RegNotifyChangeKeyValue [ADVAPI32.???]
1752 * PARAMS
1753 * hkey [I] Handle of key to watch
1754 * fWatchSubTree [I] Flag for subkey notification
1755 * fdwNotifyFilter [I] Changes to be reported
1756 * hEvent [I] Handle of signaled event
1757 * fAsync [I] Flag for asynchronous reporting
1759 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1760 DWORD fdwNotifyFilter, HANDLE hEvent,
1761 BOOL fAsync )
1763 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1764 hEvent,fAsync);
1765 return ERROR_SUCCESS;
1769 /******************************************************************************
1770 * RegUnLoadKeyW [ADVAPI32.173]
1772 * PARAMS
1773 * hkey [I] Handle of open key
1774 * lpSubKey [I] Address of name of subkey to unload
1776 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1778 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1779 return ERROR_SUCCESS;
1783 /******************************************************************************
1784 * RegUnLoadKeyA [ADVAPI32.172]
1786 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1788 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1789 LONG ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1790 if(lpSubKeyW) HeapFree( GetProcessHeap(), 0, lpSubKeyW);
1791 return ret;
1795 /******************************************************************************
1796 * RegSetKeySecurity [ADVAPI32.167]
1798 * PARAMS
1799 * hkey [I] Open handle of key to set
1800 * SecurityInfo [I] Descriptor contents
1801 * pSecurityDesc [I] Address of descriptor for key
1803 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1804 PSECURITY_DESCRIPTOR pSecurityDesc )
1806 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1808 /* It seems to perform this check before the hkey check */
1809 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1810 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1811 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1812 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1813 /* Param OK */
1814 } else
1815 return ERROR_INVALID_PARAMETER;
1817 if (!pSecurityDesc)
1818 return ERROR_INVALID_PARAMETER;
1820 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1822 return ERROR_SUCCESS;
1826 /******************************************************************************
1827 * RegRestoreKeyW [ADVAPI32.164]
1829 * PARAMS
1830 * hkey [I] Handle of key where restore begins
1831 * lpFile [I] Address of filename containing saved tree
1832 * dwFlags [I] Optional flags
1834 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1836 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1838 /* It seems to do this check before the hkey check */
1839 if (!lpFile || !*lpFile)
1840 return ERROR_INVALID_PARAMETER;
1842 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1844 /* Check for file existence */
1846 return ERROR_SUCCESS;
1850 /******************************************************************************
1851 * RegRestoreKeyA [ADVAPI32.163]
1853 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1855 LPWSTR lpFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile );
1856 LONG ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1857 HeapFree( GetProcessHeap(), 0, lpFileW );
1858 return ret;
1862 /******************************************************************************
1863 * RegReplaceKeyW [ADVAPI32.162]
1865 * PARAMS
1866 * hkey [I] Handle of open key
1867 * lpSubKey [I] Address of name of subkey
1868 * lpNewFile [I] Address of filename for file with new data
1869 * lpOldFile [I] Address of filename for backup file
1871 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1872 LPCWSTR lpOldFile )
1874 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1875 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1876 return ERROR_SUCCESS;
1880 /******************************************************************************
1881 * RegReplaceKeyA [ADVAPI32.161]
1883 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1884 LPCSTR lpOldFile )
1886 LPWSTR lpSubKeyW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey );
1887 LPWSTR lpNewFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile );
1888 LPWSTR lpOldFileW = HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile );
1889 LONG ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1890 HeapFree( GetProcessHeap(), 0, lpOldFileW );
1891 HeapFree( GetProcessHeap(), 0, lpNewFileW );
1892 HeapFree( GetProcessHeap(), 0, lpSubKeyW );
1893 return ret;
1901 /* 16-bit functions */
1903 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1904 * some programs. Do not remove those cases. -MM
1906 static inline void fix_win16_hkey( HKEY *hkey )
1908 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1911 /******************************************************************************
1912 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1914 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1916 fix_win16_hkey( &hkey );
1917 return RegEnumKeyA( hkey, index, name, name_len );
1920 /******************************************************************************
1921 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1923 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1925 fix_win16_hkey( &hkey );
1926 return RegOpenKeyA( hkey, name, retkey );
1929 /******************************************************************************
1930 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1932 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1934 fix_win16_hkey( &hkey );
1935 return RegCreateKeyA( hkey, name, retkey );
1938 /******************************************************************************
1939 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1941 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1943 fix_win16_hkey( &hkey );
1944 return RegDeleteKeyA( hkey, name );
1947 /******************************************************************************
1948 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1950 DWORD WINAPI RegCloseKey16( HKEY hkey )
1952 fix_win16_hkey( &hkey );
1953 return RegCloseKey( hkey );
1956 /******************************************************************************
1957 * RegSetValue16 [KERNEL.221] [SHELL.5]
1959 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1961 fix_win16_hkey( &hkey );
1962 return RegSetValueA( hkey, name, type, data, count );
1965 /******************************************************************************
1966 * RegDeleteValue16 [KERNEL.222]
1968 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1970 fix_win16_hkey( &hkey );
1971 return RegDeleteValueA( hkey, name );
1974 /******************************************************************************
1975 * RegEnumValue16 [KERNEL.223]
1977 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1978 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1980 fix_win16_hkey( &hkey );
1981 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1984 /******************************************************************************
1985 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1987 * NOTES
1988 * Is this HACK still applicable?
1990 * HACK
1991 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1992 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1993 * Aldus FH4)
1995 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1997 fix_win16_hkey( &hkey );
1998 if (count) *count &= 0xffff;
1999 return RegQueryValueA( hkey, name, data, count );
2002 /******************************************************************************
2003 * RegQueryValueEx16 [KERNEL.225]
2005 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
2006 LPBYTE data, LPDWORD count )
2008 fix_win16_hkey( &hkey );
2009 return RegQueryValueExA( hkey, name, reserved, type, data, count );
2012 /******************************************************************************
2013 * RegSetValueEx16 [KERNEL.226]
2015 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
2016 CONST BYTE *data, DWORD count )
2018 fix_win16_hkey( &hkey );
2019 return RegSetValueExA( hkey, name, reserved, type, data, count );