4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
34 #include <sys/types.h>
36 #include <sys/fcntl.h>
42 #include "wine/winbase16.h"
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"
67 static void *xmalloc( size_t size
)
71 res
= malloc (size
? size
: 1);
73 WARN("Virtual memory exhausted.\n");
80 /******************************************************************************
81 * REGISTRY_Init [Internal]
82 * Registry initialisation, allocates some default keys.
84 static void REGISTRY_Init(void) {
90 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
93 /* This was an Open, but since it is called before the real registries
94 are loaded, it was changed to a Create - MTB 980507*/
95 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
96 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
99 /* \\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion
103 * string RegisteredOwner
104 * string RegisteredOrganization
107 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
112 if (-1!=gethostname(buf
,200)) {
113 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
114 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
120 /************************ LOAD Registry Function ****************************/
124 /******************************************************************************
125 * _find_or_add_key [Internal]
127 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
130 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
131 if (keyname
) free( keyname
);
135 /******************************************************************************
136 * _find_or_add_value [Internal]
138 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
140 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
141 if (name
) free( name
);
142 if (data
) free( data
);
146 /******************************************************************************
147 * _wine_read_line [Internal]
149 * reads a line including dynamically enlarging the readbuffer and throwing
152 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
162 s
=fgets(curread
,mylen
,F
);
165 if (NULL
==(s
=strchr(curread
,'\n'))) {
166 /* buffer wasn't large enough */
167 curoff
= strlen(*buf
);
168 curread
= realloc(*buf
,*len
*2);
169 if(curread
== NULL
) {
170 WARN("Out of memory");
175 mylen
= *len
; /* we filled up the buffer and
176 * got new '*len' bytes to fill
184 /* throw away comments */
185 if (**buf
=='#' || **buf
==';') {
190 if (s
) /* got end of line */
197 /******************************************************************************
198 * _wine_read_USTRING [Internal]
200 * converts a char* into a UNICODE string (up to a special char)
201 * and returns the position exactly after that string
203 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
208 /* read up to "=" or "\0" or "\n" */
210 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
212 while (*s
&& (*s
!='\n') && (*s
!='=')) {
214 *ws
++=*((unsigned char*)s
++);
218 /* Dangling \ ... may only happen if a registry
219 * write was short. FIXME: What to do?
229 WARN("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
237 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
238 if (!sscanf(xbuf
,"%x",&wc
))
239 WARN("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
241 *ws
++ =(unsigned short)wc
;
250 /******************************************************************************
251 * _wine_loadsubkey [Internal]
254 * It seems like this is returning a boolean. Should it?
260 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
267 TRACE("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
269 /* Good. We already got a line here ... so parse it */
279 WARN("Got a subhierarchy without resp. key?\n");
282 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
283 if (!_wine_read_line(F
,buf
,buflen
))
288 /* let the caller handle this line */
289 if (i
<level
|| **buf
=='\0')
292 /* it can be: a value or a keyname. Parse the name first */
293 s
=_wine_read_USTRING(s
,&name
);
295 /* switch() default: hack to avoid gotos */
299 if (subkey
) RegCloseKey( subkey
);
300 subkey
=_find_or_add_key(hkey
,name
);
303 int len
,lastmodified
,type
;
306 WARN("Unexpected character: %c\n",*s
);
310 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
311 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
318 WARN("Haven't understood possible value in |%s|, skipping.\n",*buf
);
321 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
322 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
323 len
= lstrlenW((LPWSTR
)data
)*2+2;
326 data
= (LPBYTE
)xmalloc(len
+1);
327 for (i
=0;i
<len
;i
++) {
329 if (*s
>='0' && *s
<='9')
331 if (*s
>='a' && *s
<='f')
332 data
[i
]=(*s
-'a'+'\xa')<<4;
333 if (*s
>='A' && *s
<='F')
334 data
[i
]=(*s
-'A'+'\xa')<<4;
336 if (*s
>='0' && *s
<='9')
338 if (*s
>='a' && *s
<='f')
339 data
[i
]|=*s
-'a'+'\xa';
340 if (*s
>='A' && *s
<='F')
341 data
[i
]|=*s
-'A'+'\xa';
345 _find_or_add_value(hkey
,name
,type
,data
,len
);
348 /* read the next line */
349 if (!_wine_read_line(F
,buf
,buflen
))
353 if (subkey
) RegCloseKey( subkey
);
358 /******************************************************************************
359 * _wine_loadsubreg [Internal]
361 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
367 buf
=xmalloc(10);buflen
=10;
368 if (!_wine_read_line(F
,&buf
,&buflen
)) {
372 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
377 if (ver
== 2) /* new version */
380 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
381 FILE_ATTRIBUTE_NORMAL
, -1, TRUE
)) != INVALID_HANDLE_VALUE
)
385 struct load_registry_request
*req
= server_alloc_req( sizeof(*req
), 0 );
388 server_call( REQ_LOAD_REGISTRY
);
398 TRACE("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
403 if (!_wine_read_line(F
,&buf
,&buflen
)) {
407 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
416 /******************************************************************************
417 * _wine_loadreg [Internal]
419 static int _wine_loadreg( HKEY hkey
, char *fn
)
423 TRACE("(%x,%s)\n",hkey
,debugstr_a(fn
));
427 WARN("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
430 _wine_loadsubreg(F
,hkey
,fn
);
435 /* NT REGISTRY LOADER */
437 #ifdef HAVE_SYS_MMAN_H
438 # include <sys/mman.h>
442 #define MAP_FAILED ((LPVOID)-1)
445 #define NT_REG_BLOCK_SIZE 0x1000
447 #define NT_REG_HEADER_BLOCK_ID 0x66676572 /* regf */
448 #define NT_REG_POOL_BLOCK_ID 0x6E696268 /* hbin */
449 #define NT_REG_KEY_BLOCK_ID 0x6b6e /* nk */
450 #define NT_REG_VALUE_BLOCK_ID 0x6b76 /* vk */
452 /* subblocks of nk */
453 #define NT_REG_HASH_BLOCK_ID 0x666c /* lf */
454 #define NT_REG_NOHASH_BLOCK_ID 0x696c /* li */
455 #define NT_REG_RI_BLOCK_ID 0x6972 /* ri */
457 #define NT_REG_KEY_BLOCK_TYPE 0x20
458 #define NT_REG_ROOT_KEY_BLOCK_TYPE 0x2c
462 DWORD id
; /* 0x66676572 'regf'*/
463 DWORD uk1
; /* 0x04 */
464 DWORD uk2
; /* 0x08 */
465 FILETIME DateModified
; /* 0x0c */
466 DWORD uk3
; /* 0x14 */
467 DWORD uk4
; /* 0x18 */
468 DWORD uk5
; /* 0x1c */
469 DWORD uk6
; /* 0x20 */
470 DWORD RootKeyBlock
; /* 0x24 */
471 DWORD BlockSize
; /* 0x28 */
473 DWORD Checksum
; /* at offset 0x1FC */
484 DWORD id
; /* 0x6E696268 'hbin' */
488 DWORD uk2
; /* 0x10 */
489 DWORD uk3
; /* 0x14 */
490 DWORD uk4
; /* 0x18 */
491 DWORD size
; /* 0x1C */
492 nt_hbin_sub hbin_sub
; /* 0x20 */
496 * the value_list consists of offsets to the values (vk)
500 WORD SubBlockId
; /* 0x00 0x6B6E */
501 WORD Type
; /* 0x02 for the root-key: 0x2C, otherwise 0x20*/
502 FILETIME writetime
; /* 0x04 */
503 DWORD uk1
; /* 0x0C */
504 DWORD parent_off
; /* 0x10 Offset of Owner/Parent key */
505 DWORD nr_subkeys
; /* 0x14 number of sub-Keys */
506 DWORD uk8
; /* 0x18 */
507 DWORD lf_off
; /* 0x1C Offset of the sub-key lf-Records */
508 DWORD uk2
; /* 0x20 */
509 DWORD nr_values
; /* 0x24 number of values */
510 DWORD valuelist_off
; /* 0x28 Offset of the Value-List */
511 DWORD off_sk
; /* 0x2c Offset of the sk-Record */
512 DWORD off_class
; /* 0x30 Offset of the Class-Name */
513 DWORD uk3
; /* 0x34 */
514 DWORD uk4
; /* 0x38 */
515 DWORD uk5
; /* 0x3c */
516 DWORD uk6
; /* 0x40 */
517 DWORD uk7
; /* 0x44 */
518 WORD name_len
; /* 0x48 name-length */
519 WORD class_len
; /* 0x4a class-name length */
520 char name
[1]; /* 0x4c key-name */
525 DWORD off_nk
; /* 0x00 */
526 DWORD name
; /* 0x04 */
531 WORD id
; /* 0x00 0x666c */
532 WORD nr_keys
; /* 0x06 */
533 hash_rec hash_rec
[1];
537 list of subkeys without hash
545 WORD id
; /* 0x00 0x696c */
551 this is a intermediate node
563 WORD id
; /* 0x00 0x6972 */
564 WORD nr_li
; /* 0x02 number off offsets */
565 DWORD off_li
[1]; /* 0x04 points to li */
570 WORD id
; /* 0x00 'vk' */
580 LPSTR
_strdupnA( LPCSTR str
, int len
)
584 if (!str
) return NULL
;
585 ret
= xmalloc( len
+ 1 );
586 memcpy( ret
, str
, len
);
591 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
);
592 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
);
593 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
);
600 * 0 value is a default value
601 * 1 the value has a name
604 * len of the whole data block
606 * bytes including the terminating \0 = 2*(number_of_chars+1)
607 * - reg_dword, reg_binary:
608 * if highest bit of data_len is set data_off contains the value
610 static int _nt_parse_vk(HKEY hkey
, char * base
, nt_vk
* vk
)
614 BYTE
* pdata
= (BYTE
*)(base
+vk
->data_off
+4); /* start of data */
616 if(vk
->id
!= NT_REG_VALUE_BLOCK_ID
) goto error
;
618 if (!(len
= MultiByteToWideChar( CP_ACP
, 0, vk
->name
, vk
->nam_len
, name
, 256 )) && vk
->nam_len
)
620 ERR("name too large '%.*s' (%d)\n", vk
->nam_len
, vk
->name
, vk
->nam_len
);
625 ret
= RegSetValueExW( hkey
, (vk
->flag
& 0x00000001) ? name
: NULL
, 0, vk
->type
,
626 (vk
->data_len
& 0x80000000) ? (LPBYTE
)&(vk
->data_off
): pdata
,
627 (vk
->data_len
& 0x7fffffff) );
628 if (ret
) ERR("RegSetValueEx failed (0x%08lx)\n", ret
);
631 ERR("unknown block found (0x%04x), please report!\n", vk
->id
);
638 * this structure contains the hash of a keyname and points to all
641 * exception: if the id is 'il' there are no hash values and every
644 static int _nt_parse_lf(HKEY hkey
, char * base
, int subkeys
, nt_lf
* lf
, int level
)
648 if (lf
->id
== NT_REG_HASH_BLOCK_ID
)
650 if (subkeys
!= lf
->nr_keys
) goto error1
;
652 for (i
=0; i
<lf
->nr_keys
; i
++)
654 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+lf
->hash_rec
[i
].off_nk
+4), level
)) goto error
;
657 else if (lf
->id
== NT_REG_NOHASH_BLOCK_ID
)
659 nt_li
* li
= (nt_li
*)lf
;
660 if (subkeys
!= li
->nr_keys
) goto error1
;
662 for (i
=0; i
<li
->nr_keys
; i
++)
664 if (!_nt_parse_nk(hkey
, base
, (nt_nk
*)(base
+li
->off_nk
[i
]+4), level
)) goto error
;
667 else if (lf
->id
== NT_REG_RI_BLOCK_ID
) /* ri */
669 nt_ri
* ri
= (nt_ri
*)lf
;
672 /* count all subkeys */
673 for (i
=0; i
<ri
->nr_li
; i
++)
675 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
676 if(li
->id
!= NT_REG_NOHASH_BLOCK_ID
) goto error2
;
677 li_subkeys
+= li
->nr_keys
;
681 if (subkeys
!= li_subkeys
) goto error1
;
683 /* loop through the keys */
684 for (i
=0; i
<ri
->nr_li
; i
++)
686 nt_li
* li
= (nt_li
*)(base
+ri
->off_li
[i
]+4);
687 if (!_nt_parse_lf(hkey
, base
, li
->nr_keys
, (nt_lf
*)li
, level
)) goto error
;
696 error2
: ERR("unknown node id 0x%04x, please report!\n", lf
->id
);
699 error1
: ERR("registry file corrupt! (inconsistent number of subkeys)\n");
702 error
: ERR("error reading lf block\n");
706 static int _nt_parse_nk(HKEY hkey
, char * base
, nt_nk
* nk
, int level
)
713 if(nk
->SubBlockId
!= NT_REG_KEY_BLOCK_ID
)
715 ERR("unknown node id 0x%04x, please report!\n", nk
->SubBlockId
);
719 if((nk
->Type
!=NT_REG_ROOT_KEY_BLOCK_TYPE
) &&
720 (((nt_nk
*)(base
+nk
->parent_off
+4))->SubBlockId
!= NT_REG_KEY_BLOCK_ID
))
722 ERR("registry file corrupt!\n");
726 /* create the new key */
729 name
= _strdupnA( nk
->name
, nk
->name_len
);
730 if(RegCreateKeyA( hkey
, name
, &subkey
)) { free(name
); goto error
; }
734 /* loop through the subkeys */
737 nt_lf
* lf
= (nt_lf
*)(base
+nk
->lf_off
+4);
738 if (!_nt_parse_lf(subkey
, base
, nk
->nr_subkeys
, lf
, level
-1)) goto error1
;
741 /* loop trough the value list */
742 vl
= (DWORD
*)(base
+nk
->valuelist_off
+4);
743 for (i
=0; i
<nk
->nr_values
; i
++)
745 nt_vk
* vk
= (nt_vk
*)(base
+vl
[i
]+4);
746 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
752 error1
: RegCloseKey(subkey
);
758 /* windows 95 registry loader */
760 /* SECTION 1: main header
764 #define W95_REG_CREG_ID 0x47455243
768 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
769 DWORD version
; /* ???? 0x00010000 */
770 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
771 DWORD uk2
; /* 0x0c */
772 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
778 /* SECTION 2: Directory information (tree structure)
780 * once on offset 0x20
782 * structure: [rgkn][dke]* (repeat till last_dke is reached)
784 #define W95_REG_RGKN_ID 0x4e4b4752
788 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
789 DWORD size
; /* Size of the RGKN-block */
790 DWORD root_off
; /* Rel. Offset of the root-record */
791 DWORD last_dke
; /* Offset to last DKE ? */
795 /* Disk Key Entry Structure
797 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
798 * hive itself. It looks the same like other keys. Even the ID-number can
801 * The "hash"-value is a value representing the key's name. Windows will not
802 * search for the name, but for a matching hash-value. if it finds one, it
803 * will compare the actual string info, otherwise continue with the next key.
804 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
805 * of the string which are smaller than 0x80 (128) to this D-Word.
807 * If you want to modify key names, also modify the hash-values, since they
808 * cannot be found again (although they would be displayed in REGEDIT)
809 * End of list-pointers are filled with 0xFFFFFFFF
811 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
812 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
813 * structure) and reading another RGDB_section.
815 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
816 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
817 * The remaining space between last_dke and the offset calculated from
818 * rgkn->size seems to be free for use for more dke:s.
819 * So it seems if more dke:s are added, they are added to that space and
820 * last_dke is grown, and in case that "free" space is out, the space
821 * gets grown and rgkn->size gets adjusted.
823 * there is a one to one relationship between dke and dkh
825 /* key struct, once per key */
828 DWORD x1
; /* Free entry indicator(?) */
829 DWORD hash
; /* sum of bytes of keyname */
830 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
831 DWORD prevlvl
; /* offset of previous key */
832 DWORD nextsub
; /* offset of child key */
833 DWORD next
; /* offset of sibling key */
834 WORD nrLS
; /* id inside the rgdb block */
835 WORD nrMS
; /* number of the rgdb block */
838 /* SECTION 3: key information, values and data
841 * section: [blocks]* (repeat creg->rgdb_num times)
842 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
843 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
845 * An interesting relationship exists in RGDB_section. The DWORD value
846 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
847 * I have no idea at the moment what this means. (Kevin Cozens)
850 /* block header, once per block */
851 #define W95_REG_RGDB_ID 0x42444752
855 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
856 DWORD size
; /* 0x04 */
857 DWORD uk1
; /* 0x08 */
858 DWORD uk2
; /* 0x0c */
859 DWORD uk3
; /* 0x10 */
860 DWORD uk4
; /* 0x14 */
861 DWORD uk5
; /* 0x18 */
862 DWORD uk6
; /* 0x1c */
866 /* Disk Key Header structure (RGDB part), once per key */
869 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
870 WORD nrLS
; /* 0x04 id inside the rgdb block */
871 WORD nrMS
; /* 0x06 number of the rgdb block */
872 DWORD bytesused
; /* 0x08 */
873 WORD keynamelen
; /* 0x0c len of name */
874 WORD values
; /* 0x0e number of values */
875 DWORD xx1
; /* 0x10 */
876 char name
[1]; /* 0x14 */
877 /* dkv */ /* 0x14 + keynamelen */
880 /* Disk Key Value structure, once per value */
883 DWORD type
; /* 0x00 */
885 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
886 WORD valdatalen
; /* 0x0A length of data */
887 char name
[1]; /* 0x0c */
888 /* raw data */ /* 0x0c + valnamelen */
891 /******************************************************************************
892 * _w95_lookup_dkh [Internal]
894 * seeks the dkh belonging to a dke
896 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
902 /* get the beginning of the rgdb datastore */
903 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
905 /* check: requested block < last_block) */
906 if (creg
->rgdb_num
<= nrMS
)
908 ERR("registry file corrupt! requested block no. beyond end.\n");
912 /* find the right block */
913 for(i
=0; i
<nrMS
;i
++)
915 if(rgdb
->id
!= W95_REG_RGDB_ID
) /* check the magic */
917 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
920 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
923 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
927 if(nrLS
==dkh
->nrLS
) return dkh
;
928 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
929 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
934 /******************************************************************************
935 * _w95_parse_dkv [Internal]
937 static int _w95_parse_dkv (
948 /* first value block */
949 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
951 /* loop trought the values */
952 for (i
=0; i
< dkh
->values
; i
++)
954 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
);
955 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
956 if (ret
) FIXME("RegSetValueEx returned: 0x%08lx\n", ret
);
960 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
965 /******************************************************************************
966 * _w95_parse_dke [Internal]
968 static int _w95_parse_dke(
980 /* special root key */
981 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
983 /* parse the one subkey */
984 if (dke
->nextsub
!= 0xffffffff)
986 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
988 /* has no sibling keys */
992 /* search subblock */
993 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
995 fprintf(stderr
, "dke pointing to missing dkh !\n");
1001 /* walk sibling keys */
1002 if (dke
->next
!= 0xffffffff )
1004 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1007 /* create subkey and insert values */
1008 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
);
1009 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1011 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1015 if (dke
->nextsub
!= 0xffffffff)
1017 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1021 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1024 /* end windows 95 loader */
1026 /******************************************************************************
1027 * NativeRegLoadKey [Internal]
1029 * Loads a native registry file (win95/nt)
1032 * level number of levels to cut away (eg. ".Default" in user.dat)
1034 * this function intentionally uses unix file functions to make it possible
1035 * to move it to a seperate registry helper programm
1037 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1041 DOS_FULL_NAME full_name
;
1044 char *filetype
= "unknown";
1046 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1048 /* map the registry into the memory */
1049 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1050 if ((fstat(fd
, &st
) == -1)) goto error
;
1051 if (!st
.st_size
) goto error
;
1052 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1054 switch (*(LPDWORD
)base
)
1056 /* windows 95 'CREG' */
1057 case W95_REG_CREG_ID
:
1061 _w95dke
*dke
, *root_dke
;
1064 TRACE("Loading %s registry '%s' '%s'\n", filetype
, fn
, full_name
.long_name
);
1066 /* load the header (rgkn) */
1067 rgkn
= (_w95rgkn
*)(creg
+ 1);
1068 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1070 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1073 if (rgkn
->root_off
!= 0x20)
1075 ERR("rgkn->root_off not 0x20, please report !\n");
1078 if (rgkn
->last_dke
> rgkn
->size
)
1080 ERR("registry file corrupt! last_dke > size!\n");
1083 /* verify last dke */
1084 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1085 if (dke
->x1
!= 0x80000000)
1087 ERR("last dke invalid !\n");
1090 if (rgkn
->size
> creg
->rgdb_off
)
1092 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1095 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1096 if ( (root_dke
->prevlvl
!= 0xffffffff)
1097 || (root_dke
->next
!= 0xffffffff) )
1099 ERR("registry file corrupt! invalid root dke !\n");
1103 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, root_dke
, level
);
1107 case NT_REG_HEADER_BLOCK_ID
:
1111 nt_hbin_sub
* hbin_sub
;
1115 TRACE("Loading %s registry '%s' '%s'\n", filetype
, fn
, full_name
.long_name
);
1121 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1122 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1124 ERR( "hbin block invalid\n");
1128 /* hbin_sub block */
1129 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1130 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1132 ERR( "hbin_sub block invalid\n");
1137 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1138 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1140 ERR( "special nk block not found\n");
1144 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1149 ERR("unknown registry signature !\n");
1155 ERR("error loading %s registry file %s\n",
1156 filetype
, full_name
.long_name
);
1157 if (!strcmp(filetype
, "win95"))
1158 ERR("Please report to a.mohr@mailto.de.\n");
1159 ERR("Make a backup of the file, run a good reg cleaner program and try again !\n");
1161 munmap(base
, st
.st_size
);
1166 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1168 reghack - windows 3.11 registry data format demo program.
1170 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1171 a combined hash table and tree description, and finally a text table.
1173 The header is obvious from the struct header. The taboff1 and taboff2
1174 fields are always 0x20, and their usage is unknown.
1176 The 8-byte entry table has various entry types.
1178 tabent[0] is a root index. The second word has the index of the root of
1180 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1181 the index of the key/value that has that hash. Data with the same
1182 hash value are on a circular list. The other three words in the
1183 hash entry are always zero.
1184 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1185 entry: dirent and keyent/valent. They are identified by context.
1186 tabent[freeidx] is the first free entry. The first word in a free entry
1187 is the index of the next free entry. The last has 0 as a link.
1188 The other three words in the free list are probably irrelevant.
1190 Entries in text table are preceeded by a word at offset-2. This word
1191 has the value (2*index)+1, where index is the referring keyent/valent
1192 entry in the table. I have no suggestion for the 2* and the +1.
1193 Following the word, there are N bytes of data, as per the keyent/valent
1194 entry length. The offset of the keyent/valent entry is from the start
1195 of the text table to the first data byte.
1197 This information is not available from Microsoft. The data format is
1198 deduced from the reg.dat file by me. Mistakes may
1199 have been made. I claim no rights and give no guarantees for this program.
1201 Tor Sjøwall, tor@sn.no
1204 /* reg.dat header format */
1205 struct _w31_header
{
1206 char cookie
[8]; /* 'SHCC3.10' */
1207 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1208 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1209 unsigned long tabcnt
; /* number of entries in index table */
1210 unsigned long textoff
; /* offset of text part */
1211 unsigned long textsize
; /* byte size of text part */
1212 unsigned short hashsize
; /* hash size */
1213 unsigned short freeidx
; /* free index */
1216 /* generic format of table entries */
1217 struct _w31_tabent
{
1218 unsigned short w0
, w1
, w2
, w3
;
1221 /* directory tabent: */
1222 struct _w31_dirent
{
1223 unsigned short sibling_idx
; /* table index of sibling dirent */
1224 unsigned short child_idx
; /* table index of child dirent */
1225 unsigned short key_idx
; /* table index of key keyent */
1226 unsigned short value_idx
; /* table index of value valent */
1230 struct _w31_keyent
{
1231 unsigned short hash_idx
; /* hash chain index for string */
1232 unsigned short refcnt
; /* reference count */
1233 unsigned short length
; /* length of string */
1234 unsigned short string_off
; /* offset of string in text table */
1238 struct _w31_valent
{
1239 unsigned short hash_idx
; /* hash chain index for string */
1240 unsigned short refcnt
; /* reference count */
1241 unsigned short length
; /* length of string */
1242 unsigned short string_off
; /* offset of string in text table */
1245 /* recursive helper function to display a directory tree */
1247 __w31_dumptree( unsigned short idx
,
1249 struct _w31_tabent
*tab
,
1250 struct _w31_header
*head
,
1252 time_t lastmodified
,
1255 struct _w31_dirent
*dir
;
1256 struct _w31_keyent
*key
;
1257 struct _w31_valent
*val
;
1259 static char tail
[400];
1262 dir
=(struct _w31_dirent
*)&tab
[idx
];
1265 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1267 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1268 tail
[key
->length
]='\0';
1269 /* all toplevel entries AND the entries in the
1270 * toplevel subdirectory belong to \SOFTWARE\Classes
1272 if (!level
&& !strcmp(tail
,".classes")) {
1273 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1274 idx
=dir
->sibling_idx
;
1277 if (subkey
) RegCloseKey( subkey
);
1278 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1279 /* only add if leaf node or valued node */
1280 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1281 if (dir
->value_idx
) {
1282 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1283 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1284 tail
[val
->length
]='\0';
1285 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1289 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1291 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1292 idx
=dir
->sibling_idx
;
1294 if (subkey
) RegCloseKey( subkey
);
1298 /******************************************************************************
1299 * _w31_loadreg [Internal]
1301 void _w31_loadreg(void) {
1303 struct _w31_header head
;
1304 struct _w31_tabent
*tab
;
1308 BY_HANDLE_FILE_INFORMATION hfinfo
;
1309 time_t lastmodified
;
1313 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1314 if (hf
==HFILE_ERROR
)
1317 /* read & dump header */
1318 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1319 ERR("reg.dat is too short.\n");
1323 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1324 ERR("reg.dat has bad signature.\n");
1329 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1330 /* read and dump index table */
1332 if (len
!=_lread(hf
,tab
,len
)) {
1333 ERR("couldn't read %d bytes.\n",len
);
1340 txt
= xmalloc(head
.textsize
);
1341 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1342 ERR("couldn't seek to textblock.\n");
1348 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1349 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1356 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1357 ERR("GetFileInformationByHandle failed?.\n");
1363 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1364 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1372 static void save_at_exit( HKEY hkey
, const char *path
)
1374 const char *confdir
= get_config_dir();
1375 size_t len
= strlen(confdir
) + strlen(path
) + 2;
1376 if (len
> REQUEST_MAX_VAR_SIZE
)
1378 ERR( "config dir '%s' too long\n", confdir
);
1383 struct save_registry_atexit_request
*req
= server_alloc_req( sizeof(*req
), len
);
1384 sprintf( server_data_ptr(req
), "%s/%s", confdir
, path
);
1386 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1391 /* configure save files and start the periodic saving timer */
1392 static void SHELL_InitRegistrySaving( HKEY hkey_users_default
)
1394 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1395 int period
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1397 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1400 struct set_registry_levels_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1403 req
->period
= period
* 1000;
1404 server_call( REQ_SET_REGISTRY_LEVELS
);
1408 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1410 save_at_exit( HKEY_CURRENT_USER
, SAVE_CURRENT_USER
);
1411 save_at_exit( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE
);
1412 save_at_exit( hkey_users_default
, SAVE_DEFAULT_USER
);
1417 /**********************************************************************************
1418 * SetLoadLevel [Internal]
1420 * set level to 0 for loading system files
1421 * set level to 1 for loading user files
1423 static void SetLoadLevel(int level
)
1427 struct set_registry_levels_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1429 req
->current
= level
;
1432 server_call( REQ_SET_REGISTRY_LEVELS
);
1437 /**********************************************************************************
1438 * SHELL_LoadRegistry [Internal]
1440 #define REG_DONTLOAD -1
1445 void SHELL_LoadRegistry( void )
1448 char windir
[MAX_PATHNAME_LEN
];
1449 char path
[MAX_PATHNAME_LEN
];
1450 int systemtype
= REG_WIN31
;
1451 HKEY hkey_users_default
;
1455 if (!CLIENT_IsBootThread()) return; /* already loaded */
1460 if (RegCreateKeyA(HKEY_USERS
, ".Default", &hkey_users_default
))
1461 hkey_users_default
= 0;
1463 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1465 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1467 /* test %windir%/system32/config/system --> winnt */
1468 strcpy(path
, windir
);
1469 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1470 if(GetFileAttributesA(path
) != -1)
1472 systemtype
= REG_WINNT
;
1476 /* test %windir%/system.dat --> win95 */
1477 strcpy(path
, windir
);
1478 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1479 if(GetFileAttributesA(path
) != -1)
1481 systemtype
= REG_WIN95
;
1485 if ((systemtype
==REG_WINNT
)
1486 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1488 MESSAGE("When you are running with a native NT directory specify\n");
1489 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1490 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1491 systemtype
= REG_DONTLOAD
;
1496 /* only wine registry */
1497 systemtype
= REG_DONTLOAD
;
1507 /* Load windows 95 entries */
1508 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1510 strcpy(path
, windir
);
1511 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1512 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1514 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1516 /* user specific user.dat */
1517 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1518 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1520 MESSAGE("can't load win95 user-registry %s\n", path
);
1521 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1523 /* default user.dat */
1524 if (hkey_users_default
)
1526 strcpy(path
, windir
);
1527 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1528 NativeRegLoadKey(hkey_users_default
, path
, 1);
1533 /* global user.dat */
1534 strcpy(path
, windir
);
1535 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1536 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1541 /* default user.dat */
1542 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1544 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1545 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1547 MESSAGE("can't load NT user-registry %s\n", path
);
1548 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1552 /* default user.dat */
1553 if (hkey_users_default
)
1555 strcpy(path
, windir
);
1556 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1557 NativeRegLoadKey(hkey_users_default
, path
, 1);
1562 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1565 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM", &hkey
))
1567 strcpy(path
, windir
);
1568 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1569 NativeRegLoadKey(hkey
, path
, 1);
1573 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SOFTWARE", &hkey
))
1575 strcpy(path
, windir
);
1576 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1577 NativeRegLoadKey(hkey
, path
, 1);
1581 strcpy(path
, windir
);
1582 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1583 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1585 strcpy(path
, windir
);
1586 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1587 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1589 /* this key is generated when the nt-core booted successfully */
1590 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1595 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1598 * Load the global HKU hive directly from sysconfdir
1600 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1603 * Load the global machine defaults directly from sysconfdir
1605 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1611 * Load the user saved registries
1613 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1615 const char *confdir
= get_config_dir();
1616 int len
= strlen(confdir
) + 20;
1619 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1621 * Load user's personal versions of global HKU/.Default keys
1626 strcpy( fn
, confdir
);
1627 str
= fn
+ strlen(fn
);
1630 /* try to load HKU\.Default key only */
1631 strcpy( str
, SAVE_DEFAULT_USER
);
1632 if (_wine_loadreg( hkey_users_default
, fn
))
1634 /* if not found load old file containing both HKU\.Default and HKU\user */
1635 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1636 _wine_loadreg( HKEY_USERS
, fn
);
1639 strcpy( str
, SAVE_CURRENT_USER
);
1640 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1642 strcpy( str
, SAVE_LOCAL_MACHINE
);
1643 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1645 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1648 SHELL_InitRegistrySaving( hkey_users_default
);
1649 RegCloseKey( hkey_users_default
);
1652 /********************* API FUNCTIONS ***************************************/
1657 /******************************************************************************
1658 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1659 * Immediately writes key to registry.
1660 * Only returns after data has been written to disk.
1662 * FIXME: does it really wait until data is written ?
1665 * hkey [I] Handle of key to write
1668 * Success: ERROR_SUCCESS
1669 * Failure: Error code
1671 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1673 FIXME( "(%x): stub\n", hkey
);
1674 return ERROR_SUCCESS
;
1677 /******************************************************************************
1678 * RegConnectRegistryW [ADVAPI32.128]
1681 * lpMachineName [I] Address of name of remote computer
1682 * hHey [I] Predefined registry handle
1683 * phkResult [I] Address of buffer for remote registry handle
1685 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1688 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1690 if (!lpMachineName
|| !*lpMachineName
) {
1691 /* Use the local machine name */
1692 return RegOpenKey16( hKey
, "", phkResult
);
1695 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1696 return ERROR_BAD_NETPATH
;
1700 /******************************************************************************
1701 * RegConnectRegistryA [ADVAPI32.127]
1703 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1705 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1706 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1707 HeapFree( GetProcessHeap(), 0, machineW
);
1712 /******************************************************************************
1713 * RegGetKeySecurity [ADVAPI32.144]
1714 * Retrieves a copy of security descriptor protecting the registry key
1717 * hkey [I] Open handle of key to set
1718 * SecurityInformation [I] Descriptor contents
1719 * pSecurityDescriptor [O] Address of descriptor for key
1720 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1723 * Success: ERROR_SUCCESS
1724 * Failure: Error code
1726 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1727 SECURITY_INFORMATION SecurityInformation
,
1728 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1729 LPDWORD lpcbSecurityDescriptor
)
1731 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1732 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1734 /* FIXME: Check for valid SecurityInformation values */
1736 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1737 return ERROR_INSUFFICIENT_BUFFER
;
1739 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1740 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1742 return ERROR_SUCCESS
;
1746 /******************************************************************************
1747 * RegNotifyChangeKeyValue [ADVAPI32.???]
1750 * hkey [I] Handle of key to watch
1751 * fWatchSubTree [I] Flag for subkey notification
1752 * fdwNotifyFilter [I] Changes to be reported
1753 * hEvent [I] Handle of signaled event
1754 * fAsync [I] Flag for asynchronous reporting
1756 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1757 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1760 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1762 return ERROR_SUCCESS
;
1766 /******************************************************************************
1767 * RegUnLoadKeyW [ADVAPI32.173]
1770 * hkey [I] Handle of open key
1771 * lpSubKey [I] Address of name of subkey to unload
1773 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1775 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1776 return ERROR_SUCCESS
;
1780 /******************************************************************************
1781 * RegUnLoadKeyA [ADVAPI32.172]
1783 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1785 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1786 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1787 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1792 /******************************************************************************
1793 * RegSetKeySecurity [ADVAPI32.167]
1796 * hkey [I] Open handle of key to set
1797 * SecurityInfo [I] Descriptor contents
1798 * pSecurityDesc [I] Address of descriptor for key
1800 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1801 PSECURITY_DESCRIPTOR pSecurityDesc
)
1803 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1805 /* It seems to perform this check before the hkey check */
1806 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1807 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1808 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1809 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1812 return ERROR_INVALID_PARAMETER
;
1815 return ERROR_INVALID_PARAMETER
;
1817 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1819 return ERROR_SUCCESS
;
1823 /******************************************************************************
1824 * RegRestoreKeyW [ADVAPI32.164]
1827 * hkey [I] Handle of key where restore begins
1828 * lpFile [I] Address of filename containing saved tree
1829 * dwFlags [I] Optional flags
1831 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1833 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1835 /* It seems to do this check before the hkey check */
1836 if (!lpFile
|| !*lpFile
)
1837 return ERROR_INVALID_PARAMETER
;
1839 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1841 /* Check for file existence */
1843 return ERROR_SUCCESS
;
1847 /******************************************************************************
1848 * RegRestoreKeyA [ADVAPI32.163]
1850 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1852 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1853 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1854 HeapFree( GetProcessHeap(), 0, lpFileW
);
1859 /******************************************************************************
1860 * RegReplaceKeyW [ADVAPI32.162]
1863 * hkey [I] Handle of open key
1864 * lpSubKey [I] Address of name of subkey
1865 * lpNewFile [I] Address of filename for file with new data
1866 * lpOldFile [I] Address of filename for backup file
1868 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1871 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1872 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1873 return ERROR_SUCCESS
;
1877 /******************************************************************************
1878 * RegReplaceKeyA [ADVAPI32.161]
1880 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1883 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1884 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1885 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1886 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1887 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1888 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1889 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1898 /* 16-bit functions */
1900 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1901 * some programs. Do not remove those cases. -MM
1903 static inline void fix_win16_hkey( HKEY
*hkey
)
1905 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1908 /******************************************************************************
1909 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1911 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1913 fix_win16_hkey( &hkey
);
1914 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1917 /******************************************************************************
1918 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1920 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1922 fix_win16_hkey( &hkey
);
1923 return RegOpenKeyA( hkey
, name
, retkey
);
1926 /******************************************************************************
1927 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1929 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1931 fix_win16_hkey( &hkey
);
1932 return RegCreateKeyA( hkey
, name
, retkey
);
1935 /******************************************************************************
1936 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1938 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1940 fix_win16_hkey( &hkey
);
1941 return RegDeleteKeyA( hkey
, name
);
1944 /******************************************************************************
1945 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1947 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1949 fix_win16_hkey( &hkey
);
1950 return RegCloseKey( hkey
);
1953 /******************************************************************************
1954 * RegSetValue16 [KERNEL.221] [SHELL.5]
1956 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1958 fix_win16_hkey( &hkey
);
1959 return RegSetValueA( hkey
, name
, type
, data
, count
);
1962 /******************************************************************************
1963 * RegDeleteValue16 [KERNEL.222]
1965 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1967 fix_win16_hkey( &hkey
);
1968 return RegDeleteValueA( hkey
, name
);
1971 /******************************************************************************
1972 * RegEnumValue16 [KERNEL.223]
1974 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1975 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1977 fix_win16_hkey( &hkey
);
1978 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1981 /******************************************************************************
1982 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1985 * Is this HACK still applicable?
1988 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1989 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1992 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1994 fix_win16_hkey( &hkey
);
1995 if (count
) *count
&= 0xffff;
1996 return RegQueryValueA( hkey
, name
, data
, count
);
1999 /******************************************************************************
2000 * RegQueryValueEx16 [KERNEL.225]
2002 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
2003 LPBYTE data
, LPDWORD count
)
2005 fix_win16_hkey( &hkey
);
2006 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
2009 /******************************************************************************
2010 * RegSetValueEx16 [KERNEL.226]
2012 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
2013 CONST BYTE
*data
, DWORD count
)
2015 fix_win16_hkey( &hkey
);
2016 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);