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 (n
=0; n
<nk
->nr_values
; n
++)
745 nt_vk
* vk
= (nt_vk
*)(base
+vl
[n
]+4);
746 if (!_nt_parse_vk(subkey
, base
, vk
)) goto error1
;
749 /* Don't close the subkey if it is the hkey that was passed
750 * (i.e. Level was <= 0)
752 if( subkey
!=hkey
) RegCloseKey(subkey
);
755 error1
: RegCloseKey(subkey
);
761 /* windows 95 registry loader */
763 /* SECTION 1: main header
767 #define W95_REG_CREG_ID 0x47455243
771 DWORD id
; /* "CREG" = W95_REG_CREG_ID */
772 DWORD version
; /* ???? 0x00010000 */
773 DWORD rgdb_off
; /* 0x08 Offset of 1st RGDB-block */
774 DWORD uk2
; /* 0x0c */
775 WORD rgdb_num
; /* 0x10 # of RGDB-blocks */
781 /* SECTION 2: Directory information (tree structure)
783 * once on offset 0x20
785 * structure: [rgkn][dke]* (repeat till last_dke is reached)
787 #define W95_REG_RGKN_ID 0x4e4b4752
791 DWORD id
; /*"RGKN" = W95_REG_RGKN_ID */
792 DWORD size
; /* Size of the RGKN-block */
793 DWORD root_off
; /* Rel. Offset of the root-record */
794 DWORD last_dke
; /* Offset to last DKE ? */
798 /* Disk Key Entry Structure
800 * the 1st entry in a "usual" registry file is a nul-entry with subkeys: the
801 * hive itself. It looks the same like other keys. Even the ID-number can
804 * The "hash"-value is a value representing the key's name. Windows will not
805 * search for the name, but for a matching hash-value. if it finds one, it
806 * will compare the actual string info, otherwise continue with the next key.
807 * To calculate the hash initialize a D-Word with 0 and add all ASCII-values
808 * of the string which are smaller than 0x80 (128) to this D-Word.
810 * If you want to modify key names, also modify the hash-values, since they
811 * cannot be found again (although they would be displayed in REGEDIT)
812 * End of list-pointers are filled with 0xFFFFFFFF
814 * Disk keys are layed out flat ... But, sometimes, nrLS and nrMS are both
815 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
816 * structure) and reading another RGDB_section.
818 * The last DKE (see field last_dke in _w95_rgkn) has only 3 DWORDs with
819 * 0x80000000 (EOL indicator ?) as x1, the hash value and 0xFFFFFFFF as x3.
820 * The remaining space between last_dke and the offset calculated from
821 * rgkn->size seems to be free for use for more dke:s.
822 * So it seems if more dke:s are added, they are added to that space and
823 * last_dke is grown, and in case that "free" space is out, the space
824 * gets grown and rgkn->size gets adjusted.
826 * there is a one to one relationship between dke and dkh
828 /* key struct, once per key */
831 DWORD x1
; /* Free entry indicator(?) */
832 DWORD hash
; /* sum of bytes of keyname */
833 DWORD x3
; /* Root key indicator? usually 0xFFFFFFFF */
834 DWORD prevlvl
; /* offset of previous key */
835 DWORD nextsub
; /* offset of child key */
836 DWORD next
; /* offset of sibling key */
837 WORD nrLS
; /* id inside the rgdb block */
838 WORD nrMS
; /* number of the rgdb block */
841 /* SECTION 3: key information, values and data
844 * section: [blocks]* (repeat creg->rgdb_num times)
845 * blocks: [rgdb] [subblocks]* (repeat till block size reached )
846 * subblocks: [dkh] [dkv]* (repeat dkh->values times )
848 * An interesting relationship exists in RGDB_section. The DWORD value
849 * at offset 0x10 equals the one at offset 0x04 minus the one at offset 0x08.
850 * I have no idea at the moment what this means. (Kevin Cozens)
853 /* block header, once per block */
854 #define W95_REG_RGDB_ID 0x42444752
858 DWORD id
; /* 0x00 'RGDB' = W95_REG_RGDB_ID */
859 DWORD size
; /* 0x04 */
860 DWORD uk1
; /* 0x08 */
861 DWORD uk2
; /* 0x0c */
862 DWORD uk3
; /* 0x10 */
863 DWORD uk4
; /* 0x14 */
864 DWORD uk5
; /* 0x18 */
865 DWORD uk6
; /* 0x1c */
869 /* Disk Key Header structure (RGDB part), once per key */
872 DWORD nextkeyoff
; /* 0x00 offset to next dkh */
873 WORD nrLS
; /* 0x04 id inside the rgdb block */
874 WORD nrMS
; /* 0x06 number of the rgdb block */
875 DWORD bytesused
; /* 0x08 */
876 WORD keynamelen
; /* 0x0c len of name */
877 WORD values
; /* 0x0e number of values */
878 DWORD xx1
; /* 0x10 */
879 char name
[1]; /* 0x14 */
880 /* dkv */ /* 0x14 + keynamelen */
883 /* Disk Key Value structure, once per value */
886 DWORD type
; /* 0x00 */
888 WORD valnamelen
; /* 0x08 length of name, 0 is default key */
889 WORD valdatalen
; /* 0x0A length of data */
890 char name
[1]; /* 0x0c */
891 /* raw data */ /* 0x0c + valnamelen */
894 /******************************************************************************
895 * _w95_lookup_dkh [Internal]
897 * seeks the dkh belonging to a dke
899 static _w95dkh
* _w95_lookup_dkh (_w95creg
*creg
, int nrLS
, int nrMS
)
905 /* get the beginning of the rgdb datastore */
906 rgdb
= (_w95rgdb
*)((char*)creg
+creg
->rgdb_off
);
908 /* check: requested block < last_block) */
909 if (creg
->rgdb_num
<= nrMS
)
911 ERR("registry file corrupt! requested block no. beyond end.\n");
915 /* find the right block */
916 for(i
=0; i
<nrMS
;i
++)
918 if(rgdb
->id
!= W95_REG_RGDB_ID
) /* check the magic */
920 ERR("registry file corrupt! bad magic 0x%08lx\n", rgdb
->id
);
923 rgdb
= (_w95rgdb
*) ((char*)rgdb
+rgdb
->size
); /* find next block */
926 dkh
= (_w95dkh
*)(rgdb
+ 1); /* first sub block within the rgdb */
930 if(nrLS
==dkh
->nrLS
) return dkh
;
931 dkh
= (_w95dkh
*)((char*)dkh
+ dkh
->nextkeyoff
); /* find next subblock */
932 } while ((char *)dkh
< ((char*)rgdb
+rgdb
->size
));
937 /******************************************************************************
938 * _w95_parse_dkv [Internal]
940 static int _w95_parse_dkv (
951 /* first value block */
952 dkv
= (_w95dkv
*)((char*)dkh
+dkh
->keynamelen
+0x14);
954 /* loop trought the values */
955 for (i
=0; i
< dkh
->values
; i
++)
957 name
= _strdupnA(dkv
->name
, dkv
->valnamelen
);
958 ret
= RegSetValueExA(hkey
, name
, 0, dkv
->type
, &(dkv
->name
[dkv
->valnamelen
]),dkv
->valdatalen
);
959 if (ret
) FIXME("RegSetValueEx returned: 0x%08lx\n", ret
);
963 dkv
= (_w95dkv
*)((char*)dkv
+dkv
->valnamelen
+dkv
->valdatalen
+0x0c);
968 /******************************************************************************
969 * _w95_parse_dke [Internal]
971 static int _w95_parse_dke(
983 /* special root key */
984 if (dke
->nrLS
== 0xffff || dke
->nrMS
==0xffff) /* eg. the root key has no name */
986 /* parse the one subkey */
987 if (dke
->nextsub
!= 0xffffffff)
989 return _w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
);
991 /* has no sibling keys */
995 /* search subblock */
996 if (!(dkh
= _w95_lookup_dkh(creg
, dke
->nrLS
, dke
->nrMS
)))
998 fprintf(stderr
, "dke pointing to missing dkh !\n");
1004 /* walk sibling keys */
1005 if (dke
->next
!= 0xffffffff )
1007 if (!_w95_parse_dke(hkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->next
), level
)) goto error
;
1010 /* create subkey and insert values */
1011 name
= _strdupnA( dkh
->name
, dkh
->keynamelen
);
1012 if (RegCreateKeyA(hkey
, name
, &hsubkey
)) { free(name
); goto error
; }
1014 if (!_w95_parse_dkv(hsubkey
, dkh
, dke
->nrLS
, dke
->nrMS
)) goto error1
;
1018 if (dke
->nextsub
!= 0xffffffff)
1020 if (!_w95_parse_dke(hsubkey
, creg
, rgkn
, (_w95dke
*)((char*)rgkn
+dke
->nextsub
), level
-1)) goto error1
;
1024 error1
: if (hsubkey
!= hkey
) RegCloseKey(hsubkey
);
1027 /* end windows 95 loader */
1029 /******************************************************************************
1030 * NativeRegLoadKey [Internal]
1032 * Loads a native registry file (win95/nt)
1035 * level number of levels to cut away (eg. ".Default" in user.dat)
1037 * this function intentionally uses unix file functions to make it possible
1038 * to move it to a seperate registry helper programm
1040 static int NativeRegLoadKey( HKEY hkey
, char* fn
, int level
)
1044 DOS_FULL_NAME full_name
;
1047 char *filetype
= "unknown";
1049 if (!DOSFS_GetFullName( fn
, 0, &full_name
)) return FALSE
;
1051 /* map the registry into the memory */
1052 if ((fd
= open(full_name
.long_name
, O_RDONLY
| O_NONBLOCK
)) == -1) return FALSE
;
1053 if ((fstat(fd
, &st
) == -1)) goto error
;
1054 if (!st
.st_size
) goto error
;
1055 if ((base
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) == MAP_FAILED
) goto error
;
1057 switch (*(LPDWORD
)base
)
1059 /* windows 95 'CREG' */
1060 case W95_REG_CREG_ID
:
1064 _w95dke
*dke
, *root_dke
;
1067 TRACE("Loading %s registry '%s' '%s'\n", filetype
, fn
, full_name
.long_name
);
1069 /* load the header (rgkn) */
1070 rgkn
= (_w95rgkn
*)(creg
+ 1);
1071 if (rgkn
->id
!= W95_REG_RGKN_ID
)
1073 ERR("second IFF header not RGKN, but %lx\n", rgkn
->id
);
1076 if (rgkn
->root_off
!= 0x20)
1078 ERR("rgkn->root_off not 0x20, please report !\n");
1081 if (rgkn
->last_dke
> rgkn
->size
)
1083 ERR("registry file corrupt! last_dke > size!\n");
1086 /* verify last dke */
1087 dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->last_dke
);
1088 if (dke
->x1
!= 0x80000000)
1090 ERR("last dke invalid !\n");
1093 if (rgkn
->size
> creg
->rgdb_off
)
1095 ERR("registry file corrupt! rgkn size > rgdb_off !\n");
1098 root_dke
= (_w95dke
*)((char*)rgkn
+ rgkn
->root_off
);
1099 if ( (root_dke
->prevlvl
!= 0xffffffff)
1100 || (root_dke
->next
!= 0xffffffff) )
1102 ERR("registry file corrupt! invalid root dke !\n");
1106 ret
= _w95_parse_dke(hkey
, creg
, rgkn
, root_dke
, level
);
1110 case NT_REG_HEADER_BLOCK_ID
:
1114 nt_hbin_sub
* hbin_sub
;
1118 TRACE("Loading %s registry '%s' '%s'\n", filetype
, fn
, full_name
.long_name
);
1124 hbin
= (nt_hbin
*)((char*) base
+ 0x1000);
1125 if (hbin
->id
!= NT_REG_POOL_BLOCK_ID
)
1127 ERR( "hbin block invalid\n");
1131 /* hbin_sub block */
1132 hbin_sub
= (nt_hbin_sub
*)&(hbin
->hbin_sub
);
1133 if ((hbin_sub
->data
[0] != 'n') || (hbin_sub
->data
[1] != 'k'))
1135 ERR( "hbin_sub block invalid\n");
1140 nk
= (nt_nk
*)&(hbin_sub
->data
[0]);
1141 if (nk
->Type
!= NT_REG_ROOT_KEY_BLOCK_TYPE
)
1143 ERR( "special nk block not found\n");
1147 ret
= _nt_parse_nk (hkey
, (char *) base
+ 0x1000, nk
, level
);
1152 ERR("unknown registry signature !\n");
1158 ERR("error loading %s registry file %s\n",
1159 filetype
, full_name
.long_name
);
1160 if (!strcmp(filetype
, "win95"))
1161 ERR("Please report to a.mohr@mailto.de.\n");
1162 ERR("Make a backup of the file, run a good reg cleaner program and try again !\n");
1164 munmap(base
, st
.st_size
);
1169 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1171 reghack - windows 3.11 registry data format demo program.
1173 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1174 a combined hash table and tree description, and finally a text table.
1176 The header is obvious from the struct header. The taboff1 and taboff2
1177 fields are always 0x20, and their usage is unknown.
1179 The 8-byte entry table has various entry types.
1181 tabent[0] is a root index. The second word has the index of the root of
1183 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1184 the index of the key/value that has that hash. Data with the same
1185 hash value are on a circular list. The other three words in the
1186 hash entry are always zero.
1187 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1188 entry: dirent and keyent/valent. They are identified by context.
1189 tabent[freeidx] is the first free entry. The first word in a free entry
1190 is the index of the next free entry. The last has 0 as a link.
1191 The other three words in the free list are probably irrelevant.
1193 Entries in text table are preceeded by a word at offset-2. This word
1194 has the value (2*index)+1, where index is the referring keyent/valent
1195 entry in the table. I have no suggestion for the 2* and the +1.
1196 Following the word, there are N bytes of data, as per the keyent/valent
1197 entry length. The offset of the keyent/valent entry is from the start
1198 of the text table to the first data byte.
1200 This information is not available from Microsoft. The data format is
1201 deduced from the reg.dat file by me. Mistakes may
1202 have been made. I claim no rights and give no guarantees for this program.
1204 Tor Sjøwall, tor@sn.no
1207 /* reg.dat header format */
1208 struct _w31_header
{
1209 char cookie
[8]; /* 'SHCC3.10' */
1210 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1211 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1212 unsigned long tabcnt
; /* number of entries in index table */
1213 unsigned long textoff
; /* offset of text part */
1214 unsigned long textsize
; /* byte size of text part */
1215 unsigned short hashsize
; /* hash size */
1216 unsigned short freeidx
; /* free index */
1219 /* generic format of table entries */
1220 struct _w31_tabent
{
1221 unsigned short w0
, w1
, w2
, w3
;
1224 /* directory tabent: */
1225 struct _w31_dirent
{
1226 unsigned short sibling_idx
; /* table index of sibling dirent */
1227 unsigned short child_idx
; /* table index of child dirent */
1228 unsigned short key_idx
; /* table index of key keyent */
1229 unsigned short value_idx
; /* table index of value valent */
1233 struct _w31_keyent
{
1234 unsigned short hash_idx
; /* hash chain index for string */
1235 unsigned short refcnt
; /* reference count */
1236 unsigned short length
; /* length of string */
1237 unsigned short string_off
; /* offset of string in text table */
1241 struct _w31_valent
{
1242 unsigned short hash_idx
; /* hash chain index for string */
1243 unsigned short refcnt
; /* reference count */
1244 unsigned short length
; /* length of string */
1245 unsigned short string_off
; /* offset of string in text table */
1248 /* recursive helper function to display a directory tree */
1250 __w31_dumptree( unsigned short idx
,
1252 struct _w31_tabent
*tab
,
1253 struct _w31_header
*head
,
1255 time_t lastmodified
,
1258 struct _w31_dirent
*dir
;
1259 struct _w31_keyent
*key
;
1260 struct _w31_valent
*val
;
1262 static char tail
[400];
1265 dir
=(struct _w31_dirent
*)&tab
[idx
];
1268 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1270 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1271 tail
[key
->length
]='\0';
1272 /* all toplevel entries AND the entries in the
1273 * toplevel subdirectory belong to \SOFTWARE\Classes
1275 if (!level
&& !strcmp(tail
,".classes")) {
1276 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1277 idx
=dir
->sibling_idx
;
1280 if (subkey
) RegCloseKey( subkey
);
1281 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1282 /* only add if leaf node or valued node */
1283 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1284 if (dir
->value_idx
) {
1285 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1286 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1287 tail
[val
->length
]='\0';
1288 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1292 TRACE("strange: no directory key name, idx=%04x\n", idx
);
1294 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1295 idx
=dir
->sibling_idx
;
1297 if (subkey
) RegCloseKey( subkey
);
1301 /******************************************************************************
1302 * _w31_loadreg [Internal]
1304 void _w31_loadreg(void) {
1306 struct _w31_header head
;
1307 struct _w31_tabent
*tab
;
1311 BY_HANDLE_FILE_INFORMATION hfinfo
;
1312 time_t lastmodified
;
1316 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1317 if (hf
==HFILE_ERROR
)
1320 /* read & dump header */
1321 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1322 ERR("reg.dat is too short.\n");
1326 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1327 ERR("reg.dat has bad signature.\n");
1332 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1333 /* read and dump index table */
1335 if (len
!=_lread(hf
,tab
,len
)) {
1336 ERR("couldn't read %d bytes.\n",len
);
1343 txt
= xmalloc(head
.textsize
);
1344 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1345 ERR("couldn't seek to textblock.\n");
1351 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1352 ERR("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1359 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1360 ERR("GetFileInformationByHandle failed?.\n");
1366 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1367 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1375 static void save_at_exit( HKEY hkey
, const char *path
)
1377 const char *confdir
= get_config_dir();
1378 size_t len
= strlen(confdir
) + strlen(path
) + 2;
1379 if (len
> REQUEST_MAX_VAR_SIZE
)
1381 ERR( "config dir '%s' too long\n", confdir
);
1386 struct save_registry_atexit_request
*req
= server_alloc_req( sizeof(*req
), len
);
1387 sprintf( server_data_ptr(req
), "%s/%s", confdir
, path
);
1389 server_call( REQ_SAVE_REGISTRY_ATEXIT
);
1394 /* configure save files and start the periodic saving timer */
1395 static void SHELL_InitRegistrySaving( HKEY hkey_users_default
)
1397 int all
= PROFILE_GetWineIniBool( "registry", "SaveOnlyUpdatedKeys", 1 );
1398 int period
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 );
1400 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
1403 struct set_registry_levels_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1406 req
->period
= period
* 1000;
1407 server_call( REQ_SET_REGISTRY_LEVELS
);
1411 if (PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1))
1413 save_at_exit( HKEY_CURRENT_USER
, SAVE_CURRENT_USER
);
1414 save_at_exit( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE
);
1415 save_at_exit( hkey_users_default
, SAVE_DEFAULT_USER
);
1420 /**********************************************************************************
1421 * SetLoadLevel [Internal]
1423 * set level to 0 for loading system files
1424 * set level to 1 for loading user files
1426 static void SetLoadLevel(int level
)
1430 struct set_registry_levels_request
*req
= server_alloc_req( sizeof(*req
), 0 );
1432 req
->current
= level
;
1435 server_call( REQ_SET_REGISTRY_LEVELS
);
1440 /**********************************************************************************
1441 * SHELL_LoadRegistry [Internal]
1443 #define REG_DONTLOAD -1
1448 void SHELL_LoadRegistry( void )
1451 char windir
[MAX_PATHNAME_LEN
];
1452 char path
[MAX_PATHNAME_LEN
];
1453 int systemtype
= REG_WIN31
;
1454 HKEY hkey_users_default
;
1458 if (!CLIENT_IsBootThread()) return; /* already loaded */
1463 if (RegCreateKeyA(HKEY_USERS
, ".Default", &hkey_users_default
))
1464 hkey_users_default
= 0;
1466 GetWindowsDirectoryA( windir
, MAX_PATHNAME_LEN
);
1468 if (PROFILE_GetWineIniBool( "Registry", "LoadWindowsRegistryFiles", 1))
1470 /* test %windir%/system32/config/system --> winnt */
1471 strcpy(path
, windir
);
1472 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1473 if(GetFileAttributesA(path
) != (DWORD
)-1)
1475 systemtype
= REG_WINNT
;
1479 /* test %windir%/system.dat --> win95 */
1480 strcpy(path
, windir
);
1481 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1482 if(GetFileAttributesA(path
) != (DWORD
)-1)
1484 systemtype
= REG_WIN95
;
1488 if ((systemtype
==REG_WINNT
)
1489 && (! PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
)))
1491 MESSAGE("When you are running with a native NT directory specify\n");
1492 MESSAGE("'Profile=<profiledirectory>' or disable loading of Windows\n");
1493 MESSAGE("registry (LoadWindowsRegistryFiles=N)\n");
1494 systemtype
= REG_DONTLOAD
;
1499 /* only wine registry */
1500 systemtype
= REG_DONTLOAD
;
1510 /* Load windows 95 entries */
1511 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, "C:\\system.1st", 0);
1513 strcpy(path
, windir
);
1514 strncat(path
, "\\system.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1515 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1517 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1519 /* user specific user.dat */
1520 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1521 if (!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1523 MESSAGE("can't load win95 user-registry %s\n", path
);
1524 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1526 /* default user.dat */
1527 if (hkey_users_default
)
1529 strcpy(path
, windir
);
1530 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1531 NativeRegLoadKey(hkey_users_default
, path
, 1);
1536 /* global user.dat */
1537 strcpy(path
, windir
);
1538 strncat(path
, "\\user.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1539 NativeRegLoadKey(HKEY_CURRENT_USER
, path
, 1);
1544 /* default user.dat */
1545 if (PROFILE_GetWineIniString( "Wine", "Profile", "", path
, MAX_PATHNAME_LEN
))
1547 strncat(path
, "\\ntuser.dat", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1548 if(!NativeRegLoadKey( HKEY_CURRENT_USER
, path
, 1 ))
1550 MESSAGE("can't load NT user-registry %s\n", path
);
1551 MESSAGE("check wine.conf, section [Wine], value 'Profile'\n");
1555 /* default user.dat */
1556 if (hkey_users_default
)
1558 strcpy(path
, windir
);
1559 strncat(path
, "\\system32\\config\\default", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1560 NativeRegLoadKey(hkey_users_default
, path
, 1);
1565 * map HLM\System\ControlSet001 to HLM\System\CurrentControlSet
1568 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SYSTEM", &hkey
))
1570 strcpy(path
, windir
);
1571 strncat(path
, "\\system32\\config\\system", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1572 NativeRegLoadKey(hkey
, path
, 1);
1576 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
, "SOFTWARE", &hkey
))
1578 strcpy(path
, windir
);
1579 strncat(path
, "\\system32\\config\\software", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1580 NativeRegLoadKey(hkey
, path
, 1);
1584 strcpy(path
, windir
);
1585 strncat(path
, "\\system32\\config\\sam", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1586 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1588 strcpy(path
, windir
);
1589 strncat(path
, "\\system32\\config\\security", MAX_PATHNAME_LEN
- strlen(path
) - 1);
1590 NativeRegLoadKey(HKEY_LOCAL_MACHINE
, path
, 0);
1592 /* this key is generated when the nt-core booted successfully */
1593 if (!RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\Clone",&hkey
))
1598 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1601 * Load the global HKU hive directly from sysconfdir
1603 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1606 * Load the global machine defaults directly from sysconfdir
1608 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1614 * Load the user saved registries
1616 if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1618 const char *confdir
= get_config_dir();
1619 unsigned int len
= strlen(confdir
) + 20;
1622 if (len
> sizeof(path
)) fn
= HeapAlloc( GetProcessHeap(), 0, len
);
1624 * Load user's personal versions of global HKU/.Default keys
1629 strcpy( fn
, confdir
);
1630 str
= fn
+ strlen(fn
);
1633 /* try to load HKU\.Default key only */
1634 strcpy( str
, SAVE_DEFAULT_USER
);
1635 if (_wine_loadreg( hkey_users_default
, fn
))
1637 /* if not found load old file containing both HKU\.Default and HKU\user */
1638 strcpy( str
, SAVE_LOCAL_USERS_DEFAULT
);
1639 _wine_loadreg( HKEY_USERS
, fn
);
1642 strcpy( str
, SAVE_CURRENT_USER
);
1643 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1645 strcpy( str
, SAVE_LOCAL_MACHINE
);
1646 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1648 if (fn
!= path
) HeapFree( GetProcessHeap(), 0, fn
);
1651 SHELL_InitRegistrySaving( hkey_users_default
);
1652 RegCloseKey( hkey_users_default
);
1655 /********************* API FUNCTIONS ***************************************/
1660 /******************************************************************************
1661 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1662 * Immediately writes key to registry.
1663 * Only returns after data has been written to disk.
1665 * FIXME: does it really wait until data is written ?
1668 * hkey [I] Handle of key to write
1671 * Success: ERROR_SUCCESS
1672 * Failure: Error code
1674 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1676 FIXME( "(%x): stub\n", hkey
);
1677 return ERROR_SUCCESS
;
1680 /******************************************************************************
1681 * RegConnectRegistryW [ADVAPI32.128]
1684 * lpMachineName [I] Address of name of remote computer
1685 * hHey [I] Predefined registry handle
1686 * phkResult [I] Address of buffer for remote registry handle
1688 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1691 TRACE("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1693 if (!lpMachineName
|| !*lpMachineName
) {
1694 /* Use the local machine name */
1695 return RegOpenKey16( hKey
, "", phkResult
);
1698 FIXME("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1699 return ERROR_BAD_NETPATH
;
1703 /******************************************************************************
1704 * RegConnectRegistryA [ADVAPI32.127]
1706 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1708 LPWSTR machineW
= HEAP_strdupAtoW( GetProcessHeap(), 0, machine
);
1709 DWORD ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1710 HeapFree( GetProcessHeap(), 0, machineW
);
1715 /******************************************************************************
1716 * RegGetKeySecurity [ADVAPI32.144]
1717 * Retrieves a copy of security descriptor protecting the registry key
1720 * hkey [I] Open handle of key to set
1721 * SecurityInformation [I] Descriptor contents
1722 * pSecurityDescriptor [O] Address of descriptor for key
1723 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1726 * Success: ERROR_SUCCESS
1727 * Failure: Error code
1729 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1730 SECURITY_INFORMATION SecurityInformation
,
1731 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1732 LPDWORD lpcbSecurityDescriptor
)
1734 TRACE("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1735 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1737 /* FIXME: Check for valid SecurityInformation values */
1739 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1740 return ERROR_INSUFFICIENT_BUFFER
;
1742 FIXME("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1743 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1745 return ERROR_SUCCESS
;
1749 /******************************************************************************
1750 * RegNotifyChangeKeyValue [ADVAPI32.???]
1753 * hkey [I] Handle of key to watch
1754 * fWatchSubTree [I] Flag for subkey notification
1755 * fdwNotifyFilter [I] Changes to be reported
1756 * hEvent [I] Handle of signaled event
1757 * fAsync [I] Flag for asynchronous reporting
1759 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1760 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1763 FIXME("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1765 return ERROR_SUCCESS
;
1769 /******************************************************************************
1770 * RegUnLoadKeyW [ADVAPI32.173]
1773 * hkey [I] Handle of open key
1774 * lpSubKey [I] Address of name of subkey to unload
1776 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1778 FIXME("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1779 return ERROR_SUCCESS
;
1783 /******************************************************************************
1784 * RegUnLoadKeyA [ADVAPI32.172]
1786 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1788 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1789 LONG ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1790 if(lpSubKeyW
) HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1795 /******************************************************************************
1796 * RegSetKeySecurity [ADVAPI32.167]
1799 * hkey [I] Open handle of key to set
1800 * SecurityInfo [I] Descriptor contents
1801 * pSecurityDesc [I] Address of descriptor for key
1803 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1804 PSECURITY_DESCRIPTOR pSecurityDesc
)
1806 TRACE("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1808 /* It seems to perform this check before the hkey check */
1809 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1810 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1811 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1812 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1815 return ERROR_INVALID_PARAMETER
;
1818 return ERROR_INVALID_PARAMETER
;
1820 FIXME(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1822 return ERROR_SUCCESS
;
1826 /******************************************************************************
1827 * RegRestoreKeyW [ADVAPI32.164]
1830 * hkey [I] Handle of key where restore begins
1831 * lpFile [I] Address of filename containing saved tree
1832 * dwFlags [I] Optional flags
1834 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1836 TRACE("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1838 /* It seems to do this check before the hkey check */
1839 if (!lpFile
|| !*lpFile
)
1840 return ERROR_INVALID_PARAMETER
;
1842 FIXME("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1844 /* Check for file existence */
1846 return ERROR_SUCCESS
;
1850 /******************************************************************************
1851 * RegRestoreKeyA [ADVAPI32.163]
1853 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1855 LPWSTR lpFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpFile
);
1856 LONG ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1857 HeapFree( GetProcessHeap(), 0, lpFileW
);
1862 /******************************************************************************
1863 * RegReplaceKeyW [ADVAPI32.162]
1866 * hkey [I] Handle of open key
1867 * lpSubKey [I] Address of name of subkey
1868 * lpNewFile [I] Address of filename for file with new data
1869 * lpOldFile [I] Address of filename for backup file
1871 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1874 FIXME("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1875 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1876 return ERROR_SUCCESS
;
1880 /******************************************************************************
1881 * RegReplaceKeyA [ADVAPI32.161]
1883 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1886 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
1887 LPWSTR lpNewFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpNewFile
);
1888 LPWSTR lpOldFileW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpOldFile
);
1889 LONG ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1890 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
1891 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
1892 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
1901 /* 16-bit functions */
1903 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1904 * some programs. Do not remove those cases. -MM
1906 static inline void fix_win16_hkey( HKEY
*hkey
)
1908 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1911 /******************************************************************************
1912 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1914 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1916 fix_win16_hkey( &hkey
);
1917 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1920 /******************************************************************************
1921 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1923 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1925 fix_win16_hkey( &hkey
);
1926 return RegOpenKeyA( hkey
, name
, retkey
);
1929 /******************************************************************************
1930 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1932 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1934 fix_win16_hkey( &hkey
);
1935 return RegCreateKeyA( hkey
, name
, retkey
);
1938 /******************************************************************************
1939 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1941 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1943 fix_win16_hkey( &hkey
);
1944 return RegDeleteKeyA( hkey
, name
);
1947 /******************************************************************************
1948 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1950 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1952 fix_win16_hkey( &hkey
);
1953 return RegCloseKey( hkey
);
1956 /******************************************************************************
1957 * RegSetValue16 [KERNEL.221] [SHELL.5]
1959 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1961 fix_win16_hkey( &hkey
);
1962 return RegSetValueA( hkey
, name
, type
, data
, count
);
1965 /******************************************************************************
1966 * RegDeleteValue16 [KERNEL.222]
1968 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1970 fix_win16_hkey( &hkey
);
1971 return RegDeleteValueA( hkey
, name
);
1974 /******************************************************************************
1975 * RegEnumValue16 [KERNEL.223]
1977 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1978 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1980 fix_win16_hkey( &hkey
);
1981 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1984 /******************************************************************************
1985 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1988 * Is this HACK still applicable?
1991 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1992 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1995 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1997 fix_win16_hkey( &hkey
);
1998 if (count
) *count
&= 0xffff;
1999 return RegQueryValueA( hkey
, name
, data
, count
);
2002 /******************************************************************************
2003 * RegQueryValueEx16 [KERNEL.225]
2005 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
2006 LPBYTE data
, LPDWORD count
)
2008 fix_win16_hkey( &hkey
);
2009 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
2012 /******************************************************************************
2013 * RegSetValueEx16 [KERNEL.226]
2015 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
2016 CONST BYTE
*data
, DWORD count
)
2018 fix_win16_hkey( &hkey
);
2019 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);