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 ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1068 switch (*(LPDWORD
)base
)
1070 /* windows 95 'creg' */
1071 case W95_REG_CREG_ID
:
1076 TRACE_(reg
)("Loading win95 registry '%s' '%s'\n",fn
, full_name
.long_name
);
1078 /* load the header (rgkn) */
1079 rgkn
= (_w95rgkn
*)(creg
+ 1);
1080 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1082 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1086 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1090 case NT_REG_HEADER_BLOCK_ID
:
1094 nt_hbin_sub
* hbin_sub
;
1097 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
1103 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1104 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1106 ERR_(reg
)( "%s hbin block invalid\n", fn
);
1110 /* hbin_sub block */
1111 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1112 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1114 ERR_(reg
)( "%s hbin_sub block invalid\n", fn
);
1119 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1120 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1122 ERR_(reg
)( "%s special nk block not found\n", fn
);
1126 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1131 ERR("unknown signature in registry file %s.\n",fn
);
1135 if(!ret
) ERR("error loading registry file %s\n", fn
);
1136 error1
: munmap(base
, st
.st_size
);
1141 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1143 reghack - windows 3.11 registry data format demo program.
1145 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1146 a combined hash table and tree description, and finally a text table.
1148 The header is obvious from the struct header. The taboff1 and taboff2
1149 fields are always 0x20, and their usage is unknown.
1151 The 8-byte entry table has various entry types.
1153 tabent[0] is a root index. The second word has the index of the root of
1155 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1156 the index of the key/value that has that hash. Data with the same
1157 hash value are on a circular list. The other three words in the
1158 hash entry are always zero.
1159 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1160 entry: dirent and keyent/valent. They are identified by context.
1161 tabent[freeidx] is the first free entry. The first word in a free entry
1162 is the index of the next free entry. The last has 0 as a link.
1163 The other three words in the free list are probably irrelevant.
1165 Entries in text table are preceeded by a word at offset-2. This word
1166 has the value (2*index)+1, where index is the referring keyent/valent
1167 entry in the table. I have no suggestion for the 2* and the +1.
1168 Following the word, there are N bytes of data, as per the keyent/valent
1169 entry length. The offset of the keyent/valent entry is from the start
1170 of the text table to the first data byte.
1172 This information is not available from Microsoft. The data format is
1173 deduced from the reg.dat file by me. Mistakes may
1174 have been made. I claim no rights and give no guarantees for this program.
1176 Tor Sjøwall, tor@sn.no
1179 /* reg.dat header format */
1180 struct _w31_header
{
1181 char cookie
[8]; /* 'SHCC3.10' */
1182 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1183 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1184 unsigned long tabcnt
; /* number of entries in index table */
1185 unsigned long textoff
; /* offset of text part */
1186 unsigned long textsize
; /* byte size of text part */
1187 unsigned short hashsize
; /* hash size */
1188 unsigned short freeidx
; /* free index */
1191 /* generic format of table entries */
1192 struct _w31_tabent
{
1193 unsigned short w0
, w1
, w2
, w3
;
1196 /* directory tabent: */
1197 struct _w31_dirent
{
1198 unsigned short sibling_idx
; /* table index of sibling dirent */
1199 unsigned short child_idx
; /* table index of child dirent */
1200 unsigned short key_idx
; /* table index of key keyent */
1201 unsigned short value_idx
; /* table index of value valent */
1205 struct _w31_keyent
{
1206 unsigned short hash_idx
; /* hash chain index for string */
1207 unsigned short refcnt
; /* reference count */
1208 unsigned short length
; /* length of string */
1209 unsigned short string_off
; /* offset of string in text table */
1213 struct _w31_valent
{
1214 unsigned short hash_idx
; /* hash chain index for string */
1215 unsigned short refcnt
; /* reference count */
1216 unsigned short length
; /* length of string */
1217 unsigned short string_off
; /* offset of string in text table */
1220 /* recursive helper function to display a directory tree */
1222 __w31_dumptree( unsigned short idx
,
1224 struct _w31_tabent
*tab
,
1225 struct _w31_header
*head
,
1227 time_t lastmodified
,
1230 struct _w31_dirent
*dir
;
1231 struct _w31_keyent
*key
;
1232 struct _w31_valent
*val
;
1234 static char tail
[400];
1237 dir
=(struct _w31_dirent
*)&tab
[idx
];
1240 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1242 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1243 tail
[key
->length
]='\0';
1244 /* all toplevel entries AND the entries in the
1245 * toplevel subdirectory belong to \SOFTWARE\Classes
1247 if (!level
&& !lstrcmpA(tail
,".classes")) {
1248 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1249 idx
=dir
->sibling_idx
;
1252 if (subkey
) RegCloseKey( subkey
);
1253 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1254 /* only add if leaf node or valued node */
1255 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1256 if (dir
->value_idx
) {
1257 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1258 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1259 tail
[val
->length
]='\0';
1260 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1264 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1266 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1267 idx
=dir
->sibling_idx
;
1269 if (subkey
) RegCloseKey( subkey
);
1273 /******************************************************************************
1274 * _w31_loadreg [Internal]
1276 void _w31_loadreg(void) {
1278 struct _w31_header head
;
1279 struct _w31_tabent
*tab
;
1283 BY_HANDLE_FILE_INFORMATION hfinfo
;
1284 time_t lastmodified
;
1288 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1289 if (hf
==HFILE_ERROR
)
1292 /* read & dump header */
1293 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1294 ERR("reg.dat is too short.\n");
1298 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1299 ERR("reg.dat has bad signature.\n");
1304 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1305 /* read and dump index table */
1307 if (len
!=_lread(hf
,tab
,len
)) {
1308 ERR("couldn't read %d bytes.\n",len
);
1315 txt
= xmalloc(head
.textsize
);
1316 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1317 ERR("couldn't seek to textblock.\n");
1323 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1324 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1331 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1332 ERR("GetFileInformationByHandle failed?.\n");
1338 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1339 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1347 /* configure save files and start the periodic saving timer */
1348 static void SHELL_InitRegistrySaving(void)
1350 struct set_registry_levels_request
*req
= get_req_buffer();
1352 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1353 int version
= PROFILE_GetWineIniBool( "registry", "UseNewFormat", 1 ) ? 2 : 1;
1354 int period
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1356 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1359 req
->version
= version
;
1360 req
->period
= period
* 1000;
1361 server_call( REQ_SET_REGISTRY_LEVELS
);
1363 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1365 struct save_registry_atexit_request
*req
= get_req_buffer();
1366 const char *confdir
= get_config_dir();
1367 char *str
= req
->file
+ strlen(confdir
);
1369 if (str
+ 20 > req
->file
+ server_remaining(req
->file
))
1371 ERR("config dir '%s' too long\n", confdir
);
1375 strcpy( req
->file
, confdir
);
1376 strcpy( str
, "/" SAVE_CURRENT_USER
);
1377 req
->hkey
= HKEY_CURRENT_USER
;
1378 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1380 strcpy( req
->file
, confdir
);
1381 strcpy( str
, "/" SAVE_LOCAL_MACHINE
);
1382 req
->hkey
= HKEY_LOCAL_MACHINE
;
1383 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1385 strcpy( req
->file
, confdir
);
1386 strcpy( str
, "/" SAVE_LOCAL_USERS_DEFAULT
);
1387 req
->hkey
= HKEY_USERS
;
1388 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1393 /**********************************************************************************
1394 * SetLoadLevel [Internal]
1396 * set level to 0 for loading system files
1397 * set level to 1 for loading user files
1399 static void SetLoadLevel(int level
)
1401 struct set_registry_levels_request
*req
= get_req_buffer();
1403 req
->current
= level
;
1407 server_call( REQ_SET_REGISTRY_LEVELS
);
1410 /**********************************************************************************
1411 * SHELL_LoadRegistry [Internal]
1413 #define REG_DONTLOAD -1
1418 void SHELL_LoadRegistry( void )
1421 char windir
[MAX_PATHNAME_LEN
];
1422 char path
[MAX_PATHNAME_LEN
];
1423 int systemtype
= REG_WIN31
;
1427 if (!CLIENT_IsBootThread()) return; /* already loaded */
1432 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1434 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1436 /* test %windir%/system32/config/system --> winnt */
1437 strcpy(path
, windir
);
1438 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1439 if(GetFileAttributesA(path
) != -1)
1441 systemtype
= REG_WINNT
;
1445 /* test %windir%/system.dat --> win95 */
1446 strcpy(path
, windir
);
1447 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1448 if(GetFileAttributesA(path
) != -1)
1450 systemtype
= REG_WIN95
;
1454 if ((systemtype
==REG_WINNT
)
1455 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1457 MESSAGE("When you are running with a native NT directory specify\n");
1458 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1459 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1460 systemtype
= REG_DONTLOAD
;
1465 /* only wine registry */
1466 systemtype
= REG_DONTLOAD
;
1476 /* Load windows 95 entries */
1477 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1479 strcpy(path
, windir
);
1480 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1481 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1483 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1485 /* user specific user.dat */
1486 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1487 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1489 MESSAGE("can't load win95 user-registry %s\n", path
);
1490 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1492 /* default user.dat */
1493 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1495 strcpy(path
, windir
);
1496 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1497 NativeRegLoadKey(hkey
, path
, 1);
1503 /* global user.dat */
1504 strcpy(path
, windir
);
1505 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1506 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1511 /* default user.dat */
1512 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1514 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1515 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1517 MESSAGE("can't load NT user-registry %s\n", path
);
1518 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1522 /* default user.dat */
1523 if (!RegCreateKeyA(HKEY_USERS
, ".Default", &hkey
))
1525 strcpy(path
, windir
);
1526 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1527 NativeRegLoadKey(hkey
, path
, 1);
1533 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1536 strcpy(path
, windir
);
1537 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1538 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1540 strcpy(path
, windir
);
1541 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1542 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1544 strcpy(path
, windir
);
1545 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1546 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1548 strcpy(path
, windir
);
1549 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1550 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1552 /* this key is generated when the nt-core booted successfully */
1553 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1558 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1561 * Load the global HKU hive directly from sysconfdir
1563 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1566 * Load the global machine defaults directly form sysconfdir
1568 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1574 * Load the user saved registries
1576 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1578 const char *confdir
= get_config_dir();
1579 int len
= strlen(confdir
) + 20;
1582 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1584 * Load user's personal versions of global HKU/.Default keys
1589 strcpy( fn
, confdir
);
1590 str
= fn
+ strlen(fn
);
1593 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1594 _wine_loadreg( HKEY_USERS
, fn
);
1596 strcpy( str
, SAVE_CURRENT_USER
);
1597 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1599 strcpy( str
, SAVE_LOCAL_MACHINE
);
1600 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1602 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1606 SHELL_InitRegistrySaving();
1609 /********************* API FUNCTIONS ***************************************/
1614 /******************************************************************************
1615 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1616 * Immediately writes key to registry.
1617 * Only returns after data has been written to disk.
1619 * FIXME: does it really wait until data is written ?
1622 * hkey [I] Handle of key to write
1625 * Success: ERROR_SUCCESS
1626 * Failure: Error code
1628 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1630 FIXME( "(%x): stub\n", hkey
);
1631 return ERROR_SUCCESS
;
1634 /******************************************************************************
1635 * RegConnectRegistryW [ADVAPI32.128]
1638 * lpMachineName [I] Address of name of remote computer
1639 * hHey [I] Predefined registry handle
1640 * phkResult [I] Address of buffer for remote registry handle
1642 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1645 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1647 if (!lpMachineName
|| !*lpMachineName
) {
1648 /* Use the local machine name */
1649 return RegOpenKey16( hKey
, "", phkResult
);
1652 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1653 return ERROR_BAD_NETPATH
;
1657 /******************************************************************************
1658 * RegConnectRegistryA [ADVAPI32.127]
1660 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1663 LPWSTR machineW
= strdupA2W(machine
);
1664 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1670 /******************************************************************************
1671 * RegGetKeySecurity [ADVAPI32.144]
1672 * Retrieves a copy of security descriptor protecting the registry key
1675 * hkey [I] Open handle of key to set
1676 * SecurityInformation [I] Descriptor contents
1677 * pSecurityDescriptor [O] Address of descriptor for key
1678 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1681 * Success: ERROR_SUCCESS
1682 * Failure: Error code
1684 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1685 SECURITY_INFORMATION SecurityInformation
,
1686 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1687 LPDWORD lpcbSecurityDescriptor
)
1689 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1690 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1692 /* FIXME: Check for valid SecurityInformation values */
1694 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1695 return ERROR_INSUFFICIENT_BUFFER
;
1697 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1698 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1700 return ERROR_SUCCESS
;
1704 /******************************************************************************
1705 * RegNotifyChangeKeyValue [ADVAPI32.???]
1708 * hkey [I] Handle of key to watch
1709 * fWatchSubTree [I] Flag for subkey notification
1710 * fdwNotifyFilter [I] Changes to be reported
1711 * hEvent [I] Handle of signaled event
1712 * fAsync [I] Flag for asynchronous reporting
1714 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1715 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1718 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1720 return ERROR_SUCCESS
;
1724 /******************************************************************************
1725 * RegUnLoadKeyW [ADVAPI32.173]
1728 * hkey [I] Handle of open key
1729 * lpSubKey [I] Address of name of subkey to unload
1731 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1733 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1734 return ERROR_SUCCESS
;
1738 /******************************************************************************
1739 * RegUnLoadKeyA [ADVAPI32.172]
1741 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1744 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1745 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1746 if(lpSubKeyW
) free(lpSubKeyW
);
1751 /******************************************************************************
1752 * RegSetKeySecurity [ADVAPI32.167]
1755 * hkey [I] Open handle of key to set
1756 * SecurityInfo [I] Descriptor contents
1757 * pSecurityDesc [I] Address of descriptor for key
1759 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1760 PSECURITY_DESCRIPTOR pSecurityDesc
)
1762 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1764 /* It seems to perform this check before the hkey check */
1765 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1766 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1767 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1768 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1771 return ERROR_INVALID_PARAMETER
;
1774 return ERROR_INVALID_PARAMETER
;
1776 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1778 return ERROR_SUCCESS
;
1782 /******************************************************************************
1783 * RegRestoreKeyW [ADVAPI32.164]
1786 * hkey [I] Handle of key where restore begins
1787 * lpFile [I] Address of filename containing saved tree
1788 * dwFlags [I] Optional flags
1790 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1792 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1794 /* It seems to do this check before the hkey check */
1795 if (!lpFile
|| !*lpFile
)
1796 return ERROR_INVALID_PARAMETER
;
1798 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1800 /* Check for file existence */
1802 return ERROR_SUCCESS
;
1806 /******************************************************************************
1807 * RegRestoreKeyA [ADVAPI32.163]
1809 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1812 LPWSTR lpFileW
= strdupA2W(lpFile
);
1813 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1814 if(lpFileW
) free(lpFileW
);
1819 /******************************************************************************
1820 * RegReplaceKeyW [ADVAPI32.162]
1823 * hkey [I] Handle of open key
1824 * lpSubKey [I] Address of name of subkey
1825 * lpNewFile [I] Address of filename for file with new data
1826 * lpOldFile [I] Address of filename for backup file
1828 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1831 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1832 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1833 return ERROR_SUCCESS
;
1837 /******************************************************************************
1838 * RegReplaceKeyA [ADVAPI32.161]
1840 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1844 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1845 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1846 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1847 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1859 /* 16-bit functions */
1861 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1862 * some programs. Do not remove those cases. -MM
1864 static inline void fix_win16_hkey( HKEY
*hkey
)
1866 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1869 /******************************************************************************
1870 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1872 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1874 fix_win16_hkey( &hkey
);
1875 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1878 /******************************************************************************
1879 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1881 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1883 fix_win16_hkey( &hkey
);
1884 return RegOpenKeyA( hkey
, name
, retkey
);
1887 /******************************************************************************
1888 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1890 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1892 fix_win16_hkey( &hkey
);
1893 return RegCreateKeyA( hkey
, name
, retkey
);
1896 /******************************************************************************
1897 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1899 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1901 fix_win16_hkey( &hkey
);
1902 return RegDeleteKeyA( hkey
, name
);
1905 /******************************************************************************
1906 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1908 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1910 fix_win16_hkey( &hkey
);
1911 return RegCloseKey( hkey
);
1914 /******************************************************************************
1915 * RegSetValue16 [KERNEL.221] [SHELL.5]
1917 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1919 fix_win16_hkey( &hkey
);
1920 return RegSetValueA( hkey
, name
, type
, data
, count
);
1923 /******************************************************************************
1924 * RegDeleteValue16 [KERNEL.222]
1926 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1928 fix_win16_hkey( &hkey
);
1929 return RegDeleteValueA( hkey
, name
);
1932 /******************************************************************************
1933 * RegEnumValue16 [KERNEL.223]
1935 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1936 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1938 fix_win16_hkey( &hkey
);
1939 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1942 /******************************************************************************
1943 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1946 * Is this HACK still applicable?
1949 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1950 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1953 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1955 fix_win16_hkey( &hkey
);
1956 if (count
) *count
&= 0xffff;
1957 return RegQueryValueA( hkey
, name
, data
, count
);
1960 /******************************************************************************
1961 * RegQueryValueEx16 [KERNEL.225]
1963 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1964 LPBYTE data
, LPDWORD count
)
1966 fix_win16_hkey( &hkey
);
1967 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1970 /******************************************************************************
1971 * RegSetValueEx16 [KERNEL.226]
1973 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1974 CONST BYTE
*data
, DWORD count
)
1976 fix_win16_hkey( &hkey
);
1977 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);