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>
41 #include "wine/winbase16.h"
42 #include "wine/winestring.h"
46 #include "debugtools.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
)
73 res
= malloc (size
? size
: 1);
75 WARN("Virtual memory exhausted.\n");
83 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
84 * If so, can we remove them?
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
)
93 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
94 lstrcpyAtoW(dest
,src
);
100 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
103 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
105 lstrcpynAtoW(dest
,src
,nchars
+1);
111 /******************************************************************************
112 * REGISTRY_Init [Internal]
113 * Registry initialisation, allocates some default keys.
115 static void REGISTRY_Init(void) {
121 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&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"));
130 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
134 * string RegisteredOwner
135 * string RegisteredOrganization
138 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
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);
151 /************************ LOAD Registry Function ****************************/
155 /******************************************************************************
156 * _find_or_add_key [Internal]
158 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
161 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
162 if (keyname
) free( keyname
);
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
183 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
193 s
=fgets(curread
,mylen
,F
);
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");
206 mylen
= *len
; /* we filled up the buffer and
207 * got new '*len' bytes to fill
215 /* throw away comments */
216 if (**buf
=='#' || **buf
==';') {
221 if (s
) /* got end of line */
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
)
239 /* read up to "=" or "\0" or "\n" */
241 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
243 while (*s
&& (*s
!='\n') && (*s
!='=')) {
245 *ws
++=*((unsigned char*)s
++);
249 /* Dangling \ ... may only happen if a registry
250 * write was short. FIXME: What do to?
260 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
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
);
272 *ws
++ =(unsigned short)wc
;
281 /******************************************************************************
282 * _wine_loadsubkey [Internal]
285 * It seems like this is returning a boolean. Should it?
291 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
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 */
310 WARN("Got a subhierarchy without resp. key?\n");
313 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
314 if (!_wine_read_line(F
,buf
,buflen
))
319 /* let the caller handle this line */
320 if (i
<level
|| **buf
=='\0')
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 */
330 if (subkey
) RegCloseKey( subkey
);
331 subkey
=_find_or_add_key(hkey
,name
);
334 int len
,lastmodified
,type
;
337 WARN("Unexpected character: %c\n",*s
);
341 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
342 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
349 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
352 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
353 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
354 len
= lstrlenW((LPWSTR
)data
)*2+2;
357 data
= (LPBYTE
)xmalloc(len
+1);
358 for (i
=0;i
<len
;i
++) {
360 if (*s
>='0' && *s
<='9')
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;
367 if (*s
>='0' && *s
<='9')
369 if (*s
>='a' && *s
<='f')
370 data
[i
]|=*s
-'a'+'\xa';
371 if (*s
>='A' && *s
<='F')
372 data
[i
]|=*s
-'A'+'\xa';
376 _find_or_add_value(hkey
,name
,type
,data
,len
);
379 /* read the next line */
380 if (!_wine_read_line(F
,buf
,buflen
))
384 if (subkey
) RegCloseKey( subkey
);
389 /******************************************************************************
390 * _wine_loadsubreg [Internal]
392 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
398 buf
=xmalloc(10);buflen
=10;
399 if (!_wine_read_line(F
,&buf
,&buflen
)) {
403 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
408 if (ver
== 2) /* new version */
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();
418 server_call( REQ_LOAD_REGISTRY
);
426 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
431 if (!_wine_read_line(F
,&buf
,&buflen
)) {
435 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
444 /******************************************************************************
445 * _wine_loadreg [Internal]
447 static void _wine_loadreg( HKEY hkey
, char *fn
)
451 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
455 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
458 _wine_loadsubreg(F
,hkey
,fn
);
462 /* NT REGISTRY LOADER */
464 #ifdef HAVE_SYS_MMAN_H
465 # include <sys/mman.h>
469 #define MAP_FAILED ((LPVOID)-1)
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
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 */
500 DWORD Checksum
; /* at offset 0x1FC */
511 DWORD id
; /* 0x6E696268 'hbin' */
515 DWORD uk2
; /* 0x10 */
516 DWORD uk3
; /* 0x14 */
517 DWORD uk4
; /* 0x18 */
518 DWORD size
; /* 0x1C */
519 nt_hbin_sub hbin_sub
; /* 0x20 */
523 * the value_list consists of offsets to the values (vk)
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 */
552 DWORD off_nk
; /* 0x00 */
553 DWORD name
; /* 0x04 */
558 WORD id
; /* 0x00 0x666c */
559 WORD nr_keys
; /* 0x06 */
560 hash_rec hash_rec
[1];
564 list of subkeys without hash
572 WORD id
; /* 0x00 0x696c */
578 this is a intermediate node
590 WORD id
; /* 0x00 0x6972 */
591 WORD nr_li
; /* 0x02 number off offsets */
592 DWORD off_li
[1]; /* 0x04 points to li */
597 WORD id
; /* 0x00 'vk' */
607 LPSTR
_strdupnA( LPCSTR str
, int len
)
611 if (!str
) return NULL
;
612 ret
= malloc( len
+ 1 );
613 lstrcpynA( ret
, str
, len
);
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
);
627 * 0 value is a default value
628 * 1 the value has a name
631 * len of the whole data block
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
)
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
);
653 ERR_(reg
)("unknown block found (0x%04x), please report!\n", vk
->id
);
660 * this structure contains the hash of a keyname and points to all
663 * exception: if the id is 'il' there are no hash values and every
666 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
)
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
;
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
;
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
;
718 error2
: ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
721 error1
: ERR_(reg
)("registry file corrupt! (inconsistent number of subkeys)\n");
724 error
: ERR_(reg
)("error reading lf block\n");
728 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
735 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)
737 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
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");
748 /* create the new key */
751 name
= _strdupnA( nk
->name
, nk
->name_len
+1);
752 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
756 /* loop through the 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
;
774 error1
: RegCloseKey(subkey
);
780 /* windows 95 registry loader */
782 /* SECTION 1: main header
786 #define W95_REG_CREG_ID 0x47455243
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 */
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
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 */
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
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 */
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 */
851 /* SECTION 3: key information, values and data
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
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 */
879 /* Disk Key Header structure (RGDB part), once per key */
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 */
893 /* Disk Key Value structure, once per value */
896 DWORD type
; /* 0x00 */
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 */
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
)
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");
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
);
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
));
947 /******************************************************************************
948 * _w95_parse_dkv [Internal]
950 static int _w95_parse_dkv (
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
);
973 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
978 /******************************************************************************
979 * _w95_parse_dke [Internal]
981 static int _w95_parse_dke(
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 */
1008 /* search subblock */
1009 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
1011 fprintf(stderr
, "dke pointing to missing dkh !\n");
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
; }
1027 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1031 if (dke
->nextsub
!= 0xffffffff)
1033 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1037 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1040 /* end windows 95 loader */
1042 /******************************************************************************
1043 * NativeRegLoadKey [Internal]
1045 * Loads a native registry file (win95/nt)
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
)
1057 DOS_FULL_NAME full_name
;
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
:
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
);
1087 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1091 case NT_REG_HEADER_BLOCK_ID
:
1095 nt_hbin_sub
* hbin_sub
;
1098 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
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
);
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
);
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
);
1127 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1132 ERR("unknown signature in registry file %s.\n",fn
);
1136 if(!ret
) ERR("error loading registry file %s\n", fn
);
1137 error1
: munmap(base
, st
.st_size
);
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
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 */
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 */
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 */
1223 __w31_dumptree( unsigned short idx
,
1225 struct _w31_tabent
*tab
,
1226 struct _w31_header
*head
,
1228 time_t lastmodified
,
1231 struct _w31_dirent
*dir
;
1232 struct _w31_keyent
*key
;
1233 struct _w31_valent
*val
;
1235 static char tail
[400];
1238 dir
=(struct _w31_dirent
*)&tab
[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
;
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 );
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) {
1279 struct _w31_header head
;
1280 struct _w31_tabent
*tab
;
1284 BY_HANDLE_FILE_INFORMATION hfinfo
;
1285 time_t lastmodified
;
1289 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1290 if (hf
==HFILE_ERROR
)
1293 /* read & dump header */
1294 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1295 ERR("reg.dat is too short.\n");
1299 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1300 ERR("reg.dat has bad signature.\n");
1305 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1306 /* read and dump index table */
1308 if (len
!=_lread(hf
,tab
,len
)) {
1309 ERR("couldn't read %d bytes.\n",len
);
1316 txt
= xmalloc(head
.textsize
);
1317 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1318 ERR("couldn't seek to textblock.\n");
1324 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1325 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1332 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1333 ERR("GetFileInformationByHandle failed?.\n");
1339 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1340 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
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) */
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
);
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
;
1408 server_call( REQ_SET_REGISTRY_LEVELS
);
1411 /**********************************************************************************
1412 * SHELL_LoadRegistry [Internal]
1414 #define REG_DONTLOAD -1
1419 void SHELL_LoadRegistry( void )
1422 char windir
[MAX_PATHNAME_LEN
];
1423 char path
[MAX_PATHNAME_LEN
];
1424 int systemtype
= REG_WIN31
;
1428 if (!CLIENT_IsBootThread()) return; /* already loaded */
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
;
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
;
1466 /* only wine registry */
1467 systemtype
= REG_DONTLOAD
;
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);
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);
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);
1534 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1537 strcpy(path
, windir
);
1538 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1539 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1541 strcpy(path
, windir
);
1542 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1543 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1545 strcpy(path
, windir
);
1546 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1547 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1549 strcpy(path
, windir
);
1550 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1551 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1553 /* this key is generated when the nt-core booted successfully */
1554 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1559 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1562 * Load the global HKU hive directly from sysconfdir
1564 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1567 * Load the global machine defaults directly form sysconfdir
1569 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1575 * Load the user saved registries
1577 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1579 const char *confdir
= get_config_dir();
1580 int len
= strlen(confdir
) + 20;
1583 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1585 * Load user's personal versions of global HKU/.Default keys
1590 strcpy( fn
, confdir
);
1591 str
= fn
+ strlen(fn
);
1594 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1595 _wine_loadreg( HKEY_USERS
, fn
);
1597 strcpy( str
, SAVE_CURRENT_USER
);
1598 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1600 strcpy( str
, SAVE_LOCAL_MACHINE
);
1601 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1603 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1607 SHELL_InitRegistrySaving();
1610 /********************* API FUNCTIONS ***************************************/
1615 /******************************************************************************
1616 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1617 * Immediately writes key to registry.
1618 * Only returns after data has been written to disk.
1620 * FIXME: does it really wait until data is written ?
1623 * hkey [I] Handle of key to write
1626 * Success: ERROR_SUCCESS
1627 * Failure: Error code
1629 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1631 FIXME( "(%x): stub\n", hkey
);
1632 return ERROR_SUCCESS
;
1635 /******************************************************************************
1636 * RegConnectRegistryW [ADVAPI32.128]
1639 * lpMachineName [I] Address of name of remote computer
1640 * hHey [I] Predefined registry handle
1641 * phkResult [I] Address of buffer for remote registry handle
1643 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1646 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1648 if (!lpMachineName
|| !*lpMachineName
) {
1649 /* Use the local machine name */
1650 return RegOpenKey16( hKey
, "", phkResult
);
1653 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1654 return ERROR_BAD_NETPATH
;
1658 /******************************************************************************
1659 * RegConnectRegistryA [ADVAPI32.127]
1661 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1664 LPWSTR machineW
= strdupA2W(machine
);
1665 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1671 /******************************************************************************
1672 * RegGetKeySecurity [ADVAPI32.144]
1673 * Retrieves a copy of security descriptor protecting the registry key
1676 * hkey [I] Open handle of key to set
1677 * SecurityInformation [I] Descriptor contents
1678 * pSecurityDescriptor [O] Address of descriptor for key
1679 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1682 * Success: ERROR_SUCCESS
1683 * Failure: Error code
1685 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1686 SECURITY_INFORMATION SecurityInformation
,
1687 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1688 LPDWORD lpcbSecurityDescriptor
)
1690 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1691 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1693 /* FIXME: Check for valid SecurityInformation values */
1695 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1696 return ERROR_INSUFFICIENT_BUFFER
;
1698 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1699 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1701 return ERROR_SUCCESS
;
1705 /******************************************************************************
1706 * RegNotifyChangeKeyValue [ADVAPI32.???]
1709 * hkey [I] Handle of key to watch
1710 * fWatchSubTree [I] Flag for subkey notification
1711 * fdwNotifyFilter [I] Changes to be reported
1712 * hEvent [I] Handle of signaled event
1713 * fAsync [I] Flag for asynchronous reporting
1715 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1716 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1719 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1721 return ERROR_SUCCESS
;
1725 /******************************************************************************
1726 * RegUnLoadKeyW [ADVAPI32.173]
1729 * hkey [I] Handle of open key
1730 * lpSubKey [I] Address of name of subkey to unload
1732 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1734 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1735 return ERROR_SUCCESS
;
1739 /******************************************************************************
1740 * RegUnLoadKeyA [ADVAPI32.172]
1742 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1745 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1746 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1747 if(lpSubKeyW
) free(lpSubKeyW
);
1752 /******************************************************************************
1753 * RegSetKeySecurity [ADVAPI32.167]
1756 * hkey [I] Open handle of key to set
1757 * SecurityInfo [I] Descriptor contents
1758 * pSecurityDesc [I] Address of descriptor for key
1760 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1761 PSECURITY_DESCRIPTOR pSecurityDesc
)
1763 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1765 /* It seems to perform this check before the hkey check */
1766 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1767 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1768 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1769 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1772 return ERROR_INVALID_PARAMETER
;
1775 return ERROR_INVALID_PARAMETER
;
1777 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1779 return ERROR_SUCCESS
;
1783 /******************************************************************************
1784 * RegRestoreKeyW [ADVAPI32.164]
1787 * hkey [I] Handle of key where restore begins
1788 * lpFile [I] Address of filename containing saved tree
1789 * dwFlags [I] Optional flags
1791 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1793 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1795 /* It seems to do this check before the hkey check */
1796 if (!lpFile
|| !*lpFile
)
1797 return ERROR_INVALID_PARAMETER
;
1799 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1801 /* Check for file existence */
1803 return ERROR_SUCCESS
;
1807 /******************************************************************************
1808 * RegRestoreKeyA [ADVAPI32.163]
1810 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1813 LPWSTR lpFileW
= strdupA2W(lpFile
);
1814 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1815 if(lpFileW
) free(lpFileW
);
1820 /******************************************************************************
1821 * RegReplaceKeyW [ADVAPI32.162]
1824 * hkey [I] Handle of open key
1825 * lpSubKey [I] Address of name of subkey
1826 * lpNewFile [I] Address of filename for file with new data
1827 * lpOldFile [I] Address of filename for backup file
1829 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1832 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1833 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1834 return ERROR_SUCCESS
;
1838 /******************************************************************************
1839 * RegReplaceKeyA [ADVAPI32.161]
1841 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1845 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1846 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1847 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1848 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1860 /* 16-bit functions */
1862 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1863 * some programs. Do not remove those cases. -MM
1865 static inline void fix_win16_hkey( HKEY
*hkey
)
1867 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1870 /******************************************************************************
1871 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1873 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1875 fix_win16_hkey( &hkey
);
1876 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1879 /******************************************************************************
1880 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1882 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1884 fix_win16_hkey( &hkey
);
1885 return RegOpenKeyA( hkey
, name
, retkey
);
1888 /******************************************************************************
1889 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1891 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1893 fix_win16_hkey( &hkey
);
1894 return RegCreateKeyA( hkey
, name
, retkey
);
1897 /******************************************************************************
1898 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1900 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1902 fix_win16_hkey( &hkey
);
1903 return RegDeleteKeyA( hkey
, name
);
1906 /******************************************************************************
1907 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1909 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1911 fix_win16_hkey( &hkey
);
1912 return RegCloseKey( hkey
);
1915 /******************************************************************************
1916 * RegSetValue16 [KERNEL.221] [SHELL.5]
1918 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1920 fix_win16_hkey( &hkey
);
1921 return RegSetValueA( hkey
, name
, type
, data
, count
);
1924 /******************************************************************************
1925 * RegDeleteValue16 [KERNEL.222]
1927 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1929 fix_win16_hkey( &hkey
);
1930 return RegDeleteValueA( hkey
, name
);
1933 /******************************************************************************
1934 * RegEnumValue16 [KERNEL.223]
1936 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1937 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1939 fix_win16_hkey( &hkey
);
1940 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1943 /******************************************************************************
1944 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1947 * Is this HACK still applicable?
1950 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1951 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1954 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1956 fix_win16_hkey( &hkey
);
1957 if (count
) *count
&= 0xffff;
1958 return RegQueryValueA( hkey
, name
, data
, count
);
1961 /******************************************************************************
1962 * RegQueryValueEx16 [KERNEL.225]
1964 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1965 LPBYTE data
, LPDWORD count
)
1967 fix_win16_hkey( &hkey
);
1968 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1971 /******************************************************************************
1972 * RegSetValueEx16 [KERNEL.226]
1974 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1975 CONST BYTE
*data
, DWORD count
)
1977 fix_win16_hkey( &hkey
);
1978 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);