4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
34 #include <sys/types.h>
36 #include <sys/fcntl.h>
42 #include "wine/winbase16.h"
43 #include "wine/winestring.h"
47 #include "debugtools.h"
53 DEFAULT_DEBUG_CHANNEL(reg
);
55 static void REGISTRY_Init(void);
56 /* FIXME: following defines should be configured global ... */
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
70 static void *xmalloc( size_t size
)
74 res
= malloc (size
? size
: 1);
76 WARN("Virtual memory exhausted.\n");
84 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
85 * If so, can we remove them?
87 * No, the memory handling functions are called very often in here,
88 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
89 * loading 100 times slower. -MM
91 static LPWSTR
strdupA2W(LPCSTR src
)
94 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
95 lstrcpyAtoW(dest
,src
);
101 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
104 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
106 lstrcpynAtoW(dest
,src
,nchars
+1);
112 /******************************************************************************
113 * REGISTRY_Init [Internal]
114 * Registry initialisation, allocates some default keys.
116 static void REGISTRY_Init(void) {
122 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
125 /* This was an Open, but since it is called before the real registries
126 are loaded, it was changed to a Create - MTB 980507*/
127 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
128 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
131 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
135 * string RegisteredOwner
136 * string RegisteredOrganization
139 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
144 if (-1!=gethostname(buf
,200)) {
145 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
146 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
152 /************************ LOAD Registry Function ****************************/
156 /******************************************************************************
157 * _find_or_add_key [Internal]
159 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
162 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
163 if (keyname
) free( keyname
);
167 /******************************************************************************
168 * _find_or_add_value [Internal]
170 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
172 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
173 if (name
) free( name
);
174 if (data
) free( data
);
178 /******************************************************************************
179 * _wine_read_line [Internal]
181 * reads a line including dynamically enlarging the readbuffer and throwing
184 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
194 s
=fgets(curread
,mylen
,F
);
197 if (NULL
==(s
=strchr(curread
,'\n'))) {
198 /* buffer wasn't large enough */
199 curoff
= strlen(*buf
);
200 curread
= realloc(*buf
,*len
*2);
201 if(curread
== NULL
) {
202 WARN("Out of memory");
207 mylen
= *len
; /* we filled up the buffer and
208 * got new '*len' bytes to fill
216 /* throw away comments */
217 if (**buf
=='#' || **buf
==';') {
222 if (s
) /* got end of line */
229 /******************************************************************************
230 * _wine_read_USTRING [Internal]
232 * converts a char* into a UNICODE string (up to a special char)
233 * and returns the position exactly after that string
235 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
240 /* read up to "=" or "\0" or "\n" */
242 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
244 while (*s
&& (*s
!='\n') && (*s
!='=')) {
246 *ws
++=*((unsigned char*)s
++);
250 /* Dangling \ ... may only happen if a registry
251 * write was short. FIXME: What do to?
261 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
269 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
270 if (!sscanf(xbuf
,"%x",&wc
))
271 WARN("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
273 *ws
++ =(unsigned short)wc
;
282 /******************************************************************************
283 * _wine_loadsubkey [Internal]
286 * It seems like this is returning a boolean. Should it?
292 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
299 TRACE("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
301 /* Good. We already got a line here ... so parse it */
311 WARN("Got a subhierarchy without resp. key?\n");
314 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
315 if (!_wine_read_line(F
,buf
,buflen
))
320 /* let the caller handle this line */
321 if (i
<level
|| **buf
=='\0')
324 /* it can be: a value or a keyname. Parse the name first */
325 s
=_wine_read_USTRING(s
,&name
);
327 /* switch() default: hack to avoid gotos */
331 if (subkey
) RegCloseKey( subkey
);
332 subkey
=_find_or_add_key(hkey
,name
);
335 int len
,lastmodified
,type
;
338 WARN("Unexpected character: %c\n",*s
);
342 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
343 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
350 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
353 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
354 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
355 len
= lstrlenW((LPWSTR
)data
)*2+2;
358 data
= (LPBYTE
)xmalloc(len
+1);
359 for (i
=0;i
<len
;i
++) {
361 if (*s
>='0' && *s
<='9')
363 if (*s
>='a' && *s
<='f')
364 data
[i
]=(*s
-'a'+'\xa')<<4;
365 if (*s
>='A' && *s
<='F')
366 data
[i
]=(*s
-'A'+'\xa')<<4;
368 if (*s
>='0' && *s
<='9')
370 if (*s
>='a' && *s
<='f')
371 data
[i
]|=*s
-'a'+'\xa';
372 if (*s
>='A' && *s
<='F')
373 data
[i
]|=*s
-'A'+'\xa';
377 _find_or_add_value(hkey
,name
,type
,data
,len
);
380 /* read the next line */
381 if (!_wine_read_line(F
,buf
,buflen
))
385 if (subkey
) RegCloseKey( subkey
);
390 /******************************************************************************
391 * _wine_loadsubreg [Internal]
393 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
399 buf
=xmalloc(10);buflen
=10;
400 if (!_wine_read_line(F
,&buf
,&buflen
)) {
404 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
409 if (ver
== 2) /* new version */
412 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
413 FILE_ATTRIBUTE_NORMAL
, -1, TRUE
)) != INVALID_HANDLE_VALUE
)
415 struct load_registry_request
*req
= get_req_buffer();
419 server_call( REQ_LOAD_REGISTRY
);
427 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
432 if (!_wine_read_line(F
,&buf
,&buflen
)) {
436 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
445 /******************************************************************************
446 * _wine_loadreg [Internal]
448 static void _wine_loadreg( HKEY hkey
, char *fn
)
452 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
456 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
459 _wine_loadsubreg(F
,hkey
,fn
);
463 /* NT REGISTRY LOADER */
465 #ifdef HAVE_SYS_MMAN_H
466 # include <sys/mman.h>
470 #define MAP_FAILED ((LPVOID)-1)
473 #define NT_REG_BLOCK_SIZE 0x1000
475 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
476 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
477 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
478 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
480 /* subblocks of nk */
481 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
482 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
483 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
485 #define NT_REG_KEY_BLOCK_TYPE 0x20
486 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
490 DWORD id
; /* 0x66676572 'regf'*/
491 DWORD uk1
; /* 0x04 */
492 DWORD uk2
; /* 0x08 */
493 FILETIME DateModified
; /* 0x0c */
494 DWORD uk3
; /* 0x14 */
495 DWORD uk4
; /* 0x18 */
496 DWORD uk5
; /* 0x1c */
497 DWORD uk6
; /* 0x20 */
498 DWORD RootKeyBlock
; /* 0x24 */
499 DWORD BlockSize
; /* 0x28 */
501 DWORD Checksum
; /* at offset 0x1FC */
512 DWORD id
; /* 0x6E696268 'hbin' */
516 DWORD uk2
; /* 0x10 */
517 DWORD uk3
; /* 0x14 */
518 DWORD uk4
; /* 0x18 */
519 DWORD size
; /* 0x1C */
520 nt_hbin_sub hbin_sub
; /* 0x20 */
524 * the value_list consists of offsets to the values (vk)
528 WORD SubBlockId
; /* 0x00 0x6B6E */
529 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
530 FILETIME writetime
; /* 0x04 */
531 DWORD uk1
; /* 0x0C */
532 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
533 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
534 DWORD uk8
; /* 0x18 */
535 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
536 DWORD uk2
; /* 0x20 */
537 DWORD nr_values
; /* 0x24 number of values */
538 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
539 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
540 DWORD off_class
; /* 0x30 Offset of the Class-Name */
541 DWORD uk3
; /* 0x34 */
542 DWORD uk4
; /* 0x38 */
543 DWORD uk5
; /* 0x3c */
544 DWORD uk6
; /* 0x40 */
545 DWORD uk7
; /* 0x44 */
546 WORD name_len
; /* 0x48 name-length */
547 WORD class_len
; /* 0x4a class-name length */
548 char name
[1]; /* 0x4c key-name */
553 DWORD off_nk
; /* 0x00 */
554 DWORD name
; /* 0x04 */
559 WORD id
; /* 0x00 0x666c */
560 WORD nr_keys
; /* 0x06 */
561 hash_rec hash_rec
[1];
565 list of subkeys without hash
573 WORD id
; /* 0x00 0x696c */
579 this is a intermediate node
591 WORD id
; /* 0x00 0x6972 */
592 WORD nr_li
; /* 0x02 number off offsets */
593 DWORD off_li
[1]; /* 0x04 points to li */
598 WORD id
; /* 0x00 'vk' */
608 LPSTR
_strdupnA( LPCSTR str
, int len
)
612 if (!str
) return NULL
;
613 ret
= malloc( len
+ 1 );
614 lstrcpynA( ret
, str
, len
);
619 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
);
620 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
);
621 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
);
628 * 0 value is a default value
629 * 1 the value has a name
632 * len of the whole data block
634 * bytes including the terminating \0 = 2*(number_of_chars+1)
635 * - reg_dword, reg_binary:
636 * if highest bit of data_len is set data_off contains the value
638 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
)
642 BYTE
* pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
644 if(vk
->id
!= NT_REG_VALUE_BLOCK_ID
) goto error
;
646 lstrcpynAtoW(name
, vk
->name
, vk
->nam_len
+1);
648 ret
= RegSetValueExW( hkey
, (vk
->flag
& 0x00000001) ? name
: NULL
, 0, vk
->type
,
649 (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
,
650 (vk
->data_len
& 0x7fffffff) );
651 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
654 ERR_(reg
)("unknown block found (0x%04x), please report!\n", vk
->id
);
661 * this structure contains the hash of a keyname and points to all
664 * exception: if the id is 'il' there are no hash values and every
667 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
)
671 if (lf
->id
== NT_REG_HASH_BLOCK_ID
)
673 if (subkeys
!= lf
->nr_keys
) goto error1
;
675 for (i
=0; i
<lf
->nr_keys
; i
++)
677 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), level
)) goto error
;
680 else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
)
682 nt_li
* li
= (nt_li
*)lf
;
683 if (subkeys
!= li
->nr_keys
) goto error1
;
685 for (i
=0; i
<li
->nr_keys
; i
++)
687 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), level
)) goto error
;
690 else if (lf
->id
== NT_REG_RI_BLOCK_ID
) /* ri */
692 nt_ri
* ri
= (nt_ri
*)lf
;
695 /* count all subkeys */
696 for (i
=0; i
<ri
->nr_li
; i
++)
698 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
699 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
700 li_subkeys
+= li
->nr_keys
;
704 if (subkeys
!= li_subkeys
) goto error1
;
706 /* loop through the keys */
707 for (i
=0; i
<ri
->nr_li
; i
++)
709 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
710 if (!_nt_parse_lf(hkey
, base
, li
->nr_keys
, (nt_lf
*)li
, level
)) goto error
;
719 error2
: ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
722 error1
: ERR_(reg
)("registry file corrupt! (inconsistent number of subkeys)\n");
725 error
: ERR_(reg
)("error reading lf block\n");
729 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
736 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)
738 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
742 if((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) &&
743 (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
))
745 ERR_(reg
)("registry file corrupt!\n");
749 /* create the new key */
752 name
= _strdupnA( nk
->name
, nk
->name_len
+1);
753 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
757 /* loop through the subkeys */
760 nt_lf
* lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
761 if (!_nt_parse_lf(subkey
, base
, nk
->nr_subkeys
, lf
, level
-1)) goto error1
;
764 /* loop trough the value list */
765 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
766 for (i
=0; i
<nk
->nr_values
; i
++)
768 nt_vk
* vk
= (nt_vk
*)(base
+vl
[i
]+4);
769 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
775 error1
: RegCloseKey(subkey
);
781 /* windows 95 registry loader */
783 /* SECTION 1: main header
787 #define W95_REG_CREG_ID 0x47455243
791 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
792 DWORD version
; /* ???? 0x00010000 */
793 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
794 DWORD uk2
; /* 0x0c */
795 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
801 /* SECTION 2: Directory information (tree structure)
803 * once on offset 0x20
805 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
807 #define W95_REG_RGKN_ID 0x4e4b4752
811 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
812 DWORD size
; /* Size of the RGKN-block */
813 DWORD root_off
; /* Rel. Offset of the root-record */
817 /* Disk Key Entry Structure
819 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
820 * hive itself. It looks the same like other keys. Even the ID-number can
823 * The "hash"-value is a value representing the key's name. Windows will not
824 * search for the name, but for a matching hash-value. if it finds one, it
825 * will compare the actual string info, otherwise continue with the next key.
826 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
827 * of the string which are smaller than 0x80 (128) to this D-Word.
829 * If you want to modify key names, also modify the hash-values, since they
830 * cannot be found again (although they would be displayed in REGEDIT)
831 * End of list-pointers are filled with 0xFFFFFFFF
833 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
834 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
835 * structure) and reading another RGDB_section.
837 * there is a one to one relationship between dke and dkh
839 /* key struct, once per key */
842 DWORD x1
; /* Free entry indicator(?) */
843 DWORD hash
; /* sum of bytes of keyname */
844 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
845 DWORD prevlvl
; /* offset of previous key */
846 DWORD nextsub
; /* offset of child key */
847 DWORD next
; /* offset of sibling key */
848 WORD nrLS
; /* id inside the rgdb block */
849 WORD nrMS
; /* number of the rgdb block */
852 /* SECTION 3: key information, values and data
855 * section: [blocks]* (repeat creg->rgdb_num times)
856 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
857 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
859 * An interesting relationship exists in RGDB_section. The value at offset
860 * 10 equals the value at offset 4 minus the value at offset 8. I have no
861 * idea at the moment what this means. (Kevin Cozens)
864 /* block header, once per block */
865 #define W95_REG_RGDB_ID 0x42444752
869 DWORD id
; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
870 DWORD size
; /* 0x04 */
871 DWORD uk1
; /* 0x08 */
872 DWORD uk2
; /* 0x0c */
873 DWORD uk3
; /* 0x10 */
874 DWORD uk4
; /* 0x14 */
875 DWORD uk5
; /* 0x18 */
876 DWORD uk6
; /* 0x1c */
880 /* Disk Key Header structure (RGDB part), once per key */
883 DWORD nextkeyoff
; /* 0x00 offset to next dkh*/
884 WORD nrLS
; /* 0x04 id inside the rgdb block */
885 WORD nrMS
; /* 0x06 number of the rgdb block */
886 DWORD bytesused
; /* 0x08 */
887 WORD keynamelen
; /* 0x0c len of name */
888 WORD values
; /* 0x0e number of values */
889 DWORD xx1
; /* 0x10 */
890 char name
[1]; /* 0x14 */
891 /* dkv */ /* 0x14 + keynamelen */
894 /* Disk Key Value structure, once per value */
897 DWORD type
; /* 0x00 */
899 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
900 WORD valdatalen
; /* 0x0A length of data */
901 char name
[1]; /* 0x0c */
902 /* raw data */ /* 0x0c + valnamelen */
905 /******************************************************************************
906 * _w95_lookup_dkh [Internal]
908 * seeks the dkh belonging to a dke
910 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
916 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
); /* get the beginning of the rgdb datastore */
917 assert (creg
->rgdb_num
> nrMS
); /* check: requested block < last_block) */
919 /* find the right block */
920 for(i
=0; i
<nrMS
;i
++)
922 assert(rgdb
->id
== W95_REG_RGDB_ID
); /* check the magic */
923 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
926 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
930 if(nrLS
==dkh
->nrLS
) return dkh
;
931 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
932 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
937 /******************************************************************************
938 * _w95_parse_dkv [Internal]
940 static int _w95_parse_dkv (
951 /* first value block */
952 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
954 /* loop trought the values */
955 for (i
=0; i
< dkh
->values
; i
++)
957 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
+1);
958 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
959 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
963 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
968 /******************************************************************************
969 * _w95_parse_dke [Internal]
971 static int _w95_parse_dke(
983 /* get start address of root key block */
984 if (!dke
) dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
986 /* special root key */
987 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
989 /* parse the one subkey*/
990 if (dke
->nextsub
!= 0xffffffff)
992 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
994 /* has no sibling keys */
998 /* search subblock */
999 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
1001 fprintf(stderr
, "dke pointing to missing dkh !\n");
1007 /* walk sibling keys */
1008 if (dke
->next
!= 0xffffffff )
1010 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1013 /* create subkey and insert values */
1014 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
+1);
1015 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1017 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1021 if (dke
->nextsub
!= 0xffffffff)
1023 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1027 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1030 /* end windows 95 loader */
1032 /******************************************************************************
1033 * NativeRegLoadKey [Internal]
1035 * Loads a native registry file (win95/nt)
1038 * level number of levels to cut away (eg. ".Default" in user.dat)
1040 * this function intentionally uses unix file functions to make it possible
1041 * to move it to a seperate registry helper programm
1043 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1047 DOS_FULL_NAME full_name
;
1051 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1053 /* map the registry into the memory */
1054 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1055 if ((fstat(fd
, &st
) == -1)) goto error
;
1056 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1058 switch (*(LPDWORD
)base
)
1060 /* windows 95 'creg' */
1061 case W95_REG_CREG_ID
:
1066 TRACE_(reg
)("Loading win95 registry '%s' '%s'\n",fn
, full_name
.long_name
);
1068 /* load the header (rgkn) */
1069 rgkn
= (_w95rgkn
*)(creg
+ 1);
1070 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1072 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1076 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1080 case NT_REG_HEADER_BLOCK_ID
:
1084 nt_hbin_sub
* hbin_sub
;
1087 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
1093 hbin
= (nt_hbin
*) ((char *) base
+ 0x1000);
1094 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1096 ERR_(reg
)( "%s hbin block invalid\n", fn
);
1100 /* hbin_sub block */
1101 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1102 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1104 ERR_(reg
)( "%s hbin_sub block invalid\n", fn
);
1109 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1110 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1112 ERR_(reg
)( "%s special nk block not found\n", fn
);
1116 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1121 ERR("unknown signature in registry file %s.\n",fn
);
1125 if(!ret
) ERR("error loading registry file %s\n", fn
);
1126 error1
: munmap(base
, st
.st_size
);
1131 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1133 reghack - windows 3.11 registry data format demo program.
1135 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1136 a combined hash table and tree description, and finally a text table.
1138 The header is obvious from the struct header. The taboff1 and taboff2
1139 fields are always 0x20, and their usage is unknown.
1141 The 8-byte entry table has various entry types.
1143 tabent[0] is a root index. The second word has the index of the root of
1145 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1146 the index of the key/value that has that hash. Data with the same
1147 hash value are on a circular list. The other three words in the
1148 hash entry are always zero.
1149 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1150 entry: dirent and keyent/valent. They are identified by context.
1151 tabent[freeidx] is the first free entry. The first word in a free entry
1152 is the index of the next free entry. The last has 0 as a link.
1153 The other three words in the free list are probably irrelevant.
1155 Entries in text table are preceeded by a word at offset-2. This word
1156 has the value (2*index)+1, where index is the referring keyent/valent
1157 entry in the table. I have no suggestion for the 2* and the +1.
1158 Following the word, there are N bytes of data, as per the keyent/valent
1159 entry length. The offset of the keyent/valent entry is from the start
1160 of the text table to the first data byte.
1162 This information is not available from Microsoft. The data format is
1163 deduced from the reg.dat file by me. Mistakes may
1164 have been made. I claim no rights and give no guarantees for this program.
1166 Tor Sjøwall, tor@sn.no
1169 /* reg.dat header format */
1170 struct _w31_header
{
1171 char cookie
[8]; /* 'SHCC3.10' */
1172 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1173 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1174 unsigned long tabcnt
; /* number of entries in index table */
1175 unsigned long textoff
; /* offset of text part */
1176 unsigned long textsize
; /* byte size of text part */
1177 unsigned short hashsize
; /* hash size */
1178 unsigned short freeidx
; /* free index */
1181 /* generic format of table entries */
1182 struct _w31_tabent
{
1183 unsigned short w0
, w1
, w2
, w3
;
1186 /* directory tabent: */
1187 struct _w31_dirent
{
1188 unsigned short sibling_idx
; /* table index of sibling dirent */
1189 unsigned short child_idx
; /* table index of child dirent */
1190 unsigned short key_idx
; /* table index of key keyent */
1191 unsigned short value_idx
; /* table index of value valent */
1195 struct _w31_keyent
{
1196 unsigned short hash_idx
; /* hash chain index for string */
1197 unsigned short refcnt
; /* reference count */
1198 unsigned short length
; /* length of string */
1199 unsigned short string_off
; /* offset of string in text table */
1203 struct _w31_valent
{
1204 unsigned short hash_idx
; /* hash chain index for string */
1205 unsigned short refcnt
; /* reference count */
1206 unsigned short length
; /* length of string */
1207 unsigned short string_off
; /* offset of string in text table */
1210 /* recursive helper function to display a directory tree */
1212 __w31_dumptree( unsigned short idx
,
1214 struct _w31_tabent
*tab
,
1215 struct _w31_header
*head
,
1217 time_t lastmodified
,
1220 struct _w31_dirent
*dir
;
1221 struct _w31_keyent
*key
;
1222 struct _w31_valent
*val
;
1224 static char tail
[400];
1227 dir
=(struct _w31_dirent
*)&tab
[idx
];
1230 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1232 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1233 tail
[key
->length
]='\0';
1234 /* all toplevel entries AND the entries in the
1235 * toplevel subdirectory belong to \SOFTWARE\Classes
1237 if (!level
&& !lstrcmpA(tail
,".classes")) {
1238 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1239 idx
=dir
->sibling_idx
;
1242 if (subkey
) RegCloseKey( subkey
);
1243 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1244 /* only add if leaf node or valued node */
1245 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1246 if (dir
->value_idx
) {
1247 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1248 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1249 tail
[val
->length
]='\0';
1250 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1254 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1256 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1257 idx
=dir
->sibling_idx
;
1259 if (subkey
) RegCloseKey( subkey
);
1263 /******************************************************************************
1264 * _w31_loadreg [Internal]
1266 void _w31_loadreg(void) {
1268 struct _w31_header head
;
1269 struct _w31_tabent
*tab
;
1273 BY_HANDLE_FILE_INFORMATION hfinfo
;
1274 time_t lastmodified
;
1278 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1279 if (hf
==HFILE_ERROR
)
1282 /* read & dump header */
1283 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1284 ERR("reg.dat is too short.\n");
1288 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1289 ERR("reg.dat has bad signature.\n");
1294 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1295 /* read and dump index table */
1297 if (len
!=_lread(hf
,tab
,len
)) {
1298 ERR("couldn't read %d bytes.\n",len
);
1305 txt
= xmalloc(head
.textsize
);
1306 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1307 ERR("couldn't seek to textblock.\n");
1313 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1314 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1321 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1322 ERR("GetFileInformationByHandle failed?.\n");
1328 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1329 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1337 /* configure save files and start the periodic saving timer */
1338 static void SHELL_InitRegistrySaving(void)
1340 struct set_registry_levels_request
*req
= get_req_buffer();
1342 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1343 int version
= PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
1344 int period
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1346 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1349 req
->version
= version
;
1350 req
->period
= period
* 1000;
1351 server_call( REQ_SET_REGISTRY_LEVELS
);
1353 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1355 struct save_registry_atexit_request
*req
= get_req_buffer();
1356 const char *confdir
= get_config_dir();
1357 char *str
= req
->file
+ strlen(confdir
);
1359 if (str
+ 20 > req
->file
+ server_remaining(req
->file
))
1361 ERR("config dir '%s' too long\n", confdir
);
1365 strcpy( req
->file
, confdir
);
1366 strcpy( str
, "/" SAVE_CURRENT_USER
);
1367 req
->hkey
= HKEY_CURRENT_USER
;
1368 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1370 strcpy( req
->file
, confdir
);
1371 strcpy( str
, "/" SAVE_LOCAL_MACHINE
);
1372 req
->hkey
= HKEY_LOCAL_MACHINE
;
1373 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1375 strcpy( req
->file
, confdir
);
1376 strcpy( str
, "/" SAVE_LOCAL_USERS_DEFAULT
);
1377 req
->hkey
= HKEY_USERS
;
1378 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1383 /**********************************************************************************
1384 * SetLoadLevel [Internal]
1386 * set level to 0 for loading system files
1387 * set level to 1 for loading user files
1389 static void SetLoadLevel(int level
)
1391 struct set_registry_levels_request
*req
= get_req_buffer();
1393 req
->current
= level
;
1397 server_call( REQ_SET_REGISTRY_LEVELS
);
1400 /**********************************************************************************
1401 * SHELL_LoadRegistry [Internal]
1403 #define REG_DONTLOAD -1
1408 void SHELL_LoadRegistry( void )
1411 char windir
[MAX_PATHNAME_LEN
];
1412 char path
[MAX_PATHNAME_LEN
];
1413 int systemtype
= REG_WIN31
;
1417 if (!CLIENT_IsBootThread()) return; /* already loaded */
1422 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1424 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1426 /* test %windir%/system32/config/system --> winnt */
1427 strcpy(path
, windir
);
1428 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1429 if(GetFileAttributesA(path
) != -1)
1431 systemtype
= REG_WINNT
;
1435 /* test %windir%/system.dat --> win95 */
1436 strcpy(path
, windir
);
1437 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1438 if(GetFileAttributesA(path
) != -1)
1440 systemtype
= REG_WIN95
;
1444 if ((systemtype
==REG_WINNT
)
1445 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1447 MESSAGE("When you are running with a native NT directory specify\n");
1448 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1449 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1450 systemtype
= REG_DONTLOAD
;
1455 /* only wine registry */
1456 systemtype
= REG_DONTLOAD
;
1466 /* Load windows 95 entries */
1467 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1469 strcpy(path
, windir
);
1470 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1471 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1473 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1475 /* user specific user.dat */
1476 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1477 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1479 MESSAGE("can't load win95 user-registry %s\n", path
);
1480 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1482 /* default user.dat */
1483 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1485 strcpy(path
, windir
);
1486 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1487 NativeRegLoadKey(hkey
, path
, 1);
1493 /* global user.dat */
1494 strcpy(path
, windir
);
1495 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1496 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1501 /* default user.dat */
1502 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1504 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1505 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1507 MESSAGE("can't load NT user-registry %s\n", path
);
1508 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1512 /* default user.dat */
1513 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1515 strcpy(path
, windir
);
1516 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1517 NativeRegLoadKey(hkey
, path
, 1);
1523 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1526 strcpy(path
, windir
);
1527 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1528 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1530 strcpy(path
, windir
);
1531 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1532 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1534 strcpy(path
, windir
);
1535 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1536 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1538 strcpy(path
, windir
);
1539 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1540 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1542 /* this key is generated when the nt-core booted successfully */
1543 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1548 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1551 * Load the global HKU hive directly from sysconfdir
1553 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1556 * Load the global machine defaults directly form sysconfdir
1558 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1564 * Load the user saved registries
1566 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1568 const char *confdir
= get_config_dir();
1569 int len
= strlen(confdir
) + 20;
1572 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1574 * Load user's personal versions of global HKU/.Default keys
1579 strcpy( fn
, confdir
);
1580 str
= fn
+ strlen(fn
);
1583 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1584 _wine_loadreg( HKEY_USERS
, fn
);
1586 strcpy( str
, SAVE_CURRENT_USER
);
1587 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1589 strcpy( str
, SAVE_LOCAL_MACHINE
);
1590 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1592 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1596 SHELL_InitRegistrySaving();
1599 /********************* API FUNCTIONS ***************************************/
1604 /******************************************************************************
1605 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1606 * Immediately writes key to registry.
1607 * Only returns after data has been written to disk.
1609 * FIXME: does it really wait until data is written ?
1612 * hkey [I] Handle of key to write
1615 * Success: ERROR_SUCCESS
1616 * Failure: Error code
1618 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1620 FIXME( "(%x): stub\n", hkey
);
1621 return ERROR_SUCCESS
;
1624 /******************************************************************************
1625 * RegConnectRegistryW [ADVAPI32.128]
1628 * lpMachineName [I] Address of name of remote computer
1629 * hHey [I] Predefined registry handle
1630 * phkResult [I] Address of buffer for remote registry handle
1632 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1635 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1637 if (!lpMachineName
|| !*lpMachineName
) {
1638 /* Use the local machine name */
1639 return RegOpenKey16( hKey
, "", phkResult
);
1642 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1643 return ERROR_BAD_NETPATH
;
1647 /******************************************************************************
1648 * RegConnectRegistryA [ADVAPI32.127]
1650 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1653 LPWSTR machineW
= strdupA2W(machine
);
1654 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1660 /******************************************************************************
1661 * RegGetKeySecurity [ADVAPI32.144]
1662 * Retrieves a copy of security descriptor protecting the registry key
1665 * hkey [I] Open handle of key to set
1666 * SecurityInformation [I] Descriptor contents
1667 * pSecurityDescriptor [O] Address of descriptor for key
1668 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1671 * Success: ERROR_SUCCESS
1672 * Failure: Error code
1674 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1675 SECURITY_INFORMATION SecurityInformation
,
1676 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1677 LPDWORD lpcbSecurityDescriptor
)
1679 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1680 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1682 /* FIXME: Check for valid SecurityInformation values */
1684 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1685 return ERROR_INSUFFICIENT_BUFFER
;
1687 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1688 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1690 return ERROR_SUCCESS
;
1694 /******************************************************************************
1695 * RegNotifyChangeKeyValue [ADVAPI32.???]
1698 * hkey [I] Handle of key to watch
1699 * fWatchSubTree [I] Flag for subkey notification
1700 * fdwNotifyFilter [I] Changes to be reported
1701 * hEvent [I] Handle of signaled event
1702 * fAsync [I] Flag for asynchronous reporting
1704 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1705 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1708 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1710 return ERROR_SUCCESS
;
1714 /******************************************************************************
1715 * RegUnLoadKeyW [ADVAPI32.173]
1718 * hkey [I] Handle of open key
1719 * lpSubKey [I] Address of name of subkey to unload
1721 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1723 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1724 return ERROR_SUCCESS
;
1728 /******************************************************************************
1729 * RegUnLoadKeyA [ADVAPI32.172]
1731 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1734 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1735 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1736 if(lpSubKeyW
) free(lpSubKeyW
);
1741 /******************************************************************************
1742 * RegSetKeySecurity [ADVAPI32.167]
1745 * hkey [I] Open handle of key to set
1746 * SecurityInfo [I] Descriptor contents
1747 * pSecurityDesc [I] Address of descriptor for key
1749 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1750 PSECURITY_DESCRIPTOR pSecurityDesc
)
1752 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1754 /* It seems to perform this check before the hkey check */
1755 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1756 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1757 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1758 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1761 return ERROR_INVALID_PARAMETER
;
1764 return ERROR_INVALID_PARAMETER
;
1766 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1768 return ERROR_SUCCESS
;
1772 /******************************************************************************
1773 * RegRestoreKeyW [ADVAPI32.164]
1776 * hkey [I] Handle of key where restore begins
1777 * lpFile [I] Address of filename containing saved tree
1778 * dwFlags [I] Optional flags
1780 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1782 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1784 /* It seems to do this check before the hkey check */
1785 if (!lpFile
|| !*lpFile
)
1786 return ERROR_INVALID_PARAMETER
;
1788 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1790 /* Check for file existence */
1792 return ERROR_SUCCESS
;
1796 /******************************************************************************
1797 * RegRestoreKeyA [ADVAPI32.163]
1799 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1802 LPWSTR lpFileW
= strdupA2W(lpFile
);
1803 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1804 if(lpFileW
) free(lpFileW
);
1809 /******************************************************************************
1810 * RegReplaceKeyW [ADVAPI32.162]
1813 * hkey [I] Handle of open key
1814 * lpSubKey [I] Address of name of subkey
1815 * lpNewFile [I] Address of filename for file with new data
1816 * lpOldFile [I] Address of filename for backup file
1818 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1821 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1822 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1823 return ERROR_SUCCESS
;
1827 /******************************************************************************
1828 * RegReplaceKeyA [ADVAPI32.161]
1830 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1834 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1835 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1836 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1837 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1849 /* 16-bit functions */
1851 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1852 * some programs. Do not remove those cases. -MM
1854 static inline void fix_win16_hkey( HKEY
*hkey
)
1856 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1859 /******************************************************************************
1860 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1862 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1864 fix_win16_hkey( &hkey
);
1865 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1868 /******************************************************************************
1869 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1871 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1873 fix_win16_hkey( &hkey
);
1874 return RegOpenKeyA( hkey
, name
, retkey
);
1877 /******************************************************************************
1878 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1880 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1882 fix_win16_hkey( &hkey
);
1883 return RegCreateKeyA( hkey
, name
, retkey
);
1886 /******************************************************************************
1887 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1889 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1891 fix_win16_hkey( &hkey
);
1892 return RegDeleteKeyA( hkey
, name
);
1895 /******************************************************************************
1896 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1898 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1900 fix_win16_hkey( &hkey
);
1901 return RegCloseKey( hkey
);
1904 /******************************************************************************
1905 * RegSetValue16 [KERNEL.221] [SHELL.5]
1907 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1909 fix_win16_hkey( &hkey
);
1910 return RegSetValueA( hkey
, name
, type
, data
, count
);
1913 /******************************************************************************
1914 * RegDeleteValue16 [KERNEL.222]
1916 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1918 fix_win16_hkey( &hkey
);
1919 return RegDeleteValueA( hkey
, name
);
1922 /******************************************************************************
1923 * RegEnumValue16 [KERNEL.223]
1925 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1926 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1928 fix_win16_hkey( &hkey
);
1929 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1932 /******************************************************************************
1933 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1936 * Is this HACK still applicable?
1939 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1940 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1943 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1945 fix_win16_hkey( &hkey
);
1946 if (count
) *count
&= 0xffff;
1947 return RegQueryValueA( hkey
, name
, data
, count
);
1950 /******************************************************************************
1951 * RegQueryValueEx16 [KERNEL.225]
1953 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1954 LPBYTE data
, LPDWORD count
)
1956 fix_win16_hkey( &hkey
);
1957 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1960 /******************************************************************************
1961 * RegSetValueEx16 [KERNEL.226]
1963 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1964 CONST BYTE
*data
, DWORD count
)
1966 fix_win16_hkey( &hkey
);
1967 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);