- added thread-safety protection to XListPixmapFormats
[wine.git] / misc / registry.c
blob1d62ca4808a49155cffdf22c1f5072c961fd7f4f
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 "wine/winbase16.h"
42 #include "wine/winestring.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_LOCAL_USERS_DEFAULT "wine.userreg"
63 #define SAVE_LOCAL_MACHINE "system.reg"
65 /* what valuetypes do we need to convert? */
66 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
69 static void *xmalloc( size_t size )
71 void *res;
73 res = malloc (size ? size : 1);
74 if (res == NULL) {
75 WARN("Virtual memory exhausted.\n");
76 exit (1);
78 return res;
82 * QUESTION
83 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
84 * If so, can we remove them?
85 * ANSWER
86 * No, the memory handling functions are called very often in here,
87 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
88 * loading 100 times slower. -MM
90 static LPWSTR strdupA2W(LPCSTR src)
92 if(src) {
93 LPWSTR dest=xmalloc(2*strlen(src)+2);
94 lstrcpyAtoW(dest,src);
95 return dest;
97 return NULL;
100 LPWSTR strcvtA2W(LPCSTR src, int nchars)
103 LPWSTR dest = xmalloc (2 * nchars + 2);
105 lstrcpynAtoW(dest,src,nchars+1);
106 return dest;
111 /******************************************************************************
112 * REGISTRY_Init [Internal]
113 * Registry initialisation, allocates some default keys.
115 static void REGISTRY_Init(void) {
116 HKEY hkey;
117 char buf[200];
119 TRACE("(void)\n");
121 RegCreateKeyA(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
122 RegCloseKey(hkey);
124 /* This was an Open, but since it is called before the real registries
125 are loaded, it was changed to a Create - MTB 980507*/
126 RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
127 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
128 RegCloseKey(hkey);
130 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
131 * CurrentVersion
132 * CurrentBuildNumber
133 * CurrentType
134 * string RegisteredOwner
135 * string RegisteredOrganization
138 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
139 * string SysContact
140 * string SysLocation
141 * SysServices
143 if (-1!=gethostname(buf,200)) {
144 RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
145 RegSetValueExA(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
146 RegCloseKey(hkey);
151 /************************ LOAD Registry Function ****************************/
155 /******************************************************************************
156 * _find_or_add_key [Internal]
158 static inline HKEY _find_or_add_key( HKEY hkey, LPWSTR keyname )
160 HKEY subkey;
161 if (RegCreateKeyW( hkey, keyname, &subkey ) != ERROR_SUCCESS) subkey = 0;
162 if (keyname) free( keyname );
163 return subkey;
166 /******************************************************************************
167 * _find_or_add_value [Internal]
169 static void _find_or_add_value( HKEY hkey, LPWSTR name, DWORD type, LPBYTE data, DWORD len )
171 RegSetValueExW( hkey, name, 0, type, data, len );
172 if (name) free( name );
173 if (data) free( data );
177 /******************************************************************************
178 * _wine_read_line [Internal]
180 * reads a line including dynamically enlarging the readbuffer and throwing
181 * away comments
183 static int _wine_read_line( FILE *F, char **buf, int *len )
185 char *s,*curread;
186 int mylen,curoff;
188 curread = *buf;
189 mylen = *len;
190 **buf = '\0';
191 while (1) {
192 while (1) {
193 s=fgets(curread,mylen,F);
194 if (s==NULL)
195 return 0; /* EOF */
196 if (NULL==(s=strchr(curread,'\n'))) {
197 /* buffer wasn't large enough */
198 curoff = strlen(*buf);
199 curread = realloc(*buf,*len*2);
200 if(curread == NULL) {
201 WARN("Out of memory");
202 return 0;
204 *buf = curread;
205 curread+= curoff;
206 mylen = *len; /* we filled up the buffer and
207 * got new '*len' bytes to fill
209 *len = *len * 2;
210 } else {
211 *s='\0';
212 break;
215 /* throw away comments */
216 if (**buf=='#' || **buf==';') {
217 curread = *buf;
218 mylen = *len;
219 continue;
221 if (s) /* got end of line */
222 break;
224 return 1;
228 /******************************************************************************
229 * _wine_read_USTRING [Internal]
231 * converts a char* into a UNICODE string (up to a special char)
232 * and returns the position exactly after that string
234 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
236 char *s;
237 LPWSTR ws;
239 /* read up to "=" or "\0" or "\n" */
240 s = buf;
241 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
242 ws = *str;
243 while (*s && (*s!='\n') && (*s!='=')) {
244 if (*s!='\\')
245 *ws++=*((unsigned char*)s++);
246 else {
247 s++;
248 if (!*s) {
249 /* Dangling \ ... may only happen if a registry
250 * write was short. FIXME: What do to?
252 break;
254 if (*s=='\\') {
255 *ws++='\\';
256 s++;
257 continue;
259 if (*s!='u') {
260 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
261 *ws++='\\';
262 *ws++=*s++;
263 } else {
264 char xbuf[5];
265 int wc;
267 s++;
268 memcpy(xbuf,s,4);xbuf[4]='\0';
269 if (!sscanf(xbuf,"%x",&wc))
270 WARN("Strange escape sequence %s found in |%s|\n",xbuf,buf);
271 s+=4;
272 *ws++ =(unsigned short)wc;
276 *ws = 0;
277 return s;
281 /******************************************************************************
282 * _wine_loadsubkey [Internal]
284 * NOTES
285 * It seems like this is returning a boolean. Should it?
287 * RETURNS
288 * Success: 1
289 * Failure: 0
291 static int _wine_loadsubkey( FILE *F, HKEY hkey, int level, char **buf, int *buflen )
293 HKEY subkey;
294 int i;
295 char *s;
296 LPWSTR name;
298 TRACE("(%p,%x,%d,%s,%d)\n", F, hkey, level, debugstr_a(*buf), *buflen);
300 /* Good. We already got a line here ... so parse it */
301 subkey = 0;
302 while (1) {
303 i=0;s=*buf;
304 while (*s=='\t') {
305 s++;
306 i++;
308 if (i>level) {
309 if (!subkey) {
310 WARN("Got a subhierarchy without resp. key?\n");
311 return 0;
313 if (!_wine_loadsubkey(F,subkey,level+1,buf,buflen))
314 if (!_wine_read_line(F,buf,buflen))
315 goto done;
316 continue;
319 /* let the caller handle this line */
320 if (i<level || **buf=='\0')
321 goto done;
323 /* it can be: a value or a keyname. Parse the name first */
324 s=_wine_read_USTRING(s,&name);
326 /* switch() default: hack to avoid gotos */
327 switch (0) {
328 default:
329 if (*s=='\0') {
330 if (subkey) RegCloseKey( subkey );
331 subkey=_find_or_add_key(hkey,name);
332 } else {
333 LPBYTE data;
334 int len,lastmodified,type;
336 if (*s!='=') {
337 WARN("Unexpected character: %c\n",*s);
338 break;
340 s++;
341 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
342 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
343 break;
345 /* skip the 2 , */
346 s=strchr(s,',');s++;
347 s=strchr(s,',');
348 if (!s++) {
349 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf);
350 break;
352 if (type == REG_SZ || type == REG_EXPAND_SZ) {
353 s=_wine_read_USTRING(s,(LPWSTR*)&data);
354 len = lstrlenW((LPWSTR)data)*2+2;
355 } else {
356 len=strlen(s)/2;
357 data = (LPBYTE)xmalloc(len+1);
358 for (i=0;i<len;i++) {
359 data[i]=0;
360 if (*s>='0' && *s<='9')
361 data[i]=(*s-'0')<<4;
362 if (*s>='a' && *s<='f')
363 data[i]=(*s-'a'+'\xa')<<4;
364 if (*s>='A' && *s<='F')
365 data[i]=(*s-'A'+'\xa')<<4;
366 s++;
367 if (*s>='0' && *s<='9')
368 data[i]|=*s-'0';
369 if (*s>='a' && *s<='f')
370 data[i]|=*s-'a'+'\xa';
371 if (*s>='A' && *s<='F')
372 data[i]|=*s-'A'+'\xa';
373 s++;
376 _find_or_add_value(hkey,name,type,data,len);
379 /* read the next line */
380 if (!_wine_read_line(F,buf,buflen))
381 goto done;
383 done:
384 if (subkey) RegCloseKey( subkey );
385 return 1;
389 /******************************************************************************
390 * _wine_loadsubreg [Internal]
392 static int _wine_loadsubreg( FILE *F, HKEY hkey, const char *fn )
394 int ver;
395 char *buf;
396 int buflen;
398 buf=xmalloc(10);buflen=10;
399 if (!_wine_read_line(F,&buf,&buflen)) {
400 free(buf);
401 return 0;
403 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
404 free(buf);
405 return 0;
407 if (ver!=1) {
408 if (ver == 2) /* new version */
410 HANDLE file;
411 if ((file = FILE_CreateFile( fn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
412 FILE_ATTRIBUTE_NORMAL, -1, TRUE )) != INVALID_HANDLE_VALUE)
414 struct load_registry_request *req = get_req_buffer();
415 req->hkey = hkey;
416 req->file = file;
417 req->name[0] = 0;
418 server_call( REQ_LOAD_REGISTRY );
419 CloseHandle( file );
421 free( buf );
422 return 1;
424 else
426 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
427 free(buf);
428 return 0;
431 if (!_wine_read_line(F,&buf,&buflen)) {
432 free(buf);
433 return 0;
435 if (!_wine_loadsubkey(F,hkey,0,&buf,&buflen)) {
436 free(buf);
437 return 0;
439 free(buf);
440 return 1;
444 /******************************************************************************
445 * _wine_loadreg [Internal]
447 static void _wine_loadreg( HKEY hkey, char *fn )
449 FILE *F;
451 TRACE("(%x,%s)\n",hkey,debugstr_a(fn));
453 F = fopen(fn,"rb");
454 if (F==NULL) {
455 WARN("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
456 return;
458 _wine_loadsubreg(F,hkey,fn);
459 fclose(F);
462 /* NT REGISTRY LOADER */
464 #ifdef HAVE_SYS_MMAN_H
465 # include <sys/mman.h>
466 #endif
468 #ifndef MAP_FAILED
469 #define MAP_FAILED ((LPVOID)-1)
470 #endif
472 #define NT_REG_BLOCK_SIZE 0x1000
474 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
475 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
476 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
477 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
479 /* subblocks of nk */
480 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
481 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
482 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
484 #define NT_REG_KEY_BLOCK_TYPE 0x20
485 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
487 typedef struct
489 DWORD id; /* 0x66676572 'regf'*/
490 DWORD uk1; /* 0x04 */
491 DWORD uk2; /* 0x08 */
492 FILETIME DateModified; /* 0x0c */
493 DWORD uk3; /* 0x14 */
494 DWORD uk4; /* 0x18 */
495 DWORD uk5; /* 0x1c */
496 DWORD uk6; /* 0x20 */
497 DWORD RootKeyBlock; /* 0x24 */
498 DWORD BlockSize; /* 0x28 */
499 DWORD uk7[116];
500 DWORD Checksum; /* at offset 0x1FC */
501 } nt_regf;
503 typedef struct
505 DWORD blocksize;
506 BYTE data[1];
507 } nt_hbin_sub;
509 typedef struct
511 DWORD id; /* 0x6E696268 'hbin' */
512 DWORD off_prev;
513 DWORD off_next;
514 DWORD uk1;
515 DWORD uk2; /* 0x10 */
516 DWORD uk3; /* 0x14 */
517 DWORD uk4; /* 0x18 */
518 DWORD size; /* 0x1C */
519 nt_hbin_sub hbin_sub; /* 0x20 */
520 } nt_hbin;
523 * the value_list consists of offsets to the values (vk)
525 typedef struct
527 WORD SubBlockId; /* 0x00 0x6B6E */
528 WORD Type; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
529 FILETIME writetime; /* 0x04 */
530 DWORD uk1; /* 0x0C */
531 DWORD parent_off; /* 0x10 Offset of Owner/Parent key */
532 DWORD nr_subkeys; /* 0x14 number of sub-Keys */
533 DWORD uk8; /* 0x18 */
534 DWORD lf_off; /* 0x1C Offset of the sub-key lf-Records */
535 DWORD uk2; /* 0x20 */
536 DWORD nr_values; /* 0x24 number of values */
537 DWORD valuelist_off; /* 0x28 Offset of the Value-List */
538 DWORD off_sk; /* 0x2c Offset of the sk-Record */
539 DWORD off_class; /* 0x30 Offset of the Class-Name */
540 DWORD uk3; /* 0x34 */
541 DWORD uk4; /* 0x38 */
542 DWORD uk5; /* 0x3c */
543 DWORD uk6; /* 0x40 */
544 DWORD uk7; /* 0x44 */
545 WORD name_len; /* 0x48 name-length */
546 WORD class_len; /* 0x4a class-name length */
547 char name[1]; /* 0x4c key-name */
548 } nt_nk;
550 typedef struct
552 DWORD off_nk; /* 0x00 */
553 DWORD name; /* 0x04 */
554 } hash_rec;
556 typedef struct
558 WORD id; /* 0x00 0x666c */
559 WORD nr_keys; /* 0x06 */
560 hash_rec hash_rec[1];
561 } nt_lf;
564 list of subkeys without hash
566 li --+-->nk
568 +-->nk
570 typedef struct
572 WORD id; /* 0x00 0x696c */
573 WORD nr_keys;
574 DWORD off_nk[1];
575 } nt_li;
578 this is a intermediate node
580 ri --+-->li--+-->nk
582 | +-->nk
584 +-->li--+-->nk
586 +-->nk
588 typedef struct
590 WORD id; /* 0x00 0x6972 */
591 WORD nr_li; /* 0x02 number off offsets */
592 DWORD off_li[1]; /* 0x04 points to li */
593 } nt_ri;
595 typedef struct
597 WORD id; /* 0x00 'vk' */
598 WORD nam_len;
599 DWORD data_len;
600 DWORD data_off;
601 DWORD type;
602 WORD flag;
603 WORD uk1;
604 char name[1];
605 } nt_vk;
607 LPSTR _strdupnA( LPCSTR str, int len )
609 LPSTR ret;
611 if (!str) return NULL;
612 ret = malloc( len + 1 );
613 lstrcpynA( ret, str, len );
614 ret[len] = 0x00;
615 return ret;
618 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level);
619 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk);
620 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level);
624 * gets a value
626 * vk->flag:
627 * 0 value is a default value
628 * 1 the value has a name
630 * vk->data_len
631 * len of the whole data block
632 * - reg_sz (unicode)
633 * bytes including the terminating \0 = 2*(number_of_chars+1)
634 * - reg_dword, reg_binary:
635 * if highest bit of data_len is set data_off contains the value
637 static int _nt_parse_vk(HKEY hkey, char * base, nt_vk * vk)
639 WCHAR name [256];
640 DWORD ret;
641 BYTE * pdata = (BYTE *)(base+vk->data_off+4); /* start of data */
643 if(vk->id != NT_REG_VALUE_BLOCK_ID) goto error;
645 lstrcpynAtoW(name, vk->name, vk->nam_len+1);
647 ret = RegSetValueExW( hkey, (vk->flag & 0x00000001) ? name : NULL, 0, vk->type,
648 (vk->data_len & 0x80000000) ? (LPBYTE)&(vk->data_off): pdata,
649 (vk->data_len & 0x7fffffff) );
650 if (ret) ERR("RegSetValueEx failed (0x%08lx)\n", ret);
651 return TRUE;
652 error:
653 ERR_(reg)("unknown block found (0x%04x), please report!\n", vk->id);
654 return FALSE;
658 * get the subkeys
660 * this structure contains the hash of a keyname and points to all
661 * subkeys
663 * exception: if the id is 'il' there are no hash values and every
664 * dword is a offset
666 static int _nt_parse_lf(HKEY hkey, char * base, int subkeys, nt_lf * lf, int level)
668 int i;
670 if (lf->id == NT_REG_HASH_BLOCK_ID)
672 if (subkeys != lf->nr_keys) goto error1;
674 for (i=0; i<lf->nr_keys; i++)
676 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+lf->hash_rec[i].off_nk+4), level)) goto error;
679 else if (lf->id == NT_REG_NOHASH_BLOCK_ID)
681 nt_li * li = (nt_li*)lf;
682 if (subkeys != li->nr_keys) goto error1;
684 for (i=0; i<li->nr_keys; i++)
686 if (!_nt_parse_nk(hkey, base, (nt_nk*)(base+li->off_nk[i]+4), level)) goto error;
689 else if (lf->id == NT_REG_RI_BLOCK_ID) /* ri */
691 nt_ri * ri = (nt_ri*)lf;
692 int li_subkeys = 0;
694 /* count all subkeys */
695 for (i=0; i<ri->nr_li; i++)
697 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
698 if(li->id != NT_REG_NOHASH_BLOCK_ID) goto error2;
699 li_subkeys += li->nr_keys;
702 /* check number */
703 if (subkeys != li_subkeys) goto error1;
705 /* loop through the keys */
706 for (i=0; i<ri->nr_li; i++)
708 nt_li * li = (nt_li*)(base+ri->off_li[i]+4);
709 if (!_nt_parse_lf(hkey, base, li->nr_keys, (nt_lf*)li, level)) goto error;
712 else
714 goto error2;
716 return TRUE;
718 error2: ERR("unknown node id 0x%04x, please report!\n", lf->id);
719 return TRUE;
721 error1: ERR_(reg)("registry file corrupt! (inconsistent number of subkeys)\n");
722 return FALSE;
724 error: ERR_(reg)("error reading lf block\n");
725 return FALSE;
728 static int _nt_parse_nk(HKEY hkey, char * base, nt_nk * nk, int level)
730 char * name;
731 int i;
732 DWORD * vl;
733 HKEY subkey = hkey;
735 if(nk->SubBlockId != NT_REG_KEY_BLOCK_ID)
737 ERR("unknown node id 0x%04x, please report!\n", nk->SubBlockId);
738 goto error;
741 if((nk->Type!=NT_REG_ROOT_KEY_BLOCK_TYPE) &&
742 (((nt_nk*)(base+nk->parent_off+4))->SubBlockId != NT_REG_KEY_BLOCK_ID))
744 ERR_(reg)("registry file corrupt!\n");
745 goto error;
748 /* create the new key */
749 if(level <= 0)
751 name = _strdupnA( nk->name, nk->name_len+1);
752 if(RegCreateKeyA( hkey, name, &subkey )) { free(name); goto error; }
753 free(name);
756 /* loop through the subkeys */
757 if (nk->nr_subkeys)
759 nt_lf * lf = (nt_lf*)(base+nk->lf_off+4);
760 if (!_nt_parse_lf(subkey, base, nk->nr_subkeys, lf, level-1)) goto error1;
763 /* loop trough the value list */
764 vl = (DWORD *)(base+nk->valuelist_off+4);
765 for (i=0; i<nk->nr_values; i++)
767 nt_vk * vk = (nt_vk*)(base+vl[i]+4);
768 if (!_nt_parse_vk(subkey, base, vk)) goto error1;
771 RegCloseKey(subkey);
772 return TRUE;
774 error1: RegCloseKey(subkey);
775 error: return FALSE;
778 /* end nt loader */
780 /* windows 95 registry loader */
782 /* SECTION 1: main header
784 * once at offset 0
786 #define W95_REG_CREG_ID 0x47455243
788 typedef struct
790 DWORD id; /* "CREG" = W95_REG_CREG_ID */
791 DWORD version; /* ???? 0x00010000 */
792 DWORD rgdb_off; /* 0x08 Offset of 1st RGDB-block */
793 DWORD uk2; /* 0x0c */
794 WORD rgdb_num; /* 0x10 # of RGDB-blocks */
795 WORD uk3;
796 DWORD uk[3];
797 /* rgkn */
798 } _w95creg;
800 /* SECTION 2: Directory information (tree structure)
802 * once on offset 0x20
804 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
806 #define W95_REG_RGKN_ID 0x4e4b4752
808 typedef struct
810 DWORD id; /*"RGKN" = W95_REG_RGKN_ID */
811 DWORD size; /* Size of the RGKN-block */
812 DWORD root_off; /* Rel. Offset of the root-record */
813 DWORD uk[5];
814 } _w95rgkn;
816 /* Disk Key Entry Structure
818 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
819 * hive itself. It looks the same like other keys. Even the ID-number can
820 * be any value.
822 * The "hash"-value is a value representing the key's name. Windows will not
823 * search for the name, but for a matching hash-value. if it finds one, it
824 * will compare the actual string info, otherwise continue with the next key.
825 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
826 * of the string which are smaller than 0x80 (128) to this D-Word.
828 * If you want to modify key names, also modify the hash-values, since they
829 * cannot be found again (although they would be displayed in REGEDIT)
830 * End of list-pointers are filled with 0xFFFFFFFF
832 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
833 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
834 * structure) and reading another RGDB_section.
836 * there is a one to one relationship between dke and dkh
838 /* key struct, once per key */
839 typedef struct
841 DWORD x1; /* Free entry indicator(?) */
842 DWORD hash; /* sum of bytes of keyname */
843 DWORD x3; /* Root key indicator? usually 0xFFFFFFFF */
844 DWORD prevlvl; /* offset of previous key */
845 DWORD nextsub; /* offset of child key */
846 DWORD next; /* offset of sibling key */
847 WORD nrLS; /* id inside the rgdb block */
848 WORD nrMS; /* number of the rgdb block */
849 } _w95dke;
851 /* SECTION 3: key information, values and data
853 * structure:
854 * section: [blocks]* (repeat creg->rgdb_num times)
855 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
856 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
858 * An interesting relationship exists in RGDB_section. The value at offset
859 * 10 equals the value at offset 4 minus the value at offset 8. I have no
860 * idea at the moment what this means. (Kevin Cozens)
863 /* block header, once per block */
864 #define W95_REG_RGDB_ID 0x42444752
866 typedef struct
868 DWORD id; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
869 DWORD size; /* 0x04 */
870 DWORD uk1; /* 0x08 */
871 DWORD uk2; /* 0x0c */
872 DWORD uk3; /* 0x10 */
873 DWORD uk4; /* 0x14 */
874 DWORD uk5; /* 0x18 */
875 DWORD uk6; /* 0x1c */
876 /* dkh */
877 } _w95rgdb;
879 /* Disk Key Header structure (RGDB part), once per key */
880 typedef struct
882 DWORD nextkeyoff; /* 0x00 offset to next dkh*/
883 WORD nrLS; /* 0x04 id inside the rgdb block */
884 WORD nrMS; /* 0x06 number of the rgdb block */
885 DWORD bytesused; /* 0x08 */
886 WORD keynamelen; /* 0x0c len of name */
887 WORD values; /* 0x0e number of values */
888 DWORD xx1; /* 0x10 */
889 char name[1]; /* 0x14 */
890 /* dkv */ /* 0x14 + keynamelen */
891 } _w95dkh;
893 /* Disk Key Value structure, once per value */
894 typedef struct
896 DWORD type; /* 0x00 */
897 DWORD x1; /* 0x04 */
898 WORD valnamelen; /* 0x08 length of name, 0 is default key */
899 WORD valdatalen; /* 0x0A length of data */
900 char name[1]; /* 0x0c */
901 /* raw data */ /* 0x0c + valnamelen */
902 } _w95dkv;
904 /******************************************************************************
905 * _w95_lookup_dkh [Internal]
907 * seeks the dkh belonging to a dke
909 static _w95dkh * _w95_lookup_dkh (_w95creg *creg, int nrLS, int nrMS)
911 _w95rgdb * rgdb;
912 _w95dkh * dkh;
913 int i;
915 /* get the beginning of the rgdb datastore */
916 rgdb = (_w95rgdb*)((char*)creg+creg->rgdb_off);
918 /* check: requested block < last_block) */
919 if (creg->rgdb_num <= nrMS)
921 ERR("registry file corrupt! requested block no. beyond end.\n");
922 goto error;
925 /* find the right block */
926 for(i=0; i<nrMS ;i++)
928 if(rgdb->id != W95_REG_RGDB_ID) /* check the magic */
930 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb->id);
931 goto error;
933 rgdb = (_w95rgdb*) ((char*)rgdb+rgdb->size); /* find next block */
936 dkh = (_w95dkh*)(rgdb + 1); /* first sub block within the rgdb */
940 if(nrLS==dkh->nrLS ) return dkh;
941 dkh = (_w95dkh*)((char*)dkh + dkh->nextkeyoff); /* find next subblock */
942 } while ((char *)dkh < ((char*)rgdb+rgdb->size));
944 error: return NULL;
947 /******************************************************************************
948 * _w95_parse_dkv [Internal]
950 static int _w95_parse_dkv (
951 HKEY hkey,
952 _w95dkh * dkh,
953 int nrLS,
954 int nrMS )
956 _w95dkv * dkv;
957 int i;
958 DWORD ret;
959 char * name;
961 /* first value block */
962 dkv = (_w95dkv*)((char*)dkh+dkh->keynamelen+0x14);
964 /* loop trought the values */
965 for (i=0; i< dkh->values; i++)
967 name = _strdupnA(dkv->name, dkv->valnamelen+1);
968 ret = RegSetValueExA(hkey, name, 0, dkv->type, &(dkv->name[dkv->valnamelen]),dkv->valdatalen);
969 if (ret) FIXME("RegSetValueEx returned: 0x%08lx\n", ret);
970 free (name);
972 /* next value */
973 dkv = (_w95dkv*)((char*)dkv+dkv->valnamelen+dkv->valdatalen+0x0c);
975 return TRUE;
978 /******************************************************************************
979 * _w95_parse_dke [Internal]
981 static int _w95_parse_dke(
982 HKEY hkey,
983 _w95creg * creg,
984 _w95rgkn *rgkn,
985 _w95dke * dke,
986 int level )
988 _w95dkh * dkh;
989 HKEY hsubkey = hkey;
990 char * name;
991 int ret = FALSE;
993 /* get start address of root key block */
994 if (!dke) dke = (_w95dke*)((char*)rgkn + rgkn->root_off);
996 /* special root key */
997 if (dke->nrLS == 0xffff || dke->nrMS==0xffff) /* eg. the root key has no name */
999 /* parse the one subkey*/
1000 if (dke->nextsub != 0xffffffff)
1002 return _w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level);
1004 /* has no sibling keys */
1005 goto error;
1008 /* search subblock */
1009 if (!(dkh = _w95_lookup_dkh(creg, dke->nrLS, dke->nrMS)))
1011 fprintf(stderr, "dke pointing to missing dkh !\n");
1012 goto error;
1015 if ( level <= 0 )
1017 /* walk sibling keys */
1018 if (dke->next != 0xffffffff )
1020 if (!_w95_parse_dke(hkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->next), level)) goto error;
1023 /* create subkey and insert values */
1024 name = _strdupnA( dkh->name, dkh->keynamelen+1);
1025 if (RegCreateKeyA(hkey, name, &hsubkey)) { free(name); goto error; }
1026 free(name);
1027 if (!_w95_parse_dkv(hsubkey, dkh, dke->nrLS, dke->nrMS)) goto error1;
1030 /* next sub key */
1031 if (dke->nextsub != 0xffffffff)
1033 if (!_w95_parse_dke(hsubkey, creg, rgkn, (_w95dke*)((char*)rgkn+dke->nextsub), level-1)) goto error1;
1036 ret = TRUE;
1037 error1: if (hsubkey != hkey) RegCloseKey(hsubkey);
1038 error: return ret;
1040 /* end windows 95 loader */
1042 /******************************************************************************
1043 * NativeRegLoadKey [Internal]
1045 * Loads a native registry file (win95/nt)
1046 * hkey root key
1047 * fn filename
1048 * level number of levels to cut away (eg. ".Default" in user.dat)
1050 * this function intentionally uses unix file functions to make it possible
1051 * to move it to a seperate registry helper programm
1053 static int NativeRegLoadKey( HKEY hkey, char* fn, int level )
1055 int fd = 0;
1056 struct stat st;
1057 DOS_FULL_NAME full_name;
1058 int ret = FALSE;
1059 void * base;
1061 if (!DOSFS_GetFullName( fn, 0, &full_name )) return FALSE;
1063 /* map the registry into the memory */
1064 if ((fd = open(full_name.long_name, O_RDONLY | O_NONBLOCK)) == -1) return FALSE;
1065 if ((fstat(fd, &st) == -1)) goto error;
1066 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1068 switch (*(LPDWORD)base)
1070 /* windows 95 'creg' */
1071 case W95_REG_CREG_ID:
1073 _w95creg * creg;
1074 _w95rgkn * rgkn;
1075 creg = base;
1076 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1078 /* load the header (rgkn) */
1079 rgkn = (_w95rgkn*)(creg + 1);
1080 if (rgkn->id != W95_REG_RGKN_ID)
1082 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1083 goto error1;
1086 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1088 break;
1089 /* nt 'regf'*/
1090 case NT_REG_HEADER_BLOCK_ID:
1092 nt_regf * regf;
1093 nt_hbin * hbin;
1094 nt_hbin_sub * hbin_sub;
1095 nt_nk* nk;
1097 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1099 /* start block */
1100 regf = base;
1102 /* hbin block */
1103 hbin = (nt_hbin*)((char*) base + 0x1000);
1104 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1106 ERR_(reg)( "%s hbin block invalid\n", fn);
1107 goto error1;
1110 /* hbin_sub block */
1111 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1112 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1114 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1115 goto error1;
1118 /* nk block */
1119 nk = (nt_nk*)&(hbin_sub->data[0]);
1120 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1122 ERR_(reg)( "%s special nk block not found\n", fn);
1123 goto error1;
1126 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1128 break;
1129 default:
1131 ERR("unknown signature in registry file %s.\n",fn);
1132 goto error1;
1135 if(!ret) ERR("error loading registry file %s\n", fn);
1136 error1: munmap(base, st.st_size);
1137 error: close(fd);
1138 return ret;
1141 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1143 reghack - windows 3.11 registry data format demo program.
1145 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1146 a combined hash table and tree description, and finally a text table.
1148 The header is obvious from the struct header. The taboff1 and taboff2
1149 fields are always 0x20, and their usage is unknown.
1151 The 8-byte entry table has various entry types.
1153 tabent[0] is a root index. The second word has the index of the root of
1154 the directory.
1155 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1156 the index of the key/value that has that hash. Data with the same
1157 hash value are on a circular list. The other three words in the
1158 hash entry are always zero.
1159 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1160 entry: dirent and keyent/valent. They are identified by context.
1161 tabent[freeidx] is the first free entry. The first word in a free entry
1162 is the index of the next free entry. The last has 0 as a link.
1163 The other three words in the free list are probably irrelevant.
1165 Entries in text table are preceeded by a word at offset-2. This word
1166 has the value (2*index)+1, where index is the referring keyent/valent
1167 entry in the table. I have no suggestion for the 2* and the +1.
1168 Following the word, there are N bytes of data, as per the keyent/valent
1169 entry length. The offset of the keyent/valent entry is from the start
1170 of the text table to the first data byte.
1172 This information is not available from Microsoft. The data format is
1173 deduced from the reg.dat file by me. Mistakes may
1174 have been made. I claim no rights and give no guarantees for this program.
1176 Tor Sjøwall, tor@sn.no
1179 /* reg.dat header format */
1180 struct _w31_header {
1181 char cookie[8]; /* 'SHCC3.10' */
1182 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1183 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1184 unsigned long tabcnt; /* number of entries in index table */
1185 unsigned long textoff; /* offset of text part */
1186 unsigned long textsize; /* byte size of text part */
1187 unsigned short hashsize; /* hash size */
1188 unsigned short freeidx; /* free index */
1191 /* generic format of table entries */
1192 struct _w31_tabent {
1193 unsigned short w0, w1, w2, w3;
1196 /* directory tabent: */
1197 struct _w31_dirent {
1198 unsigned short sibling_idx; /* table index of sibling dirent */
1199 unsigned short child_idx; /* table index of child dirent */
1200 unsigned short key_idx; /* table index of key keyent */
1201 unsigned short value_idx; /* table index of value valent */
1204 /* key tabent: */
1205 struct _w31_keyent {
1206 unsigned short hash_idx; /* hash chain index for string */
1207 unsigned short refcnt; /* reference count */
1208 unsigned short length; /* length of string */
1209 unsigned short string_off; /* offset of string in text table */
1212 /* value tabent: */
1213 struct _w31_valent {
1214 unsigned short hash_idx; /* hash chain index for string */
1215 unsigned short refcnt; /* reference count */
1216 unsigned short length; /* length of string */
1217 unsigned short string_off; /* offset of string in text table */
1220 /* recursive helper function to display a directory tree */
1221 void
1222 __w31_dumptree( unsigned short idx,
1223 unsigned char *txt,
1224 struct _w31_tabent *tab,
1225 struct _w31_header *head,
1226 HKEY hkey,
1227 time_t lastmodified,
1228 int level
1230 struct _w31_dirent *dir;
1231 struct _w31_keyent *key;
1232 struct _w31_valent *val;
1233 HKEY subkey = 0;
1234 static char tail[400];
1236 while (idx!=0) {
1237 dir=(struct _w31_dirent*)&tab[idx];
1239 if (dir->key_idx) {
1240 key = (struct _w31_keyent*)&tab[dir->key_idx];
1242 memcpy(tail,&txt[key->string_off],key->length);
1243 tail[key->length]='\0';
1244 /* all toplevel entries AND the entries in the
1245 * toplevel subdirectory belong to \SOFTWARE\Classes
1247 if (!level && !lstrcmpA(tail,".classes")) {
1248 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1249 idx=dir->sibling_idx;
1250 continue;
1252 if (subkey) RegCloseKey( subkey );
1253 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1254 /* only add if leaf node or valued node */
1255 if (dir->value_idx!=0||dir->child_idx==0) {
1256 if (dir->value_idx) {
1257 val=(struct _w31_valent*)&tab[dir->value_idx];
1258 memcpy(tail,&txt[val->string_off],val->length);
1259 tail[val->length]='\0';
1260 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1263 } else {
1264 TRACE("strange: no directory key name, idx=%04x\n", idx);
1266 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1267 idx=dir->sibling_idx;
1269 if (subkey) RegCloseKey( subkey );
1273 /******************************************************************************
1274 * _w31_loadreg [Internal]
1276 void _w31_loadreg(void) {
1277 HFILE hf;
1278 struct _w31_header head;
1279 struct _w31_tabent *tab;
1280 unsigned char *txt;
1281 int len;
1282 OFSTRUCT ofs;
1283 BY_HANDLE_FILE_INFORMATION hfinfo;
1284 time_t lastmodified;
1286 TRACE("(void)\n");
1288 hf = OpenFile("reg.dat",&ofs,OF_READ);
1289 if (hf==HFILE_ERROR)
1290 return;
1292 /* read & dump header */
1293 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1294 ERR("reg.dat is too short.\n");
1295 _lclose(hf);
1296 return;
1298 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1299 ERR("reg.dat has bad signature.\n");
1300 _lclose(hf);
1301 return;
1304 len = head.tabcnt * sizeof(struct _w31_tabent);
1305 /* read and dump index table */
1306 tab = xmalloc(len);
1307 if (len!=_lread(hf,tab,len)) {
1308 ERR("couldn't read %d bytes.\n",len);
1309 free(tab);
1310 _lclose(hf);
1311 return;
1314 /* read text */
1315 txt = xmalloc(head.textsize);
1316 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1317 ERR("couldn't seek to textblock.\n");
1318 free(tab);
1319 free(txt);
1320 _lclose(hf);
1321 return;
1323 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1324 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1325 free(tab);
1326 free(txt);
1327 _lclose(hf);
1328 return;
1331 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1332 ERR("GetFileInformationByHandle failed?.\n");
1333 free(tab);
1334 free(txt);
1335 _lclose(hf);
1336 return;
1338 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1339 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1340 free(tab);
1341 free(txt);
1342 _lclose(hf);
1343 return;
1347 /* configure save files and start the periodic saving timer */
1348 static void SHELL_InitRegistrySaving(void)
1350 struct set_registry_levels_request *req = get_req_buffer();
1352 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1353 int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
1354 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1356 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1357 req->current = 1;
1358 req->saving = !all;
1359 req->version = version;
1360 req->period = period * 1000;
1361 server_call( REQ_SET_REGISTRY_LEVELS );
1363 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1365 struct save_registry_atexit_request *req = get_req_buffer();
1366 const char *confdir = get_config_dir();
1367 char *str = req->file + strlen(confdir);
1369 if (str + 20 > req->file + server_remaining(req->file))
1371 ERR("config dir '%s' too long\n", confdir );
1372 return;
1375 strcpy( req->file, confdir );
1376 strcpy( str, "/" SAVE_CURRENT_USER );
1377 req->hkey = HKEY_CURRENT_USER;
1378 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1380 strcpy( req->file, confdir );
1381 strcpy( str, "/" SAVE_LOCAL_MACHINE );
1382 req->hkey = HKEY_LOCAL_MACHINE;
1383 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1385 strcpy( req->file, confdir );
1386 strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1387 req->hkey = HKEY_USERS;
1388 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1393 /**********************************************************************************
1394 * SetLoadLevel [Internal]
1396 * set level to 0 for loading system files
1397 * set level to 1 for loading user files
1399 static void SetLoadLevel(int level)
1401 struct set_registry_levels_request *req = get_req_buffer();
1403 req->current = level;
1404 req->saving = 0;
1405 req->version = 1;
1406 req->period = 0;
1407 server_call( REQ_SET_REGISTRY_LEVELS );
1410 /**********************************************************************************
1411 * SHELL_LoadRegistry [Internal]
1413 #define REG_DONTLOAD -1
1414 #define REG_WIN31 0
1415 #define REG_WIN95 1
1416 #define REG_WINNT 2
1418 void SHELL_LoadRegistry( void )
1420 HKEY hkey;
1421 char windir[MAX_PATHNAME_LEN];
1422 char path[MAX_PATHNAME_LEN];
1423 int systemtype = REG_WIN31;
1425 TRACE("(void)\n");
1427 if (!CLIENT_IsBootThread()) return; /* already loaded */
1429 REGISTRY_Init();
1430 SetLoadLevel(0);
1432 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1434 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1436 /* test %windir%/system32/config/system --> winnt */
1437 strcpy(path, windir);
1438 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1439 if(GetFileAttributesA(path) != -1)
1441 systemtype = REG_WINNT;
1443 else
1445 /* test %windir%/system.dat --> win95 */
1446 strcpy(path, windir);
1447 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1448 if(GetFileAttributesA(path) != -1)
1450 systemtype = REG_WIN95;
1454 if ((systemtype==REG_WINNT)
1455 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1457 MESSAGE("When you are running with a native NT directory specify\n");
1458 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1459 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1460 systemtype = REG_DONTLOAD;
1463 else
1465 /* only wine registry */
1466 systemtype = REG_DONTLOAD;
1469 switch (systemtype)
1471 case REG_WIN31:
1472 _w31_loadreg();
1473 break;
1475 case REG_WIN95:
1476 /* Load windows 95 entries */
1477 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1479 strcpy(path, windir);
1480 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1481 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1483 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1485 /* user specific user.dat */
1486 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1487 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1489 MESSAGE("can't load win95 user-registry %s\n", path);
1490 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1492 /* default user.dat */
1493 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1495 strcpy(path, windir);
1496 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1497 NativeRegLoadKey(hkey, path, 1);
1498 RegCloseKey(hkey);
1501 else
1503 /* global user.dat */
1504 strcpy(path, windir);
1505 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1506 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1508 break;
1510 case REG_WINNT:
1511 /* default user.dat */
1512 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1514 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1515 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1517 MESSAGE("can't load NT user-registry %s\n", path);
1518 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1522 /* default user.dat */
1523 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1525 strcpy(path, windir);
1526 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1527 NativeRegLoadKey(hkey, path, 1);
1528 RegCloseKey(hkey);
1532 * FIXME
1533 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1536 strcpy(path, windir);
1537 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1538 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1540 strcpy(path, windir);
1541 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1542 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1544 strcpy(path, windir);
1545 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1546 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1548 strcpy(path, windir);
1549 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1550 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1552 /* this key is generated when the nt-core booted successfully */
1553 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1554 RegCloseKey(hkey);
1555 break;
1556 } /* switch */
1558 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1561 * Load the global HKU hive directly from sysconfdir
1563 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1566 * Load the global machine defaults directly form sysconfdir
1568 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1571 SetLoadLevel(1);
1574 * Load the user saved registries
1576 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1578 const char *confdir = get_config_dir();
1579 int len = strlen(confdir) + 20;
1580 char *fn = path;
1582 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1584 * Load user's personal versions of global HKU/.Default keys
1586 if (fn)
1588 char *str;
1589 strcpy( fn, confdir );
1590 str = fn + strlen(fn);
1591 *str++ = '/';
1593 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1594 _wine_loadreg( HKEY_USERS, fn );
1596 strcpy( str, SAVE_CURRENT_USER );
1597 _wine_loadreg( HKEY_CURRENT_USER, fn );
1599 strcpy( str, SAVE_LOCAL_MACHINE );
1600 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1602 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1606 SHELL_InitRegistrySaving();
1609 /********************* API FUNCTIONS ***************************************/
1614 /******************************************************************************
1615 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1616 * Immediately writes key to registry.
1617 * Only returns after data has been written to disk.
1619 * FIXME: does it really wait until data is written ?
1621 * PARAMS
1622 * hkey [I] Handle of key to write
1624 * RETURNS
1625 * Success: ERROR_SUCCESS
1626 * Failure: Error code
1628 DWORD WINAPI RegFlushKey( HKEY hkey )
1630 FIXME( "(%x): stub\n", hkey );
1631 return ERROR_SUCCESS;
1634 /******************************************************************************
1635 * RegConnectRegistryW [ADVAPI32.128]
1637 * PARAMS
1638 * lpMachineName [I] Address of name of remote computer
1639 * hHey [I] Predefined registry handle
1640 * phkResult [I] Address of buffer for remote registry handle
1642 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1643 LPHKEY phkResult )
1645 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1647 if (!lpMachineName || !*lpMachineName) {
1648 /* Use the local machine name */
1649 return RegOpenKey16( hKey, "", phkResult );
1652 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1653 return ERROR_BAD_NETPATH;
1657 /******************************************************************************
1658 * RegConnectRegistryA [ADVAPI32.127]
1660 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1662 DWORD ret;
1663 LPWSTR machineW = strdupA2W(machine);
1664 ret = RegConnectRegistryW( machineW, hkey, reskey );
1665 free(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 LONG ret;
1744 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1745 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1746 if(lpSubKeyW) free(lpSubKeyW);
1747 return ret;
1751 /******************************************************************************
1752 * RegSetKeySecurity [ADVAPI32.167]
1754 * PARAMS
1755 * hkey [I] Open handle of key to set
1756 * SecurityInfo [I] Descriptor contents
1757 * pSecurityDesc [I] Address of descriptor for key
1759 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1760 PSECURITY_DESCRIPTOR pSecurityDesc )
1762 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1764 /* It seems to perform this check before the hkey check */
1765 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1766 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1767 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1768 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1769 /* Param OK */
1770 } else
1771 return ERROR_INVALID_PARAMETER;
1773 if (!pSecurityDesc)
1774 return ERROR_INVALID_PARAMETER;
1776 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1778 return ERROR_SUCCESS;
1782 /******************************************************************************
1783 * RegRestoreKeyW [ADVAPI32.164]
1785 * PARAMS
1786 * hkey [I] Handle of key where restore begins
1787 * lpFile [I] Address of filename containing saved tree
1788 * dwFlags [I] Optional flags
1790 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1792 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1794 /* It seems to do this check before the hkey check */
1795 if (!lpFile || !*lpFile)
1796 return ERROR_INVALID_PARAMETER;
1798 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1800 /* Check for file existence */
1802 return ERROR_SUCCESS;
1806 /******************************************************************************
1807 * RegRestoreKeyA [ADVAPI32.163]
1809 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1811 LONG ret;
1812 LPWSTR lpFileW = strdupA2W(lpFile);
1813 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1814 if(lpFileW) free(lpFileW);
1815 return ret;
1819 /******************************************************************************
1820 * RegReplaceKeyW [ADVAPI32.162]
1822 * PARAMS
1823 * hkey [I] Handle of open key
1824 * lpSubKey [I] Address of name of subkey
1825 * lpNewFile [I] Address of filename for file with new data
1826 * lpOldFile [I] Address of filename for backup file
1828 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1829 LPCWSTR lpOldFile )
1831 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1832 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1833 return ERROR_SUCCESS;
1837 /******************************************************************************
1838 * RegReplaceKeyA [ADVAPI32.161]
1840 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1841 LPCSTR lpOldFile )
1843 LONG ret;
1844 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1845 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1846 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1847 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1848 free(lpOldFileW);
1849 free(lpNewFileW);
1850 free(lpSubKeyW);
1851 return ret;
1859 /* 16-bit functions */
1861 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1862 * some programs. Do not remove those cases. -MM
1864 static inline void fix_win16_hkey( HKEY *hkey )
1866 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1869 /******************************************************************************
1870 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1872 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1874 fix_win16_hkey( &hkey );
1875 return RegEnumKeyA( hkey, index, name, name_len );
1878 /******************************************************************************
1879 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1881 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1883 fix_win16_hkey( &hkey );
1884 return RegOpenKeyA( hkey, name, retkey );
1887 /******************************************************************************
1888 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1890 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1892 fix_win16_hkey( &hkey );
1893 return RegCreateKeyA( hkey, name, retkey );
1896 /******************************************************************************
1897 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1899 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1901 fix_win16_hkey( &hkey );
1902 return RegDeleteKeyA( hkey, name );
1905 /******************************************************************************
1906 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1908 DWORD WINAPI RegCloseKey16( HKEY hkey )
1910 fix_win16_hkey( &hkey );
1911 return RegCloseKey( hkey );
1914 /******************************************************************************
1915 * RegSetValue16 [KERNEL.221] [SHELL.5]
1917 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1919 fix_win16_hkey( &hkey );
1920 return RegSetValueA( hkey, name, type, data, count );
1923 /******************************************************************************
1924 * RegDeleteValue16 [KERNEL.222]
1926 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1928 fix_win16_hkey( &hkey );
1929 return RegDeleteValueA( hkey, name );
1932 /******************************************************************************
1933 * RegEnumValue16 [KERNEL.223]
1935 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1936 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1938 fix_win16_hkey( &hkey );
1939 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1942 /******************************************************************************
1943 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1945 * NOTES
1946 * Is this HACK still applicable?
1948 * HACK
1949 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1950 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1951 * Aldus FH4)
1953 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1955 fix_win16_hkey( &hkey );
1956 if (count) *count &= 0xffff;
1957 return RegQueryValueA( hkey, name, data, count );
1960 /******************************************************************************
1961 * RegQueryValueEx16 [KERNEL.225]
1963 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1964 LPBYTE data, LPDWORD count )
1966 fix_win16_hkey( &hkey );
1967 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1970 /******************************************************************************
1971 * RegSetValueEx16 [KERNEL.226]
1973 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1974 CONST BYTE *data, DWORD count )
1976 fix_win16_hkey( &hkey );
1977 return RegSetValueExA( hkey, name, reserved, type, data, count );