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*
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/fcntl.h>
39 #include "wine/winbase16.h"
40 #include "wine/winestring.h"
44 #include "debugtools.h"
48 #include "winversion.h"
52 DEFAULT_DEBUG_CHANNEL(reg
)
54 static void REGISTRY_Init(void);
55 /* FIXME: following defines should be configured global ... */
57 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
58 #define WINE_PREFIX "/.wine"
59 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
60 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
62 /* relative in ~user/.wine/ : */
63 #define SAVE_CURRENT_USER "user.reg"
64 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
65 #define SAVE_LOCAL_MACHINE "system.reg"
67 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
68 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
71 /* what valuetypes do we need to convert? */
72 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
78 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
79 * If so, can we remove them?
81 * No, the memory handling functions are called very often in here,
82 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
83 * loading 100 times slower. -MM
85 static LPWSTR
strdupA2W(LPCSTR src
)
88 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
89 lstrcpyAtoW(dest
,src
);
95 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
98 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
100 lstrcpynAtoW(dest
,src
,nchars
+1);
107 /******************************************************************************
108 * REGISTRY_Init [Internal]
109 * Registry initialisation, allocates some default keys.
111 static void REGISTRY_Init(void) {
115 TRACE_(reg
)("(void)\n");
117 RegCreateKeyA(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
120 /* This was an Open, but since it is called before the real registries
121 are loaded, it was changed to a Create - MTB 980507*/
122 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
123 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
126 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
130 * string RegisteredOwner
131 * string RegisteredOrganization
134 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
139 if (-1!=gethostname(buf
,200)) {
140 RegCreateKeyA(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
141 RegSetValueExA(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
147 /************************ SAVE Registry Function ****************************/
149 #define REGISTRY_SAVE_VERSION 0x00000001
151 /* Registry saveformat:
152 * If you change it, increase above number by 1, which will flush
153 * old registry database files.
156 * "WINE REGISTRY Version %d"
160 * valuename=lastmodified,type,data
164 * keyname,valuename,stringdata:
165 * the usual ascii characters from 0x00-0xff (well, not 0x00)
166 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
167 * ( "=\\\t" escaped in \uXXXX form.)
171 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
173 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
174 * SaveOnlyUpdatedKeys=yes
177 /* Same as RegSaveKey but with Unix pathnames */
178 static void save_key( HKEY hkey
, const char *filename
)
180 struct save_registry_request
*req
= get_req_buffer();
185 char *name
= HeapAlloc( GetProcessHeap(), 0, strlen(filename
) + 20 );
188 strcpy( name
, filename
);
189 if ((p
= strrchr( name
, '/' ))) p
++;
194 sprintf( p
, "reg%04x.tmp", count
++ );
195 handle
= FILE_CreateFile( name
, GENERIC_WRITE
, 0, NULL
,
196 CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, -1 );
197 if (handle
!= INVALID_HANDLE_VALUE
) break;
198 if ((ret
= GetLastError()) != ERROR_FILE_EXISTS
) break;
201 if (handle
!= INVALID_HANDLE_VALUE
)
205 ret
= server_call_noerr( REQ_SAVE_REGISTRY
);
206 CloseHandle( handle
);
207 if (ret
) unlink( name
);
208 else if (rename( name
, filename
) == -1)
210 ERR( "Failed to move %s to %s: ", name
, filename
);
215 HeapFree( GetProcessHeap(), 0, name
);
219 /******************************************************************************
220 * SHELL_SaveRegistryBranch [Internal]
222 * Saves main registry branch specified by hkey.
224 static void SHELL_SaveRegistryBranch(HKEY hkey
)
228 /* Find out what to save to, get from config file */
229 BOOL writeToHome
= PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
230 BOOL writeToAlt
= PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
232 /* FIXME: does this check apply to all keys written below ? */
233 if (!(home
= getenv( "HOME" )))
234 ERR_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
236 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
237 if (hkey
== HKEY_CLASSES_ROOT
) hkey
= HKEY_LOCAL_MACHINE
;
241 case HKEY_CURRENT_USER
:
242 fn
= xmalloc( MAX_PATHNAME_LEN
);
243 if (writeToAlt
&& PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
244 fn
, MAX_PATHNAME_LEN
- 1))
245 save_key( HKEY_CURRENT_USER
, fn
);
248 if (home
&& writeToHome
)
250 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
251 strlen(SAVE_CURRENT_USER
) + 2 );
253 strcat(fn
,WINE_PREFIX
);
255 /* create the directory. don't care about errorcodes. */
256 mkdir(fn
,0755); /* drwxr-xr-x */
257 strcat(fn
,"/"SAVE_CURRENT_USER
);
258 save_key( HKEY_CURRENT_USER
, fn
);
262 case HKEY_LOCAL_MACHINE
:
263 /* Try first saving according to the defined location in .winerc */
264 fn
= xmalloc ( MAX_PATHNAME_LEN
);
265 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
266 fn
, MAX_PATHNAME_LEN
- 1))
267 save_key( HKEY_LOCAL_MACHINE
, fn
);
270 if (home
&& writeToHome
)
272 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
273 strlen(SAVE_LOCAL_MACHINE
) + 2);
275 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
276 save_key( HKEY_LOCAL_MACHINE
, fn
);
281 fn
= xmalloc( MAX_PATHNAME_LEN
);
282 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
283 fn
, MAX_PATHNAME_LEN
- 1))
284 save_key( HKEY_USERS
, fn
);
287 if (home
&& writeToHome
)
289 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
290 strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
292 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
293 save_key( HKEY_USERS
, fn
);
298 ERR_(reg
)("unknown/invalid key handle !\n");
304 /******************************************************************************
305 * SHELL_SaveRegistry [Internal]
307 void SHELL_SaveRegistry( void )
309 struct set_registry_levels_request
*req
= get_req_buffer();
314 TRACE_(reg
)("(void)\n");
317 if (RegOpenKeyA(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
326 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
331 &len
)) || (type
!=REG_SZ
))
338 if (lstrcmpiA(buf
,"yes")) all
= 1;
340 /* set saving level (0 for saving everything, 1 for saving only modified keys) */
343 req
->version
= PROFILE_GetWineIniBool( "registry", "UseNewFormat", 0 ) ? 2 : 1;
344 server_call( REQ_SET_REGISTRY_LEVELS
);
346 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER
);
347 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE
);
348 SHELL_SaveRegistryBranch(HKEY_USERS
);
351 /* Periodic save callback */
352 static void CALLBACK
periodic_save( ULONG_PTR dummy
)
354 SHELL_SaveRegistry();
357 /************************ LOAD Registry Function ****************************/
361 /******************************************************************************
362 * _find_or_add_key [Internal]
364 static inline HKEY
_find_or_add_key( HKEY hkey
, LPWSTR keyname
)
367 if (RegCreateKeyW( hkey
, keyname
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
368 if (keyname
) free( keyname
);
372 /******************************************************************************
373 * _find_or_add_value [Internal]
375 static void _find_or_add_value( HKEY hkey
, LPWSTR name
, DWORD type
, LPBYTE data
, DWORD len
)
377 RegSetValueExW( hkey
, name
, 0, type
, data
, len
);
378 if (name
) free( name
);
379 if (data
) free( data
);
383 /******************************************************************************
384 * _wine_read_line [Internal]
386 * reads a line including dynamically enlarging the readbuffer and throwing
389 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
399 s
=fgets(curread
,mylen
,F
);
402 if (NULL
==(s
=strchr(curread
,'\n'))) {
403 /* buffer wasn't large enough */
404 curoff
= strlen(*buf
);
405 *buf
= xrealloc(*buf
,*len
*2);
406 curread
= *buf
+ curoff
;
407 mylen
= *len
; /* we filled up the buffer and
408 * got new '*len' bytes to fill
416 /* throw away comments */
417 if (**buf
=='#' || **buf
==';') {
422 if (s
) /* got end of line */
429 /******************************************************************************
430 * _wine_read_USTRING [Internal]
432 * converts a char* into a UNICODE string (up to a special char)
433 * and returns the position exactly after that string
435 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
440 /* read up to "=" or "\0" or "\n" */
442 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
444 while (*s
&& (*s
!='\n') && (*s
!='=')) {
446 *ws
++=*((unsigned char*)s
++);
450 /* Dangling \ ... may only happen if a registry
451 * write was short. FIXME: What do to?
461 WARN_(reg
)("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
469 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
470 if (!sscanf(xbuf
,"%x",&wc
))
471 WARN_(reg
)("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
473 *ws
++ =(unsigned short)wc
;
482 /******************************************************************************
483 * _wine_loadsubkey [Internal]
486 * It seems like this is returning a boolean. Should it?
492 static int _wine_loadsubkey( FILE *F
, HKEY hkey
, int level
, char **buf
, int *buflen
)
499 TRACE_(reg
)("(%p,%x,%d,%s,%d)\n", F
, hkey
, level
, debugstr_a(*buf
), *buflen
);
501 /* Good. We already got a line here ... so parse it */
511 WARN_(reg
)("Got a subhierarchy without resp. key?\n");
514 if (!_wine_loadsubkey(F
,subkey
,level
+1,buf
,buflen
))
515 if (!_wine_read_line(F
,buf
,buflen
))
520 /* let the caller handle this line */
521 if (i
<level
|| **buf
=='\0')
524 /* it can be: a value or a keyname. Parse the name first */
525 s
=_wine_read_USTRING(s
,&name
);
527 /* switch() default: hack to avoid gotos */
531 if (subkey
) RegCloseKey( subkey
);
532 subkey
=_find_or_add_key(hkey
,name
);
535 int len
,lastmodified
,type
;
538 WARN_(reg
)("Unexpected character: %c\n",*s
);
542 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
543 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
550 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
553 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
554 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
555 len
= lstrlenW((LPWSTR
)data
)*2+2;
558 data
= (LPBYTE
)xmalloc(len
+1);
559 for (i
=0;i
<len
;i
++) {
561 if (*s
>='0' && *s
<='9')
563 if (*s
>='a' && *s
<='f')
564 data
[i
]=(*s
-'a'+'\xa')<<4;
565 if (*s
>='A' && *s
<='F')
566 data
[i
]=(*s
-'A'+'\xa')<<4;
568 if (*s
>='0' && *s
<='9')
570 if (*s
>='a' && *s
<='f')
571 data
[i
]|=*s
-'a'+'\xa';
572 if (*s
>='A' && *s
<='F')
573 data
[i
]|=*s
-'A'+'\xa';
577 _find_or_add_value(hkey
,name
,type
,data
,len
);
580 /* read the next line */
581 if (!_wine_read_line(F
,buf
,buflen
))
585 if (subkey
) RegCloseKey( subkey
);
590 /******************************************************************************
591 * _wine_loadsubreg [Internal]
593 static int _wine_loadsubreg( FILE *F
, HKEY hkey
, const char *fn
)
599 buf
=xmalloc(10);buflen
=10;
600 if (!_wine_read_line(F
,&buf
,&buflen
)) {
604 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
608 if (ver
!=REGISTRY_SAVE_VERSION
) {
609 if (ver
== 2) /* new version */
612 if ((file
= FILE_CreateFile( fn
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
613 FILE_ATTRIBUTE_NORMAL
, -1 )) != INVALID_HANDLE_VALUE
)
615 struct load_registry_request
*req
= get_req_buffer();
619 server_call( REQ_LOAD_REGISTRY
);
627 TRACE_(reg
)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
632 if (!_wine_read_line(F
,&buf
,&buflen
)) {
636 if (!_wine_loadsubkey(F
,hkey
,0,&buf
,&buflen
)) {
645 /******************************************************************************
646 * _wine_loadreg [Internal]
648 static void _wine_loadreg( HKEY hkey
, char *fn
)
652 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(fn
));
656 WARN_(reg
)("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
659 _wine_loadsubreg(F
,hkey
,fn
);
663 /******************************************************************************
664 * _flush_registry [Internal]
666 * This function allow to flush section of the internal registry. It is mainly
667 * implements to fix a problem with the global HKU and the local HKU.
668 * Those two files are read to build the HKU\.Default branch to finaly copy
669 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
670 * all the global HKU are saved onto the user's personal version of HKU hive.
674 static void _flush_registry( HKEY hkey
)
676 WCHAR name
[MAX_PATH
];
681 /* FIXME: we assume that deleting a key will move the other ones up, */
682 /* so that we can always use index 0 until there are no more keys */
683 if (RegEnumKeyW( hkey
, 0, name
, sizeof(name
) ) != ERROR_SUCCESS
) break;
684 if (RegOpenKeyW( hkey
, name
, &subkey
) != ERROR_SUCCESS
) break;
685 _flush_registry( subkey
);
686 if (RegDeleteKeyW( subkey
, NULL
) != ERROR_SUCCESS
) break;
687 RegCloseKey( subkey
);
692 /******************************************************************************
693 * _copy_registry [Internal]
695 static void _copy_registry( HKEY from
, HKEY to
)
700 DWORD type
, name_len
, len
;
701 static WCHAR name
[MAX_PATH
];
702 static BYTE data
[2048];
709 name_len
= sizeof(name
);
710 if (RegEnumValueW( from
, index
++, name
, &name_len
,
711 NULL
, &type
, data
, &len
) != ERROR_SUCCESS
) break;
712 RegSetValueW( to
, name
, type
, (LPCWSTR
)data
, len
);
719 name_len
= sizeof(name
);
720 if (RegEnumKeyExW( from
, index
++, name
, &name_len
,
721 NULL
, NULL
, 0, &ft
) != ERROR_SUCCESS
)
723 if (RegOpenKeyW( from
, name
, &subkey
) == ERROR_SUCCESS
)
726 if (RegCreateKeyW( to
, name
, &newsub
) == ERROR_SUCCESS
)
728 _copy_registry( subkey
, newsub
);
729 RegCloseKey( newsub
);
731 RegCloseKey( subkey
);
737 /* WINDOWS 95 REGISTRY LOADER */
739 * Structure of a win95 registry database.
743 * 8 : DWORD offset_of_RGDB_part
744 * 0C..0F: ? (someone fill in please)
745 * 10: WORD number of RGDB blocks
747 * 14: WORD always 0000?
748 * 16: WORD always 0001?
749 * 18..1F: ? (someone fill in please)
754 * 4 : DWORD offset to first RGDB section
755 * 8 : DWORD offset to the root record
756 * C..0x1B: ? (fill in)
757 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
759 * Disk Key Entry Structure:
760 * 00: DWORD - Free entry indicator(?)
761 * 04: DWORD - Hash = sum of bytes of keyname
762 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
763 * 0C: DWORD - disk address of PreviousLevel Key.
764 * 10: DWORD - disk address of Next Sublevel Key.
765 * 14: DWORD - disk address of Next Key (on same level).
766 * DKEP>18: WORD - Nr, Low Significant part.
767 * 1A: WORD - Nr, High Significant part.
769 * The disk address always points to the nr part of the previous key entry
770 * of the referenced key. Don't ask me why, or even if I got this correct
771 * from staring at 1kg of hexdumps. (DKEP)
773 * The High significant part of the structure seems to equal the number
774 * of the RGDB section. The low significant part is a unique ID within
777 * There are two minor corrections to the position of that structure.
778 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
779 * the DKE reread from there.
780 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
781 * CPS - I have not experienced the above phenomenon in my registry files
785 * 04: DWORD offset to next RGDB section
787 * 0C: WORD always 000d?
788 * 0E: WORD RGDB block number
789 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
794 * 00: DWORD nextkeyoffset - offset to the next disk key structure
795 * 08: WORD nrLS - low significant part of NR
796 * 0A: WORD nrHS - high significant part of NR
797 * 0C: DWORD bytesused - bytes used in this structure.
798 * 10: WORD name_len - length of name in bytes. without \0
799 * 12: WORD nr_of_values - number of values.
800 * 14: char name[name_len] - name string. No \0.
801 * 14+name_len: disk values
802 * nextkeyoffset: ... next disk key
805 * 00: DWORD type - value type (hmm, could be WORD too)
806 * 04: DWORD - unknown, usually 0
807 * 08: WORD namelen - length of Name. 0 means name=NULL
808 * 0C: WORD datalen - length of Data.
809 * 10: char name[namelen] - name, no \0
810 * 10+namelen: BYTE data[datalen] - data, without \0 if string
811 * 10+namelen+datalen: next values or disk key
813 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
814 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
815 * structure) and reading another RGDB_section.
816 * repeat until end of file.
818 * An interesting relationship exists in RGDB_section. The value at offset
819 * 10 equals the value at offset 4 minus the value at offset 8. I have no
820 * idea at the moment what this means. (Kevin Cozens)
822 * FIXME: this description needs some serious help, yes.
825 struct _w95keyvalue
{
827 unsigned short datalen
;
837 struct _w95keyvalue
*values
;
838 struct _w95key
*prevlvl
;
839 struct _w95key
*nextsub
;
840 struct _w95key
*next
;
854 /******************************************************************************
855 * _w95_processKey [Internal]
857 static HKEY
_w95_processKey ( HKEY hkey
, int nrLS
, int nrMS
, struct _w95_info
*info
)
860 /* Disk Key Header structure (RGDB part) */
862 unsigned long nextkeyoff
;
865 unsigned long bytesused
;
866 unsigned short keynamelen
;
867 unsigned short values
;
870 /* disk key values or nothing */
872 /* Disk Key Value structure */
876 unsigned short valnamelen
;
877 unsigned short valdatalen
;
878 /* valname, valdata */
884 char *rgdbdata
= info
->rgdbbuffer
;
885 int nbytes
= info
->rgdbsize
;
886 char *curdata
= rgdbdata
;
887 char *end
= rgdbdata
+ nbytes
;
889 char *next
= rgdbdata
;
895 if (strncmp(curdata
, "RGDB", 4)) return 0;
897 memcpy(&off_next_rgdb
,curdata
+4,4);
898 next
= curdata
+ off_next_rgdb
;
899 nrgdb
= (int) *((short *)curdata
+ 7);
901 } while (nrgdb
!= nrMS
&& (next
< end
));
903 /* curdata now points to the start of the right RGDB section */
906 #define XREAD(whereto,len) \
907 if ((curdata + len) <= end) {\
908 memcpy(whereto,curdata,len);\
913 while (curdata
< next
) {
914 struct dkh
*xdkh
= (struct dkh
*)curdata
;
916 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
917 if (xdkh
->nrLS
== nrLS
) {
918 memcpy(&dkh
,xdkh
,sizeof(dkh
));
919 curdata
+= sizeof(dkh
);
922 curdata
+= xdkh
->nextkeyoff
;
925 if (dkh
.nrLS
!= nrLS
) return 0;
927 if (nrgdb
!= dkh
.nrMS
)
930 assert((dkh
.keynamelen
<2) || curdata
[0]);
931 subkey
=_find_or_add_key(hkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
932 curdata
+= dkh
.keynamelen
;
934 for (i
=0;i
< dkh
.values
; i
++) {
940 XREAD(&dkv
,sizeof(dkv
));
942 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
943 curdata
+= dkv
.valnamelen
;
945 if ((1 << dkv
.type
) & UNICONVMASK
) {
946 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
947 len
= 2*(dkv
.valdatalen
+ 1);
949 /* I don't think we want to NULL terminate all data */
950 data
= xmalloc(dkv
.valdatalen
);
951 memcpy (data
, curdata
, dkv
.valdatalen
);
952 len
= dkv
.valdatalen
;
955 curdata
+= dkv
.valdatalen
;
957 _find_or_add_value( subkey
, name
, dkv
.type
, data
, len
);
962 /******************************************************************************
963 * _w95_walkrgkn [Internal]
965 static void _w95_walkrgkn( HKEY prevkey
, char *off
,
966 struct _w95_info
*info
)
969 /* Disk Key Entry structure (RGKN part) */
973 unsigned long x3
;/*usually 0xFFFFFFFF */
974 unsigned long prevlvl
;
975 unsigned long nextsub
;
979 } *dke
= (struct dke
*)off
;
983 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
986 subkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
988 if (dke
->nextsub
!= -1 &&
989 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
990 && (dke
->nextsub
> 0x20)) {
992 _w95_walkrgkn(subkey
? subkey
: prevkey
, /* XXX <-- This is a hack*/
993 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
996 if (subkey
) RegCloseKey( subkey
);
998 if (dke
->next
!= -1 &&
999 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1000 (dke
->next
> 0x20)) {
1001 _w95_walkrgkn(prevkey
,
1002 info
->rgknbuffer
+ dke
->next
- 0x20,
1008 /******************************************************************************
1009 * _w95_loadreg [Internal]
1011 static void _w95_loadreg( char* fn
, HKEY hkey
)
1015 unsigned long where
,version
,rgdbsection
,end
;
1016 struct _w95_info info
;
1018 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1020 TRACE_(reg
)("Loading Win95 registry database '%s'\n",fn
);
1021 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1022 if (hfd
==HFILE_ERROR
)
1025 if (4!=_lread(hfd
,magic
,4))
1027 if (strcmp(magic
,"CREG")) {
1028 WARN_(reg
)("%s is not a w95 registry.\n",fn
);
1031 if (4!=_lread(hfd
,&version
,4))
1033 if (4!=_lread(hfd
,&rgdbsection
,4))
1035 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1037 if (4!=_lread(hfd
,magic
,4))
1039 if (strcmp(magic
,"RGKN")) {
1040 WARN_(reg
)("second IFF header not RGKN, but %s\n", magic
);
1044 /* STEP 1: Keylink structures */
1045 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1050 info
.rgknsize
= end
- where
;
1051 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1052 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1055 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1058 end
= hfdinfo
.nFileSizeLow
;
1059 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1061 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1064 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1065 info
.rgdbsize
= end
- rgdbsection
;
1067 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1071 _w95_walkrgkn(hkey
, NULL
, &info
);
1073 free (info
.rgdbbuffer
);
1074 free (info
.rgknbuffer
);
1078 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1081 reghack - windows 3.11 registry data format demo program.
1083 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1084 a combined hash table and tree description, and finally a text table.
1086 The header is obvious from the struct header. The taboff1 and taboff2
1087 fields are always 0x20, and their usage is unknown.
1089 The 8-byte entry table has various entry types.
1091 tabent[0] is a root index. The second word has the index of the root of
1093 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1094 the index of the key/value that has that hash. Data with the same
1095 hash value are on a circular list. The other three words in the
1096 hash entry are always zero.
1097 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1098 entry: dirent and keyent/valent. They are identified by context.
1099 tabent[freeidx] is the first free entry. The first word in a free entry
1100 is the index of the next free entry. The last has 0 as a link.
1101 The other three words in the free list are probably irrelevant.
1103 Entries in text table are preceeded by a word at offset-2. This word
1104 has the value (2*index)+1, where index is the referring keyent/valent
1105 entry in the table. I have no suggestion for the 2* and the +1.
1106 Following the word, there are N bytes of data, as per the keyent/valent
1107 entry length. The offset of the keyent/valent entry is from the start
1108 of the text table to the first data byte.
1110 This information is not available from Microsoft. The data format is
1111 deduced from the reg.dat file by me. Mistakes may
1112 have been made. I claim no rights and give no guarantees for this program.
1114 Tor Sjøwall, tor@sn.no
1117 /* reg.dat header format */
1118 struct _w31_header
{
1119 char cookie
[8]; /* 'SHCC3.10' */
1120 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1121 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1122 unsigned long tabcnt
; /* number of entries in index table */
1123 unsigned long textoff
; /* offset of text part */
1124 unsigned long textsize
; /* byte size of text part */
1125 unsigned short hashsize
; /* hash size */
1126 unsigned short freeidx
; /* free index */
1129 /* generic format of table entries */
1130 struct _w31_tabent
{
1131 unsigned short w0
, w1
, w2
, w3
;
1134 /* directory tabent: */
1135 struct _w31_dirent
{
1136 unsigned short sibling_idx
; /* table index of sibling dirent */
1137 unsigned short child_idx
; /* table index of child dirent */
1138 unsigned short key_idx
; /* table index of key keyent */
1139 unsigned short value_idx
; /* table index of value valent */
1143 struct _w31_keyent
{
1144 unsigned short hash_idx
; /* hash chain index for string */
1145 unsigned short refcnt
; /* reference count */
1146 unsigned short length
; /* length of string */
1147 unsigned short string_off
; /* offset of string in text table */
1151 struct _w31_valent
{
1152 unsigned short hash_idx
; /* hash chain index for string */
1153 unsigned short refcnt
; /* reference count */
1154 unsigned short length
; /* length of string */
1155 unsigned short string_off
; /* offset of string in text table */
1158 /* recursive helper function to display a directory tree */
1160 __w31_dumptree( unsigned short idx
,
1162 struct _w31_tabent
*tab
,
1163 struct _w31_header
*head
,
1165 time_t lastmodified
,
1168 struct _w31_dirent
*dir
;
1169 struct _w31_keyent
*key
;
1170 struct _w31_valent
*val
;
1172 static char tail
[400];
1175 dir
=(struct _w31_dirent
*)&tab
[idx
];
1178 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1180 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1181 tail
[key
->length
]='\0';
1182 /* all toplevel entries AND the entries in the
1183 * toplevel subdirectory belong to \SOFTWARE\Classes
1185 if (!level
&& !lstrcmpA(tail
,".classes")) {
1186 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,hkey
,lastmodified
,level
+1);
1187 idx
=dir
->sibling_idx
;
1190 if (subkey
) RegCloseKey( subkey
);
1191 if (RegCreateKeyA( hkey
, tail
, &subkey
) != ERROR_SUCCESS
) subkey
= 0;
1192 /* only add if leaf node or valued node */
1193 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1194 if (dir
->value_idx
) {
1195 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1196 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1197 tail
[val
->length
]='\0';
1198 RegSetValueA( subkey
, NULL
, REG_SZ
, tail
, 0 );
1202 TRACE_(reg
)("strange: no directory key name, idx=%04x\n", idx
);
1204 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,subkey
,lastmodified
,level
+1);
1205 idx
=dir
->sibling_idx
;
1207 if (subkey
) RegCloseKey( subkey
);
1211 /******************************************************************************
1212 * _w31_loadreg [Internal]
1214 void _w31_loadreg(void) {
1216 struct _w31_header head
;
1217 struct _w31_tabent
*tab
;
1221 BY_HANDLE_FILE_INFORMATION hfinfo
;
1222 time_t lastmodified
;
1224 TRACE_(reg
)("(void)\n");
1226 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1227 if (hf
==HFILE_ERROR
)
1230 /* read & dump header */
1231 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1232 ERR_(reg
)("reg.dat is too short.\n");
1236 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1237 ERR_(reg
)("reg.dat has bad signature.\n");
1242 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1243 /* read and dump index table */
1245 if (len
!=_lread(hf
,tab
,len
)) {
1246 ERR_(reg
)("couldn't read %d bytes.\n",len
);
1253 txt
= xmalloc(head
.textsize
);
1254 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1255 ERR_(reg
)("couldn't seek to textblock.\n");
1261 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1262 ERR_(reg
)("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1269 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1270 ERR_(reg
)("GetFileInformationByHandle failed?.\n");
1276 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1277 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,HKEY_CLASSES_ROOT
,lastmodified
,0);
1285 /**********************************************************************************
1286 * SHELL_LoadRegistry [Internal]
1288 void SHELL_LoadRegistry( void )
1290 struct set_registry_levels_request
*req
= get_req_buffer();
1295 TRACE_(reg
)("(void)\n");
1299 /* set level to 0 for loading system files */
1303 server_call( REQ_SET_REGISTRY_LEVELS
);
1305 if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1))
1307 /* Load windows 3.1 entries */
1309 /* Load windows 95 entries */
1310 _w95_loadreg("C:\\system.1st", HKEY_LOCAL_MACHINE
);
1311 _w95_loadreg("system.dat", HKEY_LOCAL_MACHINE
);
1312 _w95_loadreg("user.dat", HKEY_USERS
);
1315 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1318 * Load the global HKU hive directly from sysconfdir
1320 _wine_loadreg( HKEY_USERS
, SAVE_USERS_DEFAULT
);
1323 * Load the global machine defaults directly form sysconfdir
1325 _wine_loadreg( HKEY_LOCAL_MACHINE
, SAVE_LOCAL_MACHINE_DEFAULT
);
1328 /* set level to 1 for loading user files */
1332 server_call( REQ_SET_REGISTRY_LEVELS
);
1335 * Load the user saved registries
1337 if (!(home
= getenv( "HOME" )))
1338 WARN_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1339 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1342 * Load user's personal versions of global HKU/.Default keys
1344 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
) +
1345 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1347 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1348 _wine_loadreg( HKEY_USERS
, fn
);
1351 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) + strlen(SAVE_CURRENT_USER
)+2);
1353 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1354 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1358 * Load HKLM, attempt to get the registry location from the config
1359 * file first, if exist, load and keep going.
1361 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_MACHINE
)+2);
1363 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1364 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1369 * Load HKCU, get the registry location from the config
1370 * file, if exist, load and keep going.
1372 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
1374 fn
= xmalloc( MAX_PATHNAME_LEN
);
1375 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
1376 fn
, MAX_PATHNAME_LEN
- 1))
1378 _wine_loadreg( HKEY_CURRENT_USER
, fn
);
1382 * Load HKU, get the registry location from the config
1383 * file, if exist, load and keep going.
1385 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1386 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
1387 fn
, MAX_PATHNAME_LEN
- 1))
1389 _wine_loadreg( HKEY_USERS
, fn
);
1393 * Load HKLM, get the registry location from the config
1394 * file, if exist, load and keep going.
1396 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1397 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
1398 fn
, MAX_PATHNAME_LEN
- 1))
1400 _wine_loadreg( HKEY_LOCAL_MACHINE
, fn
);
1406 * Obtain the handle of the HKU\.Default key.
1407 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1409 if (RegCreateKeyA(HKEY_USERS
,".Default",&hkey
) != ERROR_SUCCESS
)
1410 WARN_(reg
)("Could not create global user default key\n");
1412 _copy_registry( hkey
, HKEY_CURRENT_USER
);
1416 * Since HKU is built from the global HKU and the local user HKU file we must
1417 * flush the HKU tree we have built at this point otherwise the part brought
1418 * in from the global HKU is saved into the local HKU. To avoid this
1419 * useless dupplication of HKU keys we reread the local HKU key.
1422 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1423 _flush_registry( HKEY_USERS
);
1425 /* Reload user's local HKU hive */
1426 if (home
&& PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
1428 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
)
1429 + strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
1432 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1434 _wine_loadreg( HKEY_USERS
, fn
);
1440 * Make sure the update mode is there
1442 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
1444 DWORD junk
,type
,len
;
1448 if (( RegQueryValueExA(
1454 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
1456 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1462 if ((save_timeout
= PROFILE_GetWineIniInt( "registry", "PeriodicSave", 0 )))
1464 SERVICE_AddTimer( save_timeout
* 1000000, periodic_save
, 0 );
1469 /********************* API FUNCTIONS ***************************************/
1474 /******************************************************************************
1475 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
1476 * Immediately writes key to registry.
1477 * Only returns after data has been written to disk.
1479 * FIXME: does it really wait until data is written ?
1482 * hkey [I] Handle of key to write
1485 * Success: ERROR_SUCCESS
1486 * Failure: Error code
1488 DWORD WINAPI
RegFlushKey( HKEY hkey
)
1490 FIXME( "(%x): stub\n", hkey
);
1491 return ERROR_SUCCESS
;
1494 /******************************************************************************
1495 * RegConnectRegistry32W [ADVAPI32.128]
1498 * lpMachineName [I] Address of name of remote computer
1499 * hHey [I] Predefined registry handle
1500 * phkResult [I] Address of buffer for remote registry handle
1502 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
1505 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
1507 if (!lpMachineName
|| !*lpMachineName
) {
1508 /* Use the local machine name */
1509 return RegOpenKey16( hKey
, "", phkResult
);
1512 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
1513 return ERROR_BAD_NETPATH
;
1517 /******************************************************************************
1518 * RegConnectRegistry32A [ADVAPI32.127]
1520 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
1523 LPWSTR machineW
= strdupA2W(machine
);
1524 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
1530 /******************************************************************************
1531 * RegGetKeySecurity [ADVAPI32.144]
1532 * Retrieves a copy of security descriptor protecting the registry key
1535 * hkey [I] Open handle of key to set
1536 * SecurityInformation [I] Descriptor contents
1537 * pSecurityDescriptor [O] Address of descriptor for key
1538 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
1541 * Success: ERROR_SUCCESS
1542 * Failure: Error code
1544 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
1545 SECURITY_INFORMATION SecurityInformation
,
1546 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
1547 LPDWORD lpcbSecurityDescriptor
)
1549 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
1550 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1552 /* FIXME: Check for valid SecurityInformation values */
1554 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
1555 return ERROR_INSUFFICIENT_BUFFER
;
1557 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
1558 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
1560 return ERROR_SUCCESS
;
1564 /******************************************************************************
1565 * RegNotifyChangeKeyValue [ADVAPI32.???]
1568 * hkey [I] Handle of key to watch
1569 * fWatchSubTree [I] Flag for subkey notification
1570 * fdwNotifyFilter [I] Changes to be reported
1571 * hEvent [I] Handle of signaled event
1572 * fAsync [I] Flag for asynchronous reporting
1574 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
1575 DWORD fdwNotifyFilter
, HANDLE hEvent
,
1578 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
1580 return ERROR_SUCCESS
;
1584 /******************************************************************************
1585 * RegUnLoadKey32W [ADVAPI32.173]
1588 * hkey [I] Handle of open key
1589 * lpSubKey [I] Address of name of subkey to unload
1591 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
1593 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
1594 return ERROR_SUCCESS
;
1598 /******************************************************************************
1599 * RegUnLoadKey32A [ADVAPI32.172]
1601 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
1604 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1605 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
1606 if(lpSubKeyW
) free(lpSubKeyW
);
1611 /******************************************************************************
1612 * RegSetKeySecurity [ADVAPI32.167]
1615 * hkey [I] Open handle of key to set
1616 * SecurityInfo [I] Descriptor contents
1617 * pSecurityDesc [I] Address of descriptor for key
1619 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
1620 PSECURITY_DESCRIPTOR pSecurityDesc
)
1622 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
1624 /* It seems to perform this check before the hkey check */
1625 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
1626 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
1627 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
1628 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
1631 return ERROR_INVALID_PARAMETER
;
1634 return ERROR_INVALID_PARAMETER
;
1636 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
1638 return ERROR_SUCCESS
;
1642 /******************************************************************************
1643 * RegRestoreKey32W [ADVAPI32.164]
1646 * hkey [I] Handle of key where restore begins
1647 * lpFile [I] Address of filename containing saved tree
1648 * dwFlags [I] Optional flags
1650 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
1652 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1654 /* It seems to do this check before the hkey check */
1655 if (!lpFile
|| !*lpFile
)
1656 return ERROR_INVALID_PARAMETER
;
1658 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
1660 /* Check for file existence */
1662 return ERROR_SUCCESS
;
1666 /******************************************************************************
1667 * RegRestoreKey32A [ADVAPI32.163]
1669 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
1672 LPWSTR lpFileW
= strdupA2W(lpFile
);
1673 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
1674 if(lpFileW
) free(lpFileW
);
1679 /******************************************************************************
1680 * RegReplaceKey32W [ADVAPI32.162]
1683 * hkey [I] Handle of open key
1684 * lpSubKey [I] Address of name of subkey
1685 * lpNewFile [I] Address of filename for file with new data
1686 * lpOldFile [I] Address of filename for backup file
1688 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
1691 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
1692 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
1693 return ERROR_SUCCESS
;
1697 /******************************************************************************
1698 * RegReplaceKey32A [ADVAPI32.161]
1700 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
1704 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
1705 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
1706 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
1707 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
1719 /* 16-bit functions */
1721 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
1722 * some programs. Do not remove those cases. -MM
1724 static inline void fix_win16_hkey( HKEY
*hkey
)
1726 if (*hkey
== 0 || *hkey
== 1) *hkey
= HKEY_CLASSES_ROOT
;
1729 /******************************************************************************
1730 * RegEnumKey16 [KERNEL.216] [SHELL.7]
1732 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD index
, LPSTR name
, DWORD name_len
)
1734 fix_win16_hkey( &hkey
);
1735 return RegEnumKeyA( hkey
, index
, name
, name_len
);
1738 /******************************************************************************
1739 * RegOpenKey16 [KERNEL.217] [SHELL.1]
1741 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1743 fix_win16_hkey( &hkey
);
1744 return RegOpenKeyA( hkey
, name
, retkey
);
1747 /******************************************************************************
1748 * RegCreateKey16 [KERNEL.218] [SHELL.2]
1750 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR name
, LPHKEY retkey
)
1752 fix_win16_hkey( &hkey
);
1753 return RegCreateKeyA( hkey
, name
, retkey
);
1756 /******************************************************************************
1757 * RegDeleteKey16 [KERNEL.219] [SHELL.4]
1759 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR name
)
1761 fix_win16_hkey( &hkey
);
1762 return RegDeleteKeyA( hkey
, name
);
1765 /******************************************************************************
1766 * RegCloseKey16 [KERNEL.220] [SHELL.3]
1768 DWORD WINAPI
RegCloseKey16( HKEY hkey
)
1770 fix_win16_hkey( &hkey
);
1771 return RegCloseKey( hkey
);
1774 /******************************************************************************
1775 * RegSetValue16 [KERNEL.221] [SHELL.5]
1777 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR name
, DWORD type
, LPCSTR data
, DWORD count
)
1779 fix_win16_hkey( &hkey
);
1780 return RegSetValueA( hkey
, name
, type
, data
, count
);
1783 /******************************************************************************
1784 * RegDeleteValue16 [KERNEL.222]
1786 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR name
)
1788 fix_win16_hkey( &hkey
);
1789 return RegDeleteValueA( hkey
, name
);
1792 /******************************************************************************
1793 * RegEnumValue16 [KERNEL.223]
1795 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD index
, LPSTR value
, LPDWORD val_count
,
1796 LPDWORD reserved
, LPDWORD type
, LPBYTE data
, LPDWORD count
)
1798 fix_win16_hkey( &hkey
);
1799 return RegEnumValueA( hkey
, index
, value
, val_count
, reserved
, type
, data
, count
);
1802 /******************************************************************************
1803 * RegQueryValue16 [KERNEL.224] [SHELL.6]
1806 * Is this HACK still applicable?
1809 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
1810 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
1813 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPCSTR name
, LPSTR data
, LPDWORD count
)
1815 fix_win16_hkey( &hkey
);
1816 if (count
) *count
&= 0xffff;
1817 return RegQueryValueA( hkey
, name
, data
, count
);
1820 /******************************************************************************
1821 * RegQueryValueEx16 [KERNEL.225]
1823 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPCSTR name
, LPDWORD reserved
, LPDWORD type
,
1824 LPBYTE data
, LPDWORD count
)
1826 fix_win16_hkey( &hkey
);
1827 return RegQueryValueExA( hkey
, name
, reserved
, type
, data
, count
);
1830 /******************************************************************************
1831 * RegSetValueEx16 [KERNEL.226]
1833 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPCSTR name
, DWORD reserved
, DWORD type
,
1834 CONST BYTE
*data
, DWORD count
)
1836 fix_win16_hkey( &hkey
);
1837 return RegSetValueExA( hkey
, name
, reserved
, type
, data
, count
);