Removed warnings from freeing path in DeleteDC.
[wine/multimedia.git] / misc / registry.c
blob48320bb426b942db35cd1d2c2372571c3fcf2932
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 (!st.st_size) goto error;
1067 if ((base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) goto error;
1069 switch (*(LPDWORD)base)
1071 /* windows 95 'creg' */
1072 case W95_REG_CREG_ID:
1074 _w95creg * creg;
1075 _w95rgkn * rgkn;
1076 creg = base;
1077 TRACE_(reg)("Loading win95 registry '%s' '%s'\n",fn, full_name.long_name);
1079 /* load the header (rgkn) */
1080 rgkn = (_w95rgkn*)(creg + 1);
1081 if (rgkn->id != W95_REG_RGKN_ID)
1083 ERR("second IFF header not RGKN, but %lx\n", rgkn->id);
1084 goto error1;
1087 ret = _w95_parse_dke(hkey, creg, rgkn, NULL, level);
1089 break;
1090 /* nt 'regf'*/
1091 case NT_REG_HEADER_BLOCK_ID:
1093 nt_regf * regf;
1094 nt_hbin * hbin;
1095 nt_hbin_sub * hbin_sub;
1096 nt_nk* nk;
1098 TRACE_(reg)("Loading nt registry '%s' '%s'\n",fn, full_name.long_name);
1100 /* start block */
1101 regf = base;
1103 /* hbin block */
1104 hbin = (nt_hbin*)((char*) base + 0x1000);
1105 if (hbin->id != NT_REG_POOL_BLOCK_ID)
1107 ERR_(reg)( "%s hbin block invalid\n", fn);
1108 goto error1;
1111 /* hbin_sub block */
1112 hbin_sub = (nt_hbin_sub*)&(hbin->hbin_sub);
1113 if ((hbin_sub->data[0] != 'n') || (hbin_sub->data[1] != 'k'))
1115 ERR_(reg)( "%s hbin_sub block invalid\n", fn);
1116 goto error1;
1119 /* nk block */
1120 nk = (nt_nk*)&(hbin_sub->data[0]);
1121 if (nk->Type != NT_REG_ROOT_KEY_BLOCK_TYPE)
1123 ERR_(reg)( "%s special nk block not found\n", fn);
1124 goto error1;
1127 ret = _nt_parse_nk (hkey, (char *) base + 0x1000, nk, level);
1129 break;
1130 default:
1132 ERR("unknown signature in registry file %s.\n",fn);
1133 goto error1;
1136 if(!ret) ERR("error loading registry file %s\n", fn);
1137 error1: munmap(base, st.st_size);
1138 error: close(fd);
1139 return ret;
1142 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1144 reghack - windows 3.11 registry data format demo program.
1146 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1147 a combined hash table and tree description, and finally a text table.
1149 The header is obvious from the struct header. The taboff1 and taboff2
1150 fields are always 0x20, and their usage is unknown.
1152 The 8-byte entry table has various entry types.
1154 tabent[0] is a root index. The second word has the index of the root of
1155 the directory.
1156 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1157 the index of the key/value that has that hash. Data with the same
1158 hash value are on a circular list. The other three words in the
1159 hash entry are always zero.
1160 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1161 entry: dirent and keyent/valent. They are identified by context.
1162 tabent[freeidx] is the first free entry. The first word in a free entry
1163 is the index of the next free entry. The last has 0 as a link.
1164 The other three words in the free list are probably irrelevant.
1166 Entries in text table are preceeded by a word at offset-2. This word
1167 has the value (2*index)+1, where index is the referring keyent/valent
1168 entry in the table. I have no suggestion for the 2* and the +1.
1169 Following the word, there are N bytes of data, as per the keyent/valent
1170 entry length. The offset of the keyent/valent entry is from the start
1171 of the text table to the first data byte.
1173 This information is not available from Microsoft. The data format is
1174 deduced from the reg.dat file by me. Mistakes may
1175 have been made. I claim no rights and give no guarantees for this program.
1177 Tor Sjøwall, tor@sn.no
1180 /* reg.dat header format */
1181 struct _w31_header {
1182 char cookie[8]; /* 'SHCC3.10' */
1183 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1184 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1185 unsigned long tabcnt; /* number of entries in index table */
1186 unsigned long textoff; /* offset of text part */
1187 unsigned long textsize; /* byte size of text part */
1188 unsigned short hashsize; /* hash size */
1189 unsigned short freeidx; /* free index */
1192 /* generic format of table entries */
1193 struct _w31_tabent {
1194 unsigned short w0, w1, w2, w3;
1197 /* directory tabent: */
1198 struct _w31_dirent {
1199 unsigned short sibling_idx; /* table index of sibling dirent */
1200 unsigned short child_idx; /* table index of child dirent */
1201 unsigned short key_idx; /* table index of key keyent */
1202 unsigned short value_idx; /* table index of value valent */
1205 /* key tabent: */
1206 struct _w31_keyent {
1207 unsigned short hash_idx; /* hash chain index for string */
1208 unsigned short refcnt; /* reference count */
1209 unsigned short length; /* length of string */
1210 unsigned short string_off; /* offset of string in text table */
1213 /* value tabent: */
1214 struct _w31_valent {
1215 unsigned short hash_idx; /* hash chain index for string */
1216 unsigned short refcnt; /* reference count */
1217 unsigned short length; /* length of string */
1218 unsigned short string_off; /* offset of string in text table */
1221 /* recursive helper function to display a directory tree */
1222 void
1223 __w31_dumptree( unsigned short idx,
1224 unsigned char *txt,
1225 struct _w31_tabent *tab,
1226 struct _w31_header *head,
1227 HKEY hkey,
1228 time_t lastmodified,
1229 int level
1231 struct _w31_dirent *dir;
1232 struct _w31_keyent *key;
1233 struct _w31_valent *val;
1234 HKEY subkey = 0;
1235 static char tail[400];
1237 while (idx!=0) {
1238 dir=(struct _w31_dirent*)&tab[idx];
1240 if (dir->key_idx) {
1241 key = (struct _w31_keyent*)&tab[dir->key_idx];
1243 memcpy(tail,&txt[key->string_off],key->length);
1244 tail[key->length]='\0';
1245 /* all toplevel entries AND the entries in the
1246 * toplevel subdirectory belong to \SOFTWARE\Classes
1248 if (!level && !lstrcmpA(tail,".classes")) {
1249 __w31_dumptree(dir->child_idx,txt,tab,head,hkey,lastmodified,level+1);
1250 idx=dir->sibling_idx;
1251 continue;
1253 if (subkey) RegCloseKey( subkey );
1254 if (RegCreateKeyA( hkey, tail, &subkey ) != ERROR_SUCCESS) subkey = 0;
1255 /* only add if leaf node or valued node */
1256 if (dir->value_idx!=0||dir->child_idx==0) {
1257 if (dir->value_idx) {
1258 val=(struct _w31_valent*)&tab[dir->value_idx];
1259 memcpy(tail,&txt[val->string_off],val->length);
1260 tail[val->length]='\0';
1261 RegSetValueA( subkey, NULL, REG_SZ, tail, 0 );
1264 } else {
1265 TRACE("strange: no directory key name, idx=%04x\n", idx);
1267 __w31_dumptree(dir->child_idx,txt,tab,head,subkey,lastmodified,level+1);
1268 idx=dir->sibling_idx;
1270 if (subkey) RegCloseKey( subkey );
1274 /******************************************************************************
1275 * _w31_loadreg [Internal]
1277 void _w31_loadreg(void) {
1278 HFILE hf;
1279 struct _w31_header head;
1280 struct _w31_tabent *tab;
1281 unsigned char *txt;
1282 int len;
1283 OFSTRUCT ofs;
1284 BY_HANDLE_FILE_INFORMATION hfinfo;
1285 time_t lastmodified;
1287 TRACE("(void)\n");
1289 hf = OpenFile("reg.dat",&ofs,OF_READ);
1290 if (hf==HFILE_ERROR)
1291 return;
1293 /* read & dump header */
1294 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1295 ERR("reg.dat is too short.\n");
1296 _lclose(hf);
1297 return;
1299 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1300 ERR("reg.dat has bad signature.\n");
1301 _lclose(hf);
1302 return;
1305 len = head.tabcnt * sizeof(struct _w31_tabent);
1306 /* read and dump index table */
1307 tab = xmalloc(len);
1308 if (len!=_lread(hf,tab,len)) {
1309 ERR("couldn't read %d bytes.\n",len);
1310 free(tab);
1311 _lclose(hf);
1312 return;
1315 /* read text */
1316 txt = xmalloc(head.textsize);
1317 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1318 ERR("couldn't seek to textblock.\n");
1319 free(tab);
1320 free(txt);
1321 _lclose(hf);
1322 return;
1324 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1325 ERR("textblock too short (%d instead of %ld).\n",len,head.textsize);
1326 free(tab);
1327 free(txt);
1328 _lclose(hf);
1329 return;
1332 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1333 ERR("GetFileInformationByHandle failed?.\n");
1334 free(tab);
1335 free(txt);
1336 _lclose(hf);
1337 return;
1339 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1340 __w31_dumptree(tab[0].w1,txt,tab,&head,HKEY_CLASSES_ROOT,lastmodified,0);
1341 free(tab);
1342 free(txt);
1343 _lclose(hf);
1344 return;
1348 /* configure save files and start the periodic saving timer */
1349 static void SHELL_InitRegistrySaving(void)
1351 struct set_registry_levels_request *req = get_req_buffer();
1353 int all = PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1354 int version = PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
1355 int period = PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1357 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1358 req->current = 1;
1359 req->saving = !all;
1360 req->version = version;
1361 req->period = period * 1000;
1362 server_call( REQ_SET_REGISTRY_LEVELS );
1364 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1366 struct save_registry_atexit_request *req = get_req_buffer();
1367 const char *confdir = get_config_dir();
1368 char *str = req->file + strlen(confdir);
1370 if (str + 20 > req->file + server_remaining(req->file))
1372 ERR("config dir '%s' too long\n", confdir );
1373 return;
1376 strcpy( req->file, confdir );
1377 strcpy( str, "/" SAVE_CURRENT_USER );
1378 req->hkey = HKEY_CURRENT_USER;
1379 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1381 strcpy( req->file, confdir );
1382 strcpy( str, "/" SAVE_LOCAL_MACHINE );
1383 req->hkey = HKEY_LOCAL_MACHINE;
1384 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1386 strcpy( req->file, confdir );
1387 strcpy( str, "/" SAVE_LOCAL_USERS_DEFAULT );
1388 req->hkey = HKEY_USERS;
1389 server_call( REQ_SAVE_REGISTRY_ATEXIT );
1394 /**********************************************************************************
1395 * SetLoadLevel [Internal]
1397 * set level to 0 for loading system files
1398 * set level to 1 for loading user files
1400 static void SetLoadLevel(int level)
1402 struct set_registry_levels_request *req = get_req_buffer();
1404 req->current = level;
1405 req->saving = 0;
1406 req->version = 1;
1407 req->period = 0;
1408 server_call( REQ_SET_REGISTRY_LEVELS );
1411 /**********************************************************************************
1412 * SHELL_LoadRegistry [Internal]
1414 #define REG_DONTLOAD -1
1415 #define REG_WIN31 0
1416 #define REG_WIN95 1
1417 #define REG_WINNT 2
1419 void SHELL_LoadRegistry( void )
1421 HKEY hkey;
1422 char windir[MAX_PATHNAME_LEN];
1423 char path[MAX_PATHNAME_LEN];
1424 int systemtype = REG_WIN31;
1426 TRACE("(void)\n");
1428 if (!CLIENT_IsBootThread()) return; /* already loaded */
1430 REGISTRY_Init();
1431 SetLoadLevel(0);
1433 GetWindowsDirectoryA( windir, MAX_PATHNAME_LEN );
1435 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1437 /* test %windir%/system32/config/system --> winnt */
1438 strcpy(path, windir);
1439 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1440 if(GetFileAttributesA(path) != -1)
1442 systemtype = REG_WINNT;
1444 else
1446 /* test %windir%/system.dat --> win95 */
1447 strcpy(path, windir);
1448 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1449 if(GetFileAttributesA(path) != -1)
1451 systemtype = REG_WIN95;
1455 if ((systemtype==REG_WINNT)
1456 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN)))
1458 MESSAGE("When you are running with a native NT directory specify\n");
1459 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1460 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1461 systemtype = REG_DONTLOAD;
1464 else
1466 /* only wine registry */
1467 systemtype = REG_DONTLOAD;
1470 switch (systemtype)
1472 case REG_WIN31:
1473 _w31_loadreg();
1474 break;
1476 case REG_WIN95:
1477 /* Load windows 95 entries */
1478 NativeRegLoadKey(HKEY_LOCAL_MACHINE, "C:\\system.1st", 0);
1480 strcpy(path, windir);
1481 strncat(path, "\\system.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1482 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1484 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1486 /* user specific user.dat */
1487 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1488 if (!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1490 MESSAGE("can't load win95 user-registry %s\n", path);
1491 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1493 /* default user.dat */
1494 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1496 strcpy(path, windir);
1497 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1498 NativeRegLoadKey(hkey, path, 1);
1499 RegCloseKey(hkey);
1502 else
1504 /* global user.dat */
1505 strcpy(path, windir);
1506 strncat(path, "\\user.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1507 NativeRegLoadKey(HKEY_CURRENT_USER, path, 1);
1509 break;
1511 case REG_WINNT:
1512 /* default user.dat */
1513 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path, MAX_PATHNAME_LEN))
1515 strncat(path, "\\ntuser.dat", MAX_PATHNAME_LEN - strlen(path) - 1);
1516 if(!NativeRegLoadKey( HKEY_CURRENT_USER, path, 1 ))
1518 MESSAGE("can't load NT user-registry %s\n", path);
1519 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1523 /* default user.dat */
1524 if (!RegCreateKeyA(HKEY_USERS, ".Default", &hkey))
1526 strcpy(path, windir);
1527 strncat(path, "\\system32\\config\\default", MAX_PATHNAME_LEN - strlen(path) - 1);
1528 NativeRegLoadKey(hkey, path, 1);
1529 RegCloseKey(hkey);
1533 * FIXME
1534 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1537 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM", &hkey))
1539 strcpy(path, windir);
1540 strncat(path, "\\system32\\config\\system", MAX_PATHNAME_LEN - strlen(path) - 1);
1541 NativeRegLoadKey(hkey, path, 1);
1542 RegCloseKey(hkey);
1545 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &hkey))
1547 strcpy(path, windir);
1548 strncat(path, "\\system32\\config\\software", MAX_PATHNAME_LEN - strlen(path) - 1);
1549 NativeRegLoadKey(hkey, path, 1);
1550 RegCloseKey(hkey);
1553 strcpy(path, windir);
1554 strncat(path, "\\system32\\config\\sam", MAX_PATHNAME_LEN - strlen(path) - 1);
1555 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1557 strcpy(path, windir);
1558 strncat(path, "\\system32\\config\\security", MAX_PATHNAME_LEN - strlen(path) - 1);
1559 NativeRegLoadKey(HKEY_LOCAL_MACHINE, path, 0);
1561 /* this key is generated when the nt-core booted successfully */
1562 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE,"System\\Clone",&hkey))
1563 RegCloseKey(hkey);
1564 break;
1565 } /* switch */
1567 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1570 * Load the global HKU hive directly from sysconfdir
1572 _wine_loadreg( HKEY_USERS, SAVE_USERS_DEFAULT );
1575 * Load the global machine defaults directly form sysconfdir
1577 _wine_loadreg( HKEY_LOCAL_MACHINE, SAVE_LOCAL_MACHINE_DEFAULT );
1580 SetLoadLevel(1);
1583 * Load the user saved registries
1585 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1587 const char *confdir = get_config_dir();
1588 int len = strlen(confdir) + 20;
1589 char *fn = path;
1591 if (len > sizeof(path)) fn = HeapAlloc( GetProcessHeap(), 0, len );
1593 * Load user's personal versions of global HKU/.Default keys
1595 if (fn)
1597 char *str;
1598 strcpy( fn, confdir );
1599 str = fn + strlen(fn);
1600 *str++ = '/';
1602 strcpy( str, SAVE_LOCAL_USERS_DEFAULT );
1603 _wine_loadreg( HKEY_USERS, fn );
1605 strcpy( str, SAVE_CURRENT_USER );
1606 _wine_loadreg( HKEY_CURRENT_USER, fn );
1608 strcpy( str, SAVE_LOCAL_MACHINE );
1609 _wine_loadreg( HKEY_LOCAL_MACHINE, fn );
1611 if (fn != path) HeapFree( GetProcessHeap(), 0, fn );
1615 SHELL_InitRegistrySaving();
1618 /********************* API FUNCTIONS ***************************************/
1623 /******************************************************************************
1624 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1625 * Immediately writes key to registry.
1626 * Only returns after data has been written to disk.
1628 * FIXME: does it really wait until data is written ?
1630 * PARAMS
1631 * hkey [I] Handle of key to write
1633 * RETURNS
1634 * Success: ERROR_SUCCESS
1635 * Failure: Error code
1637 DWORD WINAPI RegFlushKey( HKEY hkey )
1639 FIXME( "(%x): stub\n", hkey );
1640 return ERROR_SUCCESS;
1643 /******************************************************************************
1644 * RegConnectRegistryW [ADVAPI32.128]
1646 * PARAMS
1647 * lpMachineName [I] Address of name of remote computer
1648 * hHey [I] Predefined registry handle
1649 * phkResult [I] Address of buffer for remote registry handle
1651 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
1652 LPHKEY phkResult )
1654 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
1656 if (!lpMachineName || !*lpMachineName) {
1657 /* Use the local machine name */
1658 return RegOpenKey16( hKey, "", phkResult );
1661 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName));
1662 return ERROR_BAD_NETPATH;
1666 /******************************************************************************
1667 * RegConnectRegistryA [ADVAPI32.127]
1669 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
1671 DWORD ret;
1672 LPWSTR machineW = strdupA2W(machine);
1673 ret = RegConnectRegistryW( machineW, hkey, reskey );
1674 free(machineW);
1675 return ret;
1679 /******************************************************************************
1680 * RegGetKeySecurity [ADVAPI32.144]
1681 * Retrieves a copy of security descriptor protecting the registry key
1683 * PARAMS
1684 * hkey [I] Open handle of key to set
1685 * SecurityInformation [I] Descriptor contents
1686 * pSecurityDescriptor [O] Address of descriptor for key
1687 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1689 * RETURNS
1690 * Success: ERROR_SUCCESS
1691 * Failure: Error code
1693 LONG WINAPI RegGetKeySecurity( HKEY hkey,
1694 SECURITY_INFORMATION SecurityInformation,
1695 PSECURITY_DESCRIPTOR pSecurityDescriptor,
1696 LPDWORD lpcbSecurityDescriptor )
1698 TRACE("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
1699 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1701 /* FIXME: Check for valid SecurityInformation values */
1703 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
1704 return ERROR_INSUFFICIENT_BUFFER;
1706 FIXME("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
1707 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
1709 return ERROR_SUCCESS;
1713 /******************************************************************************
1714 * RegNotifyChangeKeyValue [ADVAPI32.???]
1716 * PARAMS
1717 * hkey [I] Handle of key to watch
1718 * fWatchSubTree [I] Flag for subkey notification
1719 * fdwNotifyFilter [I] Changes to be reported
1720 * hEvent [I] Handle of signaled event
1721 * fAsync [I] Flag for asynchronous reporting
1723 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
1724 DWORD fdwNotifyFilter, HANDLE hEvent,
1725 BOOL fAsync )
1727 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
1728 hEvent,fAsync);
1729 return ERROR_SUCCESS;
1733 /******************************************************************************
1734 * RegUnLoadKeyW [ADVAPI32.173]
1736 * PARAMS
1737 * hkey [I] Handle of open key
1738 * lpSubKey [I] Address of name of subkey to unload
1740 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
1742 FIXME("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
1743 return ERROR_SUCCESS;
1747 /******************************************************************************
1748 * RegUnLoadKeyA [ADVAPI32.172]
1750 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
1752 LONG ret;
1753 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1754 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
1755 if(lpSubKeyW) free(lpSubKeyW);
1756 return ret;
1760 /******************************************************************************
1761 * RegSetKeySecurity [ADVAPI32.167]
1763 * PARAMS
1764 * hkey [I] Open handle of key to set
1765 * SecurityInfo [I] Descriptor contents
1766 * pSecurityDesc [I] Address of descriptor for key
1768 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
1769 PSECURITY_DESCRIPTOR pSecurityDesc )
1771 TRACE("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
1773 /* It seems to perform this check before the hkey check */
1774 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
1775 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
1776 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
1777 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
1778 /* Param OK */
1779 } else
1780 return ERROR_INVALID_PARAMETER;
1782 if (!pSecurityDesc)
1783 return ERROR_INVALID_PARAMETER;
1785 FIXME(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
1787 return ERROR_SUCCESS;
1791 /******************************************************************************
1792 * RegRestoreKeyW [ADVAPI32.164]
1794 * PARAMS
1795 * hkey [I] Handle of key where restore begins
1796 * lpFile [I] Address of filename containing saved tree
1797 * dwFlags [I] Optional flags
1799 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
1801 TRACE("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
1803 /* It seems to do this check before the hkey check */
1804 if (!lpFile || !*lpFile)
1805 return ERROR_INVALID_PARAMETER;
1807 FIXME("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
1809 /* Check for file existence */
1811 return ERROR_SUCCESS;
1815 /******************************************************************************
1816 * RegRestoreKeyA [ADVAPI32.163]
1818 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
1820 LONG ret;
1821 LPWSTR lpFileW = strdupA2W(lpFile);
1822 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
1823 if(lpFileW) free(lpFileW);
1824 return ret;
1828 /******************************************************************************
1829 * RegReplaceKeyW [ADVAPI32.162]
1831 * PARAMS
1832 * hkey [I] Handle of open key
1833 * lpSubKey [I] Address of name of subkey
1834 * lpNewFile [I] Address of filename for file with new data
1835 * lpOldFile [I] Address of filename for backup file
1837 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
1838 LPCWSTR lpOldFile )
1840 FIXME("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
1841 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
1842 return ERROR_SUCCESS;
1846 /******************************************************************************
1847 * RegReplaceKeyA [ADVAPI32.161]
1849 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
1850 LPCSTR lpOldFile )
1852 LONG ret;
1853 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
1854 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
1855 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
1856 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
1857 free(lpOldFileW);
1858 free(lpNewFileW);
1859 free(lpSubKeyW);
1860 return ret;
1868 /* 16-bit functions */
1870 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1871 * some programs. Do not remove those cases. -MM
1873 static inline void fix_win16_hkey( HKEY *hkey )
1875 if (*hkey == 0 || *hkey == 1) *hkey = HKEY_CLASSES_ROOT;
1878 /******************************************************************************
1879 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1881 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
1883 fix_win16_hkey( &hkey );
1884 return RegEnumKeyA( hkey, index, name, name_len );
1887 /******************************************************************************
1888 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1890 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1892 fix_win16_hkey( &hkey );
1893 return RegOpenKeyA( hkey, name, retkey );
1896 /******************************************************************************
1897 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1899 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR name, LPHKEY retkey )
1901 fix_win16_hkey( &hkey );
1902 return RegCreateKeyA( hkey, name, retkey );
1905 /******************************************************************************
1906 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1908 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR name )
1910 fix_win16_hkey( &hkey );
1911 return RegDeleteKeyA( hkey, name );
1914 /******************************************************************************
1915 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1917 DWORD WINAPI RegCloseKey16( HKEY hkey )
1919 fix_win16_hkey( &hkey );
1920 return RegCloseKey( hkey );
1923 /******************************************************************************
1924 * RegSetValue16 [KERNEL.221] [SHELL.5]
1926 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
1928 fix_win16_hkey( &hkey );
1929 return RegSetValueA( hkey, name, type, data, count );
1932 /******************************************************************************
1933 * RegDeleteValue16 [KERNEL.222]
1935 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR name )
1937 fix_win16_hkey( &hkey );
1938 return RegDeleteValueA( hkey, name );
1941 /******************************************************************************
1942 * RegEnumValue16 [KERNEL.223]
1944 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
1945 LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
1947 fix_win16_hkey( &hkey );
1948 return RegEnumValueA( hkey, index, value, val_count, reserved, type, data, count );
1951 /******************************************************************************
1952 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1954 * NOTES
1955 * Is this HACK still applicable?
1957 * HACK
1958 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1959 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1960 * Aldus FH4)
1962 DWORD WINAPI RegQueryValue16( HKEY hkey, LPCSTR name, LPSTR data, LPDWORD count )
1964 fix_win16_hkey( &hkey );
1965 if (count) *count &= 0xffff;
1966 return RegQueryValueA( hkey, name, data, count );
1969 /******************************************************************************
1970 * RegQueryValueEx16 [KERNEL.225]
1972 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
1973 LPBYTE data, LPDWORD count )
1975 fix_win16_hkey( &hkey );
1976 return RegQueryValueExA( hkey, name, reserved, type, data, count );
1979 /******************************************************************************
1980 * RegSetValueEx16 [KERNEL.226]
1982 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
1983 CONST BYTE *data, DWORD count )
1985 fix_win16_hkey( &hkey );
1986 return RegSetValueExA( hkey, name, reserved, type, data, count );