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_DEFAULT_USER "userdef.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 /* what valuetypes do we need to convert? */
67 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
70 static void *xmalloc( size_t size
)
74 res
= malloc (size
? size
: 1);
76 WARN("Virtual memory exhausted.\n");
84 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
85 * If so, can we remove them?
87 * No, the memory handling functions are called very often in here,
88 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
89 * loading 100 times slower. -MM
91 static LPWSTR
strdupA2W(LPCSTR src
)
94 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
95 lstrcpyAtoW(dest
,src
);
101 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
104 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
106 lstrcpynAtoW(dest
,src
,nchars
+1);
112 /******************************************************************************
113 * REGISTRY_Init [Internal]
114 * Registry initialisation, allocates some default keys.
116 static void REGISTRY_Init(void) {
122 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
125 /* This was an Open, but since it is called before the real registries
126 are loaded, it was changed to a Create - MTB 980507*/
127 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
128 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
131 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
135 * string RegisteredOwner
136 * string RegisteredOrganization
139 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
144 if (-1!=gethostname(buf
,200)) {
145 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
146 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
152 /************************ LOAD Registry Function ****************************/
156 /******************************************************************************
157 * _find_or_add_key [Internal]
159 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
162 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
163 if (keyname
) free( keyname
);
167 /******************************************************************************
168 * _find_or_add_value [Internal]
170 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
172 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
173 if (name
) free( name
);
174 if (data
) free( data
);
178 /******************************************************************************
179 * _wine_read_line [Internal]
181 * reads a line including dynamically enlarging the readbuffer and throwing
184 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
194 s
=fgets(curread
,mylen
,F
);
197 if (NULL
==(s
=strchr(curread
,'\n'))) {
198 /* buffer wasn't large enough */
199 curoff
= strlen(*buf
);
200 curread
= realloc(*buf
,*len
*2);
201 if(curread
== NULL
) {
202 WARN("Out of memory");
207 mylen
= *len
; /* we filled up the buffer and
208 * got new '*len' bytes to fill
216 /* throw away comments */
217 if (**buf
=='#' || **buf
==';') {
222 if (s
) /* got end of line */
229 /******************************************************************************
230 * _wine_read_USTRING [Internal]
232 * converts a char* into a UNICODE string (up to a special char)
233 * and returns the position exactly after that string
235 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
240 /* read up to "=" or "\0" or "\n" */
242 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
244 while (*s
&& (*s
!='\n') && (*s
!='=')) {
246 *ws
++=*((unsigned char*)s
++);
250 /* Dangling \ ... may only happen if a registry
251 * write was short. FIXME: What do to?
261 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
269 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
270 if (!sscanf(xbuf
,"%x",&wc
))
271 WARN("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
273 *ws
++ =(unsigned short)wc
;
282 /******************************************************************************
283 * _wine_loadsubkey [Internal]
286 * It seems like this is returning a boolean. Should it?
292 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
299 TRACE("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
301 /* Good. We already got a line here ... so parse it */
311 WARN("Got a subhierarchy without resp. key?\n");
314 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
315 if (!_wine_read_line(F
,buf
,buflen
))
320 /* let the caller handle this line */
321 if (i
<level
|| **buf
=='\0')
324 /* it can be: a value or a keyname. Parse the name first */
325 s
=_wine_read_USTRING(s
,&name
);
327 /* switch() default: hack to avoid gotos */
331 if (subkey
) RegCloseKey( subkey
);
332 subkey
=_find_or_add_key(hkey
,name
);
335 int len
,lastmodified
,type
;
338 WARN("Unexpected character: %c\n",*s
);
342 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
343 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
350 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
353 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
354 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
355 len
= lstrlenW((LPWSTR
)data
)*2+2;
358 data
= (LPBYTE
)xmalloc(len
+1);
359 for (i
=0;i
<len
;i
++) {
361 if (*s
>='0' && *s
<='9')
363 if (*s
>='a' && *s
<='f')
364 data
[i
]=(*s
-'a'+'\xa')<<4;
365 if (*s
>='A' && *s
<='F')
366 data
[i
]=(*s
-'A'+'\xa')<<4;
368 if (*s
>='0' && *s
<='9')
370 if (*s
>='a' && *s
<='f')
371 data
[i
]|=*s
-'a'+'\xa';
372 if (*s
>='A' && *s
<='F')
373 data
[i
]|=*s
-'A'+'\xa';
377 _find_or_add_value(hkey
,name
,type
,data
,len
);
380 /* read the next line */
381 if (!_wine_read_line(F
,buf
,buflen
))
385 if (subkey
) RegCloseKey( subkey
);
390 /******************************************************************************
391 * _wine_loadsubreg [Internal]
393 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
399 buf
=xmalloc(10);buflen
=10;
400 if (!_wine_read_line(F
,&buf
,&buflen
)) {
404 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
409 if (ver
== 2) /* new version */
412 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
413 FILE_ATTRIBUTE_NORMAL
, -1, TRUE
)) != INVALID_HANDLE_VALUE
)
415 struct load_registry_request
*req
= get_req_buffer();
419 server_call( REQ_LOAD_REGISTRY
);
427 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
432 if (!_wine_read_line(F
,&buf
,&buflen
)) {
436 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
445 /******************************************************************************
446 * _wine_loadreg [Internal]
448 static int _wine_loadreg( HKEY hkey
, char *fn
)
452 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
456 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
459 _wine_loadsubreg(F
,hkey
,fn
);
464 /* NT REGISTRY LOADER */
466 #ifdef HAVE_SYS_MMAN_H
467 # include <sys/mman.h>
471 #define MAP_FAILED ((LPVOID)-1)
474 #define NT_REG_BLOCK_SIZE 0x1000
476 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
477 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
478 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
479 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
481 /* subblocks of nk */
482 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
483 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
484 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
486 #define NT_REG_KEY_BLOCK_TYPE 0x20
487 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
491 DWORD id
; /* 0x66676572 'regf'*/
492 DWORD uk1
; /* 0x04 */
493 DWORD uk2
; /* 0x08 */
494 FILETIME DateModified
; /* 0x0c */
495 DWORD uk3
; /* 0x14 */
496 DWORD uk4
; /* 0x18 */
497 DWORD uk5
; /* 0x1c */
498 DWORD uk6
; /* 0x20 */
499 DWORD RootKeyBlock
; /* 0x24 */
500 DWORD BlockSize
; /* 0x28 */
502 DWORD Checksum
; /* at offset 0x1FC */
513 DWORD id
; /* 0x6E696268 'hbin' */
517 DWORD uk2
; /* 0x10 */
518 DWORD uk3
; /* 0x14 */
519 DWORD uk4
; /* 0x18 */
520 DWORD size
; /* 0x1C */
521 nt_hbin_sub hbin_sub
; /* 0x20 */
525 * the value_list consists of offsets to the values (vk)
529 WORD SubBlockId
; /* 0x00 0x6B6E */
530 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
531 FILETIME writetime
; /* 0x04 */
532 DWORD uk1
; /* 0x0C */
533 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
534 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
535 DWORD uk8
; /* 0x18 */
536 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
537 DWORD uk2
; /* 0x20 */
538 DWORD nr_values
; /* 0x24 number of values */
539 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
540 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
541 DWORD off_class
; /* 0x30 Offset of the Class-Name */
542 DWORD uk3
; /* 0x34 */
543 DWORD uk4
; /* 0x38 */
544 DWORD uk5
; /* 0x3c */
545 DWORD uk6
; /* 0x40 */
546 DWORD uk7
; /* 0x44 */
547 WORD name_len
; /* 0x48 name-length */
548 WORD class_len
; /* 0x4a class-name length */
549 char name
[1]; /* 0x4c key-name */
554 DWORD off_nk
; /* 0x00 */
555 DWORD name
; /* 0x04 */
560 WORD id
; /* 0x00 0x666c */
561 WORD nr_keys
; /* 0x06 */
562 hash_rec hash_rec
[1];
566 list of subkeys without hash
574 WORD id
; /* 0x00 0x696c */
580 this is a intermediate node
592 WORD id
; /* 0x00 0x6972 */
593 WORD nr_li
; /* 0x02 number off offsets */
594 DWORD off_li
[1]; /* 0x04 points to li */
599 WORD id
; /* 0x00 'vk' */
609 LPSTR
_strdupnA( LPCSTR str
, int len
)
613 if (!str
) return NULL
;
614 ret
= malloc( len
+ 1 );
615 lstrcpynA( ret
, str
, len
);
620 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
);
621 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
);
622 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
);
629 * 0 value is a default value
630 * 1 the value has a name
633 * len of the whole data block
635 * bytes including the terminating \0 = 2*(number_of_chars+1)
636 * - reg_dword, reg_binary:
637 * if highest bit of data_len is set data_off contains the value
639 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
)
643 BYTE
* pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
645 if(vk
->id
!= NT_REG_VALUE_BLOCK_ID
) goto error
;
647 lstrcpynAtoW(name
, vk
->name
, vk
->nam_len
+1);
649 ret
= RegSetValueExW( hkey
, (vk
->flag
& 0x00000001) ? name
: NULL
, 0, vk
->type
,
650 (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
,
651 (vk
->data_len
& 0x7fffffff) );
652 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
655 ERR_(reg
)("unknown block found (0x%04x), please report!\n", vk
->id
);
662 * this structure contains the hash of a keyname and points to all
665 * exception: if the id is 'il' there are no hash values and every
668 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
)
672 if (lf
->id
== NT_REG_HASH_BLOCK_ID
)
674 if (subkeys
!= lf
->nr_keys
) goto error1
;
676 for (i
=0; i
<lf
->nr_keys
; i
++)
678 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), level
)) goto error
;
681 else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
)
683 nt_li
* li
= (nt_li
*)lf
;
684 if (subkeys
!= li
->nr_keys
) goto error1
;
686 for (i
=0; i
<li
->nr_keys
; i
++)
688 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), level
)) goto error
;
691 else if (lf
->id
== NT_REG_RI_BLOCK_ID
) /* ri */
693 nt_ri
* ri
= (nt_ri
*)lf
;
696 /* count all subkeys */
697 for (i
=0; i
<ri
->nr_li
; i
++)
699 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
700 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
701 li_subkeys
+= li
->nr_keys
;
705 if (subkeys
!= li_subkeys
) goto error1
;
707 /* loop through the keys */
708 for (i
=0; i
<ri
->nr_li
; i
++)
710 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
711 if (!_nt_parse_lf(hkey
, base
, li
->nr_keys
, (nt_lf
*)li
, level
)) goto error
;
720 error2
: ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
723 error1
: ERR_(reg
)("registry file corrupt! (inconsistent number of subkeys)\n");
726 error
: ERR_(reg
)("error reading lf block\n");
730 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
737 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)
739 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
743 if((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) &&
744 (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
))
746 ERR_(reg
)("registry file corrupt!\n");
750 /* create the new key */
753 name
= _strdupnA( nk
->name
, nk
->name_len
+1);
754 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
758 /* loop through the subkeys */
761 nt_lf
* lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
762 if (!_nt_parse_lf(subkey
, base
, nk
->nr_subkeys
, lf
, level
-1)) goto error1
;
765 /* loop trough the value list */
766 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
767 for (i
=0; i
<nk
->nr_values
; i
++)
769 nt_vk
* vk
= (nt_vk
*)(base
+vl
[i
]+4);
770 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
776 error1
: RegCloseKey(subkey
);
782 /* windows 95 registry loader */
784 /* SECTION 1: main header
788 #define W95_REG_CREG_ID 0x47455243
792 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
793 DWORD version
; /* ???? 0x00010000 */
794 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
795 DWORD uk2
; /* 0x0c */
796 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
802 /* SECTION 2: Directory information (tree structure)
804 * once on offset 0x20
806 * structure: [rgkn][dke]* (repeat till rgkn->size is reached)
808 #define W95_REG_RGKN_ID 0x4e4b4752
812 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
813 DWORD size
; /* Size of the RGKN-block */
814 DWORD root_off
; /* Rel. Offset of the root-record */
818 /* Disk Key Entry Structure
820 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
821 * hive itself. It looks the same like other keys. Even the ID-number can
824 * The "hash"-value is a value representing the key's name. Windows will not
825 * search for the name, but for a matching hash-value. if it finds one, it
826 * will compare the actual string info, otherwise continue with the next key.
827 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
828 * of the string which are smaller than 0x80 (128) to this D-Word.
830 * If you want to modify key names, also modify the hash-values, since they
831 * cannot be found again (although they would be displayed in REGEDIT)
832 * End of list-pointers are filled with 0xFFFFFFFF
834 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
835 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
836 * structure) and reading another RGDB_section.
838 * there is a one to one relationship between dke and dkh
840 /* key struct, once per key */
843 DWORD x1
; /* Free entry indicator(?) */
844 DWORD hash
; /* sum of bytes of keyname */
845 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
846 DWORD prevlvl
; /* offset of previous key */
847 DWORD nextsub
; /* offset of child key */
848 DWORD next
; /* offset of sibling key */
849 WORD nrLS
; /* id inside the rgdb block */
850 WORD nrMS
; /* number of the rgdb block */
853 /* SECTION 3: key information, values and data
856 * section: [blocks]* (repeat creg->rgdb_num times)
857 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
858 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
860 * An interesting relationship exists in RGDB_section. The value at offset
861 * 10 equals the value at offset 4 minus the value at offset 8. I have no
862 * idea at the moment what this means. (Kevin Cozens)
865 /* block header, once per block */
866 #define W95_REG_RGDB_ID 0x42444752
870 DWORD id
; /* 0x00 'rgdb' = W95_REG_RGDB_ID */
871 DWORD size
; /* 0x04 */
872 DWORD uk1
; /* 0x08 */
873 DWORD uk2
; /* 0x0c */
874 DWORD uk3
; /* 0x10 */
875 DWORD uk4
; /* 0x14 */
876 DWORD uk5
; /* 0x18 */
877 DWORD uk6
; /* 0x1c */
881 /* Disk Key Header structure (RGDB part), once per key */
884 DWORD nextkeyoff
; /* 0x00 offset to next dkh*/
885 WORD nrLS
; /* 0x04 id inside the rgdb block */
886 WORD nrMS
; /* 0x06 number of the rgdb block */
887 DWORD bytesused
; /* 0x08 */
888 WORD keynamelen
; /* 0x0c len of name */
889 WORD values
; /* 0x0e number of values */
890 DWORD xx1
; /* 0x10 */
891 char name
[1]; /* 0x14 */
892 /* dkv */ /* 0x14 + keynamelen */
895 /* Disk Key Value structure, once per value */
898 DWORD type
; /* 0x00 */
900 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
901 WORD valdatalen
; /* 0x0A length of data */
902 char name
[1]; /* 0x0c */
903 /* raw data */ /* 0x0c + valnamelen */
906 /******************************************************************************
907 * _w95_lookup_dkh [Internal]
909 * seeks the dkh belonging to a dke
911 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
917 /* get the beginning of the rgdb datastore */
918 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
920 /* check: requested block < last_block) */
921 if (creg
->rgdb_num
<= nrMS
)
923 ERR("registry file corrupt! requested block no. beyond end.\n");
927 /* find the right block */
928 for(i
=0; i
<nrMS
;i
++)
930 if(rgdb
->id
!= W95_REG_RGDB_ID
) /* check the magic */
932 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
935 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
938 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
942 if(nrLS
==dkh
->nrLS
) return dkh
;
943 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
944 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
949 /******************************************************************************
950 * _w95_parse_dkv [Internal]
952 static int _w95_parse_dkv (
963 /* first value block */
964 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
966 /* loop trought the values */
967 for (i
=0; i
< dkh
->values
; i
++)
969 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
+1);
970 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
971 if (ret
) FIXME("RegSetValueEx returned: 0x%08lx\n", ret
);
975 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
980 /******************************************************************************
981 * _w95_parse_dke [Internal]
983 static int _w95_parse_dke(
995 /* get start address of root key block */
996 if (!dke
) dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
998 /* special root key */
999 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
1001 /* parse the one subkey*/
1002 if (dke
->nextsub
!= 0xffffffff)
1004 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
1006 /* has no sibling keys */
1010 /* search subblock */
1011 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
1013 fprintf(stderr
, "dke pointing to missing dkh !\n");
1019 /* walk sibling keys */
1020 if (dke
->next
!= 0xffffffff )
1022 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1025 /* create subkey and insert values */
1026 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
+1);
1027 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1029 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1033 if (dke
->nextsub
!= 0xffffffff)
1035 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1039 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1042 /* end windows 95 loader */
1044 /******************************************************************************
1045 * NativeRegLoadKey [Internal]
1047 * Loads a native registry file (win95/nt)
1050 * level number of levels to cut away (eg. ".Default" in user.dat)
1052 * this function intentionally uses unix file functions to make it possible
1053 * to move it to a seperate registry helper programm
1055 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1059 DOS_FULL_NAME full_name
;
1063 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1065 /* map the registry into the memory */
1066 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1067 if ((fstat(fd
, &st
) == -1)) goto error
;
1068 if (!st
.st_size
) goto error
;
1069 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1071 switch (*(LPDWORD
)base
)
1073 /* windows 95 'creg' */
1074 case W95_REG_CREG_ID
:
1079 TRACE_(reg
)("Loading win95 registry '%s' '%s'\n",fn
, full_name
.long_name
);
1081 /* load the header (rgkn) */
1082 rgkn
= (_w95rgkn
*)(creg
+ 1);
1083 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1085 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1089 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, NULL
, level
);
1093 case NT_REG_HEADER_BLOCK_ID
:
1097 nt_hbin_sub
* hbin_sub
;
1100 TRACE_(reg
)("Loading nt registry '%s' '%s'\n",fn
, full_name
.long_name
);
1106 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1107 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1109 ERR_(reg
)( "%s hbin block invalid\n", fn
);
1113 /* hbin_sub block */
1114 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1115 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1117 ERR_(reg
)( "%s hbin_sub block invalid\n", fn
);
1122 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1123 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1125 ERR_(reg
)( "%s special nk block not found\n", fn
);
1129 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1134 ERR("unknown signature in registry file %s.\n",fn
);
1138 if(!ret
) ERR("error loading registry file %s\n", fn
);
1139 error1
: munmap(base
, st
.st_size
);
1144 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1146 reghack - windows 3.11 registry data format demo program.
1148 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1149 a combined hash table and tree description, and finally a text table.
1151 The header is obvious from the struct header. The taboff1 and taboff2
1152 fields are always 0x20, and their usage is unknown.
1154 The 8-byte entry table has various entry types.
1156 tabent[0] is a root index. The second word has the index of the root of
1158 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1159 the index of the key/value that has that hash. Data with the same
1160 hash value are on a circular list. The other three words in the
1161 hash entry are always zero.
1162 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1163 entry: dirent and keyent/valent. They are identified by context.
1164 tabent[freeidx] is the first free entry. The first word in a free entry
1165 is the index of the next free entry. The last has 0 as a link.
1166 The other three words in the free list are probably irrelevant.
1168 Entries in text table are preceeded by a word at offset-2. This word
1169 has the value (2*index)+1, where index is the referring keyent/valent
1170 entry in the table. I have no suggestion for the 2* and the +1.
1171 Following the word, there are N bytes of data, as per the keyent/valent
1172 entry length. The offset of the keyent/valent entry is from the start
1173 of the text table to the first data byte.
1175 This information is not available from Microsoft. The data format is
1176 deduced from the reg.dat file by me. Mistakes may
1177 have been made. I claim no rights and give no guarantees for this program.
1179 Tor Sjøwall, tor@sn.no
1182 /* reg.dat header format */
1183 struct _w31_header
{
1184 char cookie
[8]; /* 'SHCC3.10' */
1185 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1186 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1187 unsigned long tabcnt
; /* number of entries in index table */
1188 unsigned long textoff
; /* offset of text part */
1189 unsigned long textsize
; /* byte size of text part */
1190 unsigned short hashsize
; /* hash size */
1191 unsigned short freeidx
; /* free index */
1194 /* generic format of table entries */
1195 struct _w31_tabent
{
1196 unsigned short w0
, w1
, w2
, w3
;
1199 /* directory tabent: */
1200 struct _w31_dirent
{
1201 unsigned short sibling_idx
; /* table index of sibling dirent */
1202 unsigned short child_idx
; /* table index of child dirent */
1203 unsigned short key_idx
; /* table index of key keyent */
1204 unsigned short value_idx
; /* table index of value valent */
1208 struct _w31_keyent
{
1209 unsigned short hash_idx
; /* hash chain index for string */
1210 unsigned short refcnt
; /* reference count */
1211 unsigned short length
; /* length of string */
1212 unsigned short string_off
; /* offset of string in text table */
1216 struct _w31_valent
{
1217 unsigned short hash_idx
; /* hash chain index for string */
1218 unsigned short refcnt
; /* reference count */
1219 unsigned short length
; /* length of string */
1220 unsigned short string_off
; /* offset of string in text table */
1223 /* recursive helper function to display a directory tree */
1225 __w31_dumptree( unsigned short idx
,
1227 struct _w31_tabent
*tab
,
1228 struct _w31_header
*head
,
1230 time_t lastmodified
,
1233 struct _w31_dirent
*dir
;
1234 struct _w31_keyent
*key
;
1235 struct _w31_valent
*val
;
1237 static char tail
[400];
1240 dir
=(struct _w31_dirent
*)&tab
[idx
];
1243 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1245 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1246 tail
[key
->length
]='\0';
1247 /* all toplevel entries AND the entries in the
1248 * toplevel subdirectory belong to \SOFTWARE\Classes
1250 if (!level
&& !lstrcmpA(tail
,".classes")) {
1251 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1252 idx
=dir
->sibling_idx
;
1255 if (subkey
) RegCloseKey( subkey
);
1256 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1257 /* only add if leaf node or valued node */
1258 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1259 if (dir
->value_idx
) {
1260 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1261 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1262 tail
[val
->length
]='\0';
1263 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1267 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1269 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1270 idx
=dir
->sibling_idx
;
1272 if (subkey
) RegCloseKey( subkey
);
1276 /******************************************************************************
1277 * _w31_loadreg [Internal]
1279 void _w31_loadreg(void) {
1281 struct _w31_header head
;
1282 struct _w31_tabent
*tab
;
1286 BY_HANDLE_FILE_INFORMATION hfinfo
;
1287 time_t lastmodified
;
1291 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1292 if (hf
==HFILE_ERROR
)
1295 /* read & dump header */
1296 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1297 ERR("reg.dat is too short.\n");
1301 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1302 ERR("reg.dat has bad signature.\n");
1307 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1308 /* read and dump index table */
1310 if (len
!=_lread(hf
,tab
,len
)) {
1311 ERR("couldn't read %d bytes.\n",len
);
1318 txt
= xmalloc(head
.textsize
);
1319 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1320 ERR("couldn't seek to textblock.\n");
1326 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1327 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1334 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1335 ERR("GetFileInformationByHandle failed?.\n");
1341 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1342 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1350 /* configure save files and start the periodic saving timer */
1351 static void SHELL_InitRegistrySaving( HKEY hkey_users_default
)
1353 struct set_registry_levels_request
*req
= get_req_buffer();
1355 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1356 int period
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1358 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
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_DEFAULT_USER
);
1388 req
->hkey
= hkey_users_default
;
1389 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1391 strcpy( req
->file
, confdir
);
1392 strcpy( str
, "/" SAVE_LOCAL_USERS_DEFAULT
);
1393 req
->hkey
= HKEY_USERS
;
1394 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1399 /**********************************************************************************
1400 * SetLoadLevel [Internal]
1402 * set level to 0 for loading system files
1403 * set level to 1 for loading user files
1405 static void SetLoadLevel(int level
)
1407 struct set_registry_levels_request
*req
= get_req_buffer();
1409 req
->current
= level
;
1412 server_call( REQ_SET_REGISTRY_LEVELS
);
1415 /**********************************************************************************
1416 * SHELL_LoadRegistry [Internal]
1418 #define REG_DONTLOAD -1
1423 void SHELL_LoadRegistry( void )
1426 char windir
[MAX_PATHNAME_LEN
];
1427 char path
[MAX_PATHNAME_LEN
];
1428 int systemtype
= REG_WIN31
;
1429 HKEY hkey_users_default
;
1433 if (!CLIENT_IsBootThread()) return; /* already loaded */
1438 if (RegCreateKeyA(HKEY_USERS
, ".Default", &hkey_users_default
)) hkey_users_default
= 0;
1440 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1442 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1444 /* test %windir%/system32/config/system --> winnt */
1445 strcpy(path
, windir
);
1446 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1447 if(GetFileAttributesA(path
) != -1)
1449 systemtype
= REG_WINNT
;
1453 /* test %windir%/system.dat --> win95 */
1454 strcpy(path
, windir
);
1455 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1456 if(GetFileAttributesA(path
) != -1)
1458 systemtype
= REG_WIN95
;
1462 if ((systemtype
==REG_WINNT
)
1463 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1465 MESSAGE("When you are running with a native NT directory specify\n");
1466 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1467 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1468 systemtype
= REG_DONTLOAD
;
1473 /* only wine registry */
1474 systemtype
= REG_DONTLOAD
;
1484 /* Load windows 95 entries */
1485 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1487 strcpy(path
, windir
);
1488 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1489 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1491 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1493 /* user specific user.dat */
1494 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1495 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1497 MESSAGE("can't load win95 user-registry %s\n", path
);
1498 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1500 /* default user.dat */
1501 if (hkey_users_default
)
1503 strcpy(path
, windir
);
1504 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1505 NativeRegLoadKey(hkey_users_default
, path
, 1);
1510 /* global user.dat */
1511 strcpy(path
, windir
);
1512 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1513 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1518 /* default user.dat */
1519 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1521 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1522 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1524 MESSAGE("can't load NT user-registry %s\n", path
);
1525 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1529 /* default user.dat */
1530 if (hkey_users_default
)
1532 strcpy(path
, windir
);
1533 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1534 NativeRegLoadKey(hkey_users_default
, path
, 1);
1539 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1542 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM", &hkey
))
1544 strcpy(path
, windir
);
1545 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1546 NativeRegLoadKey(hkey
, path
, 1);
1550 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SOFTWARE", &hkey
))
1552 strcpy(path
, windir
);
1553 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1554 NativeRegLoadKey(hkey
, path
, 1);
1558 strcpy(path
, windir
);
1559 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1560 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1562 strcpy(path
, windir
);
1563 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1564 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1566 /* this key is generated when the nt-core booted successfully */
1567 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1572 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1575 * Load the global HKU hive directly from sysconfdir
1577 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1580 * Load the global machine defaults directly form sysconfdir
1582 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1588 * Load the user saved registries
1590 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1592 const char *confdir
= get_config_dir();
1593 int len
= strlen(confdir
) + 20;
1596 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1598 * Load user's personal versions of global HKU/.Default keys
1603 strcpy( fn
, confdir
);
1604 str
= fn
+ strlen(fn
);
1607 /* try to load HKU\.Default key only */
1608 strcpy( str
, SAVE_DEFAULT_USER
);
1609 if (_wine_loadreg( hkey_users_default
, fn
))
1611 /* if not found load old file containing both HKU\.Default and HKU\user */
1612 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1613 _wine_loadreg( HKEY_USERS
, fn
);
1616 strcpy( str
, SAVE_CURRENT_USER
);
1617 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1619 strcpy( str
, SAVE_LOCAL_MACHINE
);
1620 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1622 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1625 SHELL_InitRegistrySaving( hkey_users_default
);
1626 RegCloseKey( hkey_users_default
);
1629 /********************* API FUNCTIONS ***************************************/
1634 /******************************************************************************
1635 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1636 * Immediately writes key to registry.
1637 * Only returns after data has been written to disk.
1639 * FIXME: does it really wait until data is written ?
1642 * hkey [I] Handle of key to write
1645 * Success: ERROR_SUCCESS
1646 * Failure: Error code
1648 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1650 FIXME( "(%x): stub\n", hkey
);
1651 return ERROR_SUCCESS
;
1654 /******************************************************************************
1655 * RegConnectRegistryW [ADVAPI32.128]
1658 * lpMachineName [I] Address of name of remote computer
1659 * hHey [I] Predefined registry handle
1660 * phkResult [I] Address of buffer for remote registry handle
1662 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1665 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1667 if (!lpMachineName
|| !*lpMachineName
) {
1668 /* Use the local machine name */
1669 return RegOpenKey16( hKey
, "", phkResult
);
1672 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1673 return ERROR_BAD_NETPATH
;
1677 /******************************************************************************
1678 * RegConnectRegistryA [ADVAPI32.127]
1680 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1683 LPWSTR machineW
= strdupA2W(machine
);
1684 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1690 /******************************************************************************
1691 * RegGetKeySecurity [ADVAPI32.144]
1692 * Retrieves a copy of security descriptor protecting the registry key
1695 * hkey [I] Open handle of key to set
1696 * SecurityInformation [I] Descriptor contents
1697 * pSecurityDescriptor [O] Address of descriptor for key
1698 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1701 * Success: ERROR_SUCCESS
1702 * Failure: Error code
1704 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1705 SECURITY_INFORMATION SecurityInformation
,
1706 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1707 LPDWORD lpcbSecurityDescriptor
)
1709 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1710 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1712 /* FIXME: Check for valid SecurityInformation values */
1714 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1715 return ERROR_INSUFFICIENT_BUFFER
;
1717 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1718 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1720 return ERROR_SUCCESS
;
1724 /******************************************************************************
1725 * RegNotifyChangeKeyValue [ADVAPI32.???]
1728 * hkey [I] Handle of key to watch
1729 * fWatchSubTree [I] Flag for subkey notification
1730 * fdwNotifyFilter [I] Changes to be reported
1731 * hEvent [I] Handle of signaled event
1732 * fAsync [I] Flag for asynchronous reporting
1734 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1735 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1738 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1740 return ERROR_SUCCESS
;
1744 /******************************************************************************
1745 * RegUnLoadKeyW [ADVAPI32.173]
1748 * hkey [I] Handle of open key
1749 * lpSubKey [I] Address of name of subkey to unload
1751 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1753 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1754 return ERROR_SUCCESS
;
1758 /******************************************************************************
1759 * RegUnLoadKeyA [ADVAPI32.172]
1761 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1764 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1765 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1766 if(lpSubKeyW
) free(lpSubKeyW
);
1771 /******************************************************************************
1772 * RegSetKeySecurity [ADVAPI32.167]
1775 * hkey [I] Open handle of key to set
1776 * SecurityInfo [I] Descriptor contents
1777 * pSecurityDesc [I] Address of descriptor for key
1779 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1780 PSECURITY_DESCRIPTOR pSecurityDesc
)
1782 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1784 /* It seems to perform this check before the hkey check */
1785 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1786 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1787 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1788 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1791 return ERROR_INVALID_PARAMETER
;
1794 return ERROR_INVALID_PARAMETER
;
1796 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1798 return ERROR_SUCCESS
;
1802 /******************************************************************************
1803 * RegRestoreKeyW [ADVAPI32.164]
1806 * hkey [I] Handle of key where restore begins
1807 * lpFile [I] Address of filename containing saved tree
1808 * dwFlags [I] Optional flags
1810 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1812 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1814 /* It seems to do this check before the hkey check */
1815 if (!lpFile
|| !*lpFile
)
1816 return ERROR_INVALID_PARAMETER
;
1818 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1820 /* Check for file existence */
1822 return ERROR_SUCCESS
;
1826 /******************************************************************************
1827 * RegRestoreKeyA [ADVAPI32.163]
1829 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1832 LPWSTR lpFileW
= strdupA2W(lpFile
);
1833 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1834 if(lpFileW
) free(lpFileW
);
1839 /******************************************************************************
1840 * RegReplaceKeyW [ADVAPI32.162]
1843 * hkey [I] Handle of open key
1844 * lpSubKey [I] Address of name of subkey
1845 * lpNewFile [I] Address of filename for file with new data
1846 * lpOldFile [I] Address of filename for backup file
1848 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1851 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1852 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1853 return ERROR_SUCCESS
;
1857 /******************************************************************************
1858 * RegReplaceKeyA [ADVAPI32.161]
1860 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1864 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1865 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1866 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1867 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1879 /* 16-bit functions */
1881 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1882 * some programs. Do not remove those cases. -MM
1884 static inline void fix_win16_hkey( HKEY
*hkey
)
1886 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1889 /******************************************************************************
1890 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1892 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1894 fix_win16_hkey( &hkey
);
1895 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1898 /******************************************************************************
1899 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1901 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1903 fix_win16_hkey( &hkey
);
1904 return RegOpenKeyA( hkey
, name
, retkey
);
1907 /******************************************************************************
1908 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1910 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1912 fix_win16_hkey( &hkey
);
1913 return RegCreateKeyA( hkey
, name
, retkey
);
1916 /******************************************************************************
1917 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1919 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1921 fix_win16_hkey( &hkey
);
1922 return RegDeleteKeyA( hkey
, name
);
1925 /******************************************************************************
1926 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1928 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1930 fix_win16_hkey( &hkey
);
1931 return RegCloseKey( hkey
);
1934 /******************************************************************************
1935 * RegSetValue16 [KERNEL.221] [SHELL.5]
1937 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1939 fix_win16_hkey( &hkey
);
1940 return RegSetValueA( hkey
, name
, type
, data
, count
);
1943 /******************************************************************************
1944 * RegDeleteValue16 [KERNEL.222]
1946 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1948 fix_win16_hkey( &hkey
);
1949 return RegDeleteValueA( hkey
, name
);
1952 /******************************************************************************
1953 * RegEnumValue16 [KERNEL.223]
1955 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1956 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1958 fix_win16_hkey( &hkey
);
1959 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1962 /******************************************************************************
1963 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1966 * Is this HACK still applicable?
1969 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1970 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1973 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1975 fix_win16_hkey( &hkey
);
1976 if (count
) *count
&= 0xffff;
1977 return RegQueryValueA( hkey
, name
, data
, count
);
1980 /******************************************************************************
1981 * RegQueryValueEx16 [KERNEL.225]
1983 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1984 LPBYTE data
, LPDWORD count
)
1986 fix_win16_hkey( &hkey
);
1987 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1990 /******************************************************************************
1991 * RegSetValueEx16 [KERNEL.226]
1993 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1994 CONST BYTE
*data
, DWORD count
)
1996 fix_win16_hkey( &hkey
);
1997 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);