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"
50 DECLARE_DEBUG_CHANNEL(reg
)
51 DECLARE_DEBUG_CHANNEL(string
)
53 static void REGISTRY_Init(void);
54 /* FIXME: following defines should be configured global ... */
56 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
57 #define WINE_PREFIX "/.wine"
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
67 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
69 /* one value of a key */
70 typedef struct tagKEYVALUE
72 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
73 DWORD type
; /* type of value */
74 DWORD len
; /* length of data in BYTEs */
75 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
76 LPBYTE data
; /* content, may be strings, binaries, etc. */
77 } KEYVALUE
,*LPKEYVALUE
;
80 typedef struct tagKEYSTRUCT
82 LPWSTR keyname
; /* name of THIS key (UNICODE) */
83 DWORD flags
; /* flags. */
86 DWORD nrofvalues
; /* nr of values in THIS key */
87 LPKEYVALUE values
; /* values in THIS key */
88 /* key management pointers */
89 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
90 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
91 } KEYSTRUCT
, *LPKEYSTRUCT
;
94 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
95 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
96 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
97 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
99 /* dynamic, not saved */
100 static KEYSTRUCT
*key_performance_data
=NULL
;
101 static KEYSTRUCT
*key_current_config
=NULL
;
102 static KEYSTRUCT
*key_dyn_data
=NULL
;
104 /* what valuetypes do we need to convert? */
105 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
108 static struct openhandle
{
113 static int nrofopenhandles
=0;
114 /* Starts after 1 because 0,1 are reserved for Win16 */
115 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
116 HKEYs for remote registry access */
117 static int currenthandle
=2;
122 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
123 * If so, can we remove them?
125 * No, the memory handling functions are called very often in here,
126 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
127 * loading 100 times slower. -MM
129 static LPWSTR
strdupA2W(LPCSTR src
)
132 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
133 lstrcpyAtoW(dest
,src
);
139 static LPWSTR
strdupW(LPCWSTR a
) {
144 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
145 b
=(LPWSTR
)xmalloc(len
);
152 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
155 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
157 lstrcpynAtoW(dest
,src
,nchars
+1);
162 * we need to convert A to W with '\0' in strings (MULTI_SZ)
165 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
168 TRACE_(reg
)("\"%s\" %i\n",src
, n
);
170 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
174 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
177 TRACE_(string
)("L\"%s\" %i\n",debugstr_w(src
), n
);
179 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
184 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
186 if (TRACE_ON(reg
) && lpbData
)
192 TRACE_(reg
)(" Value %s, Data(sz)=%s\n",
193 debugstr_w(key
->name
),
194 debugstr_w((LPCWSTR
)lpbData
));
198 TRACE_(reg
)(" Value %s, Data(dword)=0x%08lx\n",
199 debugstr_w(key
->name
),
206 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
209 TRACE_(reg
)(" Value %s, MULTI_SZ(%i=%s)\n",
210 debugstr_w(key
->name
),
214 ptr
+= lstrlenW(ptr
)+1;
221 char szTemp
[100]; /* 3*32 + 3 + 1 */
223 for ( i
= 0; i
< key
->len
; i
++)
225 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
228 sprintf (&(szTemp
[i
*3+3]),"...");
232 TRACE_(reg
)(" Value %s, Data(raw)=(%s)\n",
233 debugstr_w(key
->name
),
241 /******************************************************************************
242 * is_standard_hkey [Internal]
243 * Determines if a hkey is a standard key
245 static BOOL
is_standard_hkey( HKEY hkey
)
250 case HKEY_CLASSES_ROOT
:
251 case HKEY_CURRENT_CONFIG
:
252 case HKEY_CURRENT_USER
:
253 case HKEY_LOCAL_MACHINE
:
255 case HKEY_PERFORMANCE_DATA
:
263 /******************************************************************************
264 * add_handle [Internal]
266 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
270 TRACE_(reg
)("(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
271 /* Check for duplicates */
272 for (i
=0;i
<nrofopenhandles
;i
++) {
273 if (openhandles
[i
].lpkey
==lpkey
) {
274 /* This is not really an error - the user is allowed to create
275 two (or more) handles to the same key */
276 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
278 if (openhandles
[i
].hkey
==hkey
) {
279 WARN_(reg
)("Adding handle %x twice\n",hkey
);
282 openhandles
=xrealloc( openhandles
,
283 sizeof(struct openhandle
)*(nrofopenhandles
+1));
285 openhandles
[i
].lpkey
= lpkey
;
286 openhandles
[i
].hkey
= hkey
;
287 openhandles
[i
].accessmask
= accessmask
;
292 /******************************************************************************
293 * get_handle [Internal]
296 * Success: Pointer to key
299 static LPKEYSTRUCT
get_handle( HKEY hkey
)
303 for (i
=0; i
<nrofopenhandles
; i
++)
304 if (openhandles
[i
].hkey
== hkey
)
305 return openhandles
[i
].lpkey
;
306 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
311 /******************************************************************************
312 * remove_handle [Internal]
315 * hkey [I] Handle of key to remove
318 * Success: ERROR_SUCCESS
319 * Failure: ERROR_INVALID_HANDLE
321 static DWORD
remove_handle( HKEY hkey
)
325 for (i
=0;i
<nrofopenhandles
;i
++)
326 if (openhandles
[i
].hkey
==hkey
)
329 if (i
== nrofopenhandles
) {
330 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
331 return ERROR_INVALID_HANDLE
;
334 memcpy( openhandles
+i
,
336 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
338 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
340 return ERROR_SUCCESS
;
343 /******************************************************************************
344 * lookup_hkey [Internal]
346 * Just as the name says. Creates the root keys on demand, so we can call the
347 * Reg* functions at any time.
350 * Success: Pointer to key structure
353 #define ADD_ROOT_KEY(xx) \
354 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
355 memset(xx,'\0',sizeof(KEYSTRUCT));\
356 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
358 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
361 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
362 * some programs. Do not remove those cases. -MM
366 case HKEY_CLASSES_ROOT
:
368 if (!key_classes_root
)
372 /* calls lookup_hkey recursively, TWICE */
376 &cl_r_hkey
) != ERROR_SUCCESS
)
378 ERR_(reg
)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
382 key_classes_root
= lookup_hkey(cl_r_hkey
);
384 return key_classes_root
;
387 case HKEY_CURRENT_USER
:
388 if (!key_current_user
) {
389 ADD_ROOT_KEY(key_current_user
);
391 return key_current_user
;
393 case HKEY_LOCAL_MACHINE
:
394 if (!key_local_machine
) {
395 ADD_ROOT_KEY(key_local_machine
);
398 return key_local_machine
;
402 ADD_ROOT_KEY(key_users
);
406 case HKEY_PERFORMANCE_DATA
:
407 if (!key_performance_data
) {
408 ADD_ROOT_KEY(key_performance_data
);
410 return key_performance_data
;
414 ADD_ROOT_KEY(key_dyn_data
);
418 case HKEY_CURRENT_CONFIG
:
419 if (!key_current_config
) {
420 ADD_ROOT_KEY(key_current_config
);
422 return key_current_config
;
425 return get_handle(hkey
);
433 * recursively searches for lpkey_to_find in the root key branch
434 * given in lpcurrkey.
436 static int subkey_found(LPKEYSTRUCT lpcurrkey
, LPKEYSTRUCT lpkey_to_find
)
440 if (lpcurrkey
== lpkey_to_find
)
442 if (subkey_found(lpcurrkey
->nextsub
, lpkey_to_find
))
445 lpcurrkey
= lpcurrkey
->next
;
448 TRACE_(reg
)("No key found in this root key branch\n");
454 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
456 static HKEY
find_root_key(LPKEYSTRUCT lpkey
)
458 typedef struct tagROOT_KEYS
{
462 ROOT_KEYS root_keys
[4];
465 root_keys
[0].lpkey
= key_classes_root
;
466 root_keys
[0].hkey
= HKEY_CLASSES_ROOT
;
467 root_keys
[1].lpkey
= key_current_user
;
468 root_keys
[1].hkey
= HKEY_CURRENT_USER
;
469 root_keys
[2].lpkey
= key_local_machine
;
470 root_keys
[2].hkey
= HKEY_LOCAL_MACHINE
;
471 root_keys
[3].lpkey
= key_users
;
472 root_keys
[3].hkey
= HKEY_USERS
;
476 if (subkey_found(root_keys
[i
].lpkey
, lpkey
))
477 return root_keys
[i
].hkey
;
479 ERR_(reg
)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
484 /* so we don't accidently access them ... */
485 #define key_current_config NULL NULL
486 #define key_current_user NULL NULL
487 #define key_users NULL NULL
488 #define key_local_machine NULL NULL
489 #define key_classes_root NULL NULL
490 #define key_dyn_data NULL NULL
491 #define key_performance_data NULL NULL
493 /******************************************************************************
494 * split_keypath [Internal]
495 * splits the unicode string 'wp' into an array of strings.
496 * the array is allocated by this function.
497 * Free the array using FREE_KEY_PATH
500 * wp [I] String to split up
501 * wpv [O] Array of pointers to strings
502 * wpc [O] Number of components
504 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
509 TRACE_(reg
)("(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
511 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
513 /* We know we have at least one substring */
516 /* Replace each backslash with NULL, and increment the count */
517 for (i
=0;ws
[i
];i
++) {
526 /* Allocate the space for the array of pointers, leaving room for the
528 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
531 /* Assign each pointer to the appropriate character in the string */
536 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
541 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
546 /******************************************************************************
547 * REGISTRY_Init [Internal]
548 * Registry initialisation, allocates some default keys.
550 static void REGISTRY_Init(void) {
554 TRACE_(reg
)("(void)\n");
556 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
559 /* This was an Open, but since it is called before the real registries
560 are loaded, it was changed to a Create - MTB 980507*/
561 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
562 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
565 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
569 * string RegisteredOwner
570 * string RegisteredOrganization
573 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
578 if (-1!=gethostname(buf
,200)) {
579 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
580 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
586 /************************ SAVE Registry Function ****************************/
588 #define REGISTRY_SAVE_VERSION 0x00000001
590 /* Registry saveformat:
591 * If you change it, increase above number by 1, which will flush
592 * old registry database files.
595 * "WINE REGISTRY Version %d"
599 * valuename=lastmodified,type,data
603 * keyname,valuename,stringdata:
604 * the usual ascii characters from 0x00-0xff (well, not 0x00)
605 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
606 * ( "=\\\t" escaped in \uXXXX form.)
610 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
612 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
613 * SaveOnlyUpdatedKeys=yes
616 /******************************************************************************
617 * _save_check_tainted [Internal]
619 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
625 if (lpkey
->flags
& REG_OPTION_TAINTED
)
630 if (_save_check_tainted(lpkey
->nextsub
)) {
631 lpkey
->flags
|= REG_OPTION_TAINTED
;
639 /******************************************************************************
640 * _save_USTRING [Internal]
642 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
656 if (escapeeq
&& *s
=='=')
659 fputc(*s
,F
); /* if \\ then put it twice. */
661 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
668 /******************************************************************************
669 * _savesubkey [Internal]
672 * REG_MULTI_SZ is handled as binary (like in win95) (js)
674 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
681 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
682 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
684 for (tabs
=level
;tabs
--;)
686 _save_USTRING(F
,lpxkey
->keyname
,1);
688 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
689 LPKEYVALUE val
=lpxkey
->values
+i
;
691 for (tabs
=level
+1;tabs
--;)
693 _save_USTRING(F
,val
->name
,0);
695 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
696 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
697 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
699 for (j
=0;j
<val
->len
;j
++)
700 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
703 /* descend recursively */
704 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
713 /******************************************************************************
714 * _savesubreg [Internal]
716 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
718 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
719 _save_check_tainted(lpkey
->nextsub
);
720 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
724 /******************************************************************************
725 * _savereg [Internal]
727 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
733 WARN_(reg
)("Couldn't open %s for writing: %s\n",
738 if (!_savesubreg(F
,lpkey
,all
)) {
741 WARN_(reg
)("Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
749 /******************************************************************************
750 * SHELL_SaveRegistryBranch [Internal]
752 * Saves main registry branch specified by hkey.
754 static void SHELL_SaveRegistryBranch(HKEY hkey
, int all
)
756 char *fn
, *home
, *tmp
;
758 /* Find out what to save to, get from config file */
759 BOOL writeToHome
= PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
760 BOOL writeToAlt
= PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
762 /* FIXME: does this check apply to all keys written below ? */
763 if (!(home
= getenv( "HOME" )))
764 ERR_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
766 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
767 if (hkey
== HKEY_CLASSES_ROOT
) hkey
= HKEY_LOCAL_MACHINE
;
771 case HKEY_CURRENT_USER
:
772 fn
= xmalloc( MAX_PATHNAME_LEN
);
773 if (writeToAlt
&& PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
774 fn
, MAX_PATHNAME_LEN
- 1))
775 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
778 if (home
&& writeToHome
)
780 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
781 strlen(SAVE_CURRENT_USER
) + 2 );
783 strcat(fn
,WINE_PREFIX
);
785 /* create the directory. don't care about errorcodes. */
786 mkdir(fn
,0755); /* drwxr-xr-x */
787 strcat(fn
,"/"SAVE_CURRENT_USER
);
789 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
793 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
794 if (-1==rename(tmp
,fn
)) {
795 perror("rename tmp registry");
803 case HKEY_LOCAL_MACHINE
:
804 /* Try first saving according to the defined location in .winerc */
805 fn
= xmalloc ( MAX_PATHNAME_LEN
);
806 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
807 fn
, MAX_PATHNAME_LEN
- 1))
808 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
811 if (home
&& writeToHome
)
813 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
814 strlen(SAVE_LOCAL_MACHINE
) + 2);
816 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
818 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
822 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
823 if (-1==rename(tmp
,fn
)) {
824 perror("rename tmp registry");
833 fn
= xmalloc( MAX_PATHNAME_LEN
);
834 if (writeToAlt
&& PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
835 fn
, MAX_PATHNAME_LEN
- 1))
836 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
839 if (home
&& writeToHome
)
841 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
842 strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
844 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
846 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
849 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
850 if (-1==rename(tmp
,fn
)) {
851 perror("rename tmp registry");
860 ERR_(reg
)("unknown/invalid key handle !\n");
866 /******************************************************************************
867 * SHELL_SaveRegistry [Internal]
869 void SHELL_SaveRegistry( void )
875 TRACE_(reg
)("(void)\n");
878 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
887 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
892 &len
)) || (type
!=REG_SZ
))
899 if (lstrcmpiA(buf
,"yes"))
902 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER
, all
);
903 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE
, all
);
904 SHELL_SaveRegistryBranch(HKEY_USERS
, all
);
908 /************************ LOAD Registry Function ****************************/
912 /******************************************************************************
913 * _find_or_add_key [Internal]
915 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
917 LPKEYSTRUCT lpxkey
,*lplpkey
;
919 if ((!keyname
) || (keyname
[0]==0)) {
923 lplpkey
= &(lpkey
->nextsub
);
926 if ( tolower(lpxkey
->keyname
[0])==tolower(keyname
[0]) &&
927 !lstrcmpiW(lpxkey
->keyname
,keyname
)
930 lplpkey
= &(lpxkey
->next
);
934 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
936 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
937 lpxkey
->keyname
= keyname
;
943 /******************************************************************************
944 * _find_or_add_value [Internal]
946 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
947 LPBYTE data
, DWORD len
, DWORD lastmodified
)
952 if (name
&& !*name
) {/* empty string equals default (NULL) value */
957 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
963 if ( val
->name
!=NULL
&&
964 tolower(val
->name
[0])==tolower(name
[0]) &&
965 !lstrcmpiW(val
->name
,name
)
970 if (i
==lpkey
->nrofvalues
) {
971 lpkey
->values
= xrealloc(
973 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
976 memset(val
,'\0',sizeof(KEYVALUE
));
982 if (val
->lastmodified
<lastmodified
) {
983 val
->lastmodified
=lastmodified
;
986 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && !data
){
988 data
=xmalloc(sizeof(WCHAR
));
989 memset(data
,0,sizeof(WCHAR
));
1002 /******************************************************************************
1003 * _wine_read_line [Internal]
1005 * reads a line including dynamically enlarging the readbuffer and throwing
1008 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
1018 s
=fgets(curread
,mylen
,F
);
1021 if (NULL
==(s
=strchr(curread
,'\n'))) {
1022 /* buffer wasn't large enough */
1023 curoff
= strlen(*buf
);
1024 *buf
= xrealloc(*buf
,*len
*2);
1025 curread
= *buf
+ curoff
;
1026 mylen
= *len
; /* we filled up the buffer and
1027 * got new '*len' bytes to fill
1035 /* throw away comments */
1036 if (**buf
=='#' || **buf
==';') {
1041 if (s
) /* got end of line */
1048 /******************************************************************************
1049 * _wine_read_USTRING [Internal]
1051 * converts a char* into a UNICODE string (up to a special char)
1052 * and returns the position exactly after that string
1054 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
1059 /* read up to "=" or "\0" or "\n" */
1062 /* empty string is the win3.1 default value(NULL)*/
1066 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
1068 while (*s
&& (*s
!='\n') && (*s
!='=')) {
1070 *ws
++=*((unsigned char*)s
++);
1074 /* Dangling \ ... may only happen if a registry
1075 * write was short. FIXME: What do to?
1085 WARN_(reg
)("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1093 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1094 if (!sscanf(xbuf
,"%x",&wc
))
1095 WARN_(reg
)("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1097 *ws
++ =(unsigned short)wc
;
1104 *str
= strdupW(*str
);
1112 /******************************************************************************
1113 * _wine_loadsubkey [Internal]
1116 * It seems like this is returning a boolean. Should it?
1122 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1123 int *buflen
, DWORD optflag
)
1130 TRACE_(reg
)("(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1133 lpkey
->flags
|= optflag
;
1135 /* Good. We already got a line here ... so parse it */
1145 WARN_(reg
)("Got a subhierarchy without resp. key?\n");
1148 if (!_wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
))
1149 if (!_wine_read_line(F
,buf
,buflen
))
1154 /* let the caller handle this line */
1155 if (i
<level
|| **buf
=='\0')
1158 /* it can be: a value or a keyname. Parse the name first */
1159 s
=_wine_read_USTRING(s
,&name
);
1161 /* switch() default: hack to avoid gotos */
1165 lpxkey
=_find_or_add_key(lpkey
,name
);
1168 int len
,lastmodified
,type
;
1171 WARN_(reg
)("Unexpected character: %c\n",*s
);
1175 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1176 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
1180 s
=strchr(s
,',');s
++;
1183 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
1186 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1187 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1189 len
= lstrlenW((LPWSTR
)data
)*2+2;
1194 data
= (LPBYTE
)xmalloc(len
+1);
1195 for (i
=0;i
<len
;i
++) {
1197 if (*s
>='0' && *s
<='9')
1198 data
[i
]=(*s
-'0')<<4;
1199 if (*s
>='a' && *s
<='f')
1200 data
[i
]=(*s
-'a'+'\xa')<<4;
1201 if (*s
>='A' && *s
<='F')
1202 data
[i
]=(*s
-'A'+'\xa')<<4;
1204 if (*s
>='0' && *s
<='9')
1206 if (*s
>='a' && *s
<='f')
1207 data
[i
]|=*s
-'a'+'\xa';
1208 if (*s
>='A' && *s
<='F')
1209 data
[i
]|=*s
-'A'+'\xa';
1213 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1216 /* read the next line */
1217 if (!_wine_read_line(F
,buf
,buflen
))
1224 /******************************************************************************
1225 * _wine_loadsubreg [Internal]
1227 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1233 buf
=xmalloc(10);buflen
=10;
1234 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1238 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1242 if (ver
!=REGISTRY_SAVE_VERSION
) {
1243 TRACE_(reg
)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1247 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1251 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1260 /******************************************************************************
1261 * _wine_loadreg [Internal]
1263 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1267 TRACE_(reg
)("(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1271 WARN_(reg
)("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1274 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1282 /******************************************************************************
1283 * _flush_registry [Internal]
1285 * This function allow to flush section of the internal registry. It is mainly
1286 * implements to fix a problem with the global HKU and the local HKU.
1287 * Those two files are read to build the HKU\.Default branch to finaly copy
1288 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1289 * all the global HKU are saved onto the user's personal version of HKU hive.
1293 /* Forward declaration of recusive agent */
1294 static void _flush_reg(LPKEYSTRUCT from
);
1296 static void _flush_registry( LPKEYSTRUCT from
)
1298 /* make sure we have something... */
1302 /* Launch the recusive agent on sub branches */
1303 _flush_reg( from
->nextsub
);
1304 _flush_reg( from
->next
);
1306 /* Initialize pointers */
1307 from
->nextsub
= NULL
;
1310 static void _flush_reg( LPKEYSTRUCT from
)
1314 /* make sure we have something... */
1319 * do the same for the child keys
1321 if (from
->nextsub
!= NULL
)
1322 _flush_reg(from
->nextsub
);
1325 * do the same for the sibling keys
1327 if (from
->next
!= NULL
)
1328 _flush_reg(from
->next
);
1331 * iterate through this key's values and delete them
1333 for (j
=0;j
<from
->nrofvalues
;j
++)
1335 free( (from
->values
+j
)->name
);
1336 free( (from
->values
+j
)->data
);
1340 * free the structure
1347 /******************************************************************************
1348 * _copy_registry [Internal]
1350 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1358 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1360 for (j
=0;j
<from
->nrofvalues
;j
++) {
1364 valfrom
= from
->values
+j
;
1366 if (name
) name
=strdupW(name
);
1367 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1368 memcpy(data
,valfrom
->data
,valfrom
->len
);
1376 valfrom
->lastmodified
1379 _copy_registry(from
,lpxkey
);
1385 /* WINDOWS 95 REGISTRY LOADER */
1387 * Structure of a win95 registry database.
1389 * 0 : "CREG" - magic
1391 * 8 : DWORD offset_of_RGDB_part
1392 * 0C..0F: ? (someone fill in please)
1393 * 10: WORD number of RGDB blocks
1395 * 14: WORD always 0000?
1396 * 16: WORD always 0001?
1397 * 18..1F: ? (someone fill in please)
1401 * 0 : "RGKN" - magic
1402 * 4 : DWORD offset to first RGDB section
1403 * 8 : DWORD offset to the root record
1404 * C..0x1B: ? (fill in)
1405 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1407 * Disk Key Entry Structure:
1408 * 00: DWORD - Free entry indicator(?)
1409 * 04: DWORD - Hash = sum of bytes of keyname
1410 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1411 * 0C: DWORD - disk address of PreviousLevel Key.
1412 * 10: DWORD - disk address of Next Sublevel Key.
1413 * 14: DWORD - disk address of Next Key (on same level).
1414 * DKEP>18: WORD - Nr, Low Significant part.
1415 * 1A: WORD - Nr, High Significant part.
1417 * The disk address always points to the nr part of the previous key entry
1418 * of the referenced key. Don't ask me why, or even if I got this correct
1419 * from staring at 1kg of hexdumps. (DKEP)
1421 * The High significant part of the structure seems to equal the number
1422 * of the RGDB section. The low significant part is a unique ID within
1425 * There are two minor corrections to the position of that structure.
1426 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1427 * the DKE reread from there.
1428 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1429 * CPS - I have not experienced the above phenomenon in my registry files
1432 * 00: "RGDB" - magic
1433 * 04: DWORD offset to next RGDB section
1435 * 0C: WORD always 000d?
1436 * 0E: WORD RGDB block number
1437 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1439 * 20.....: disk keys
1442 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1443 * 08: WORD nrLS - low significant part of NR
1444 * 0A: WORD nrHS - high significant part of NR
1445 * 0C: DWORD bytesused - bytes used in this structure.
1446 * 10: WORD name_len - length of name in bytes. without \0
1447 * 12: WORD nr_of_values - number of values.
1448 * 14: char name[name_len] - name string. No \0.
1449 * 14+name_len: disk values
1450 * nextkeyoffset: ... next disk key
1453 * 00: DWORD type - value type (hmm, could be WORD too)
1454 * 04: DWORD - unknown, usually 0
1455 * 08: WORD namelen - length of Name. 0 means name=NULL
1456 * 0C: WORD datalen - length of Data.
1457 * 10: char name[namelen] - name, no \0
1458 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1459 * 10+namelen+datalen: next values or disk key
1461 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1462 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1463 * structure) and reading another RGDB_section.
1464 * repeat until end of file.
1466 * An interesting relationship exists in RGDB_section. The value at offset
1467 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1468 * idea at the moment what this means. (Kevin Cozens)
1470 * FIXME: this description needs some serious help, yes.
1473 struct _w95keyvalue
{
1475 unsigned short datalen
;
1477 unsigned char *data
;
1485 struct _w95keyvalue
*values
;
1486 struct _w95key
*prevlvl
;
1487 struct _w95key
*nextsub
;
1488 struct _w95key
*next
;
1502 /******************************************************************************
1503 * _w95_processKey [Internal]
1505 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1506 int nrLS
, int nrMS
, struct _w95_info
*info
)
1509 /* Disk Key Header structure (RGDB part) */
1511 unsigned long nextkeyoff
;
1512 unsigned short nrLS
;
1513 unsigned short nrMS
;
1514 unsigned long bytesused
;
1515 unsigned short keynamelen
;
1516 unsigned short values
;
1519 /* disk key values or nothing */
1521 /* Disk Key Value structure */
1525 unsigned short valnamelen
;
1526 unsigned short valdatalen
;
1527 /* valname, valdata */
1533 char *rgdbdata
= info
->rgdbbuffer
;
1534 int nbytes
= info
->rgdbsize
;
1535 char *curdata
= rgdbdata
;
1536 char *end
= rgdbdata
+ nbytes
;
1538 char *next
= rgdbdata
;
1544 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1546 memcpy(&off_next_rgdb
,curdata
+4,4);
1547 next
= curdata
+ off_next_rgdb
;
1548 nrgdb
= (int) *((short *)curdata
+ 7);
1550 } while (nrgdb
!= nrMS
&& (next
< end
));
1552 /* curdata now points to the start of the right RGDB section */
1555 #define XREAD(whereto,len) \
1556 if ((curdata + len) <= end) {\
1557 memcpy(whereto,curdata,len);\
1562 while (curdata
< next
) {
1563 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1565 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1566 if (xdkh
->nrLS
== nrLS
) {
1567 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1568 curdata
+= sizeof(dkh
);
1571 curdata
+= xdkh
->nextkeyoff
;
1574 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1576 if (nrgdb
!= dkh
.nrMS
)
1579 assert((dkh
.keynamelen
<2) || curdata
[0]);
1580 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1581 curdata
+= dkh
.keynamelen
;
1583 for (i
=0;i
< dkh
.values
; i
++) {
1589 XREAD(&dkv
,sizeof(dkv
));
1591 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1592 curdata
+= dkv
.valnamelen
;
1594 if ((1 << dkv
.type
) & UNICONVMASK
) {
1595 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1596 len
= 2*(dkv
.valdatalen
+ 1);
1598 /* I don't think we want to NULL terminate all data */
1599 data
= xmalloc(dkv
.valdatalen
);
1600 memcpy (data
, curdata
, dkv
.valdatalen
);
1601 len
= dkv
.valdatalen
;
1604 curdata
+= dkv
.valdatalen
;
1618 /******************************************************************************
1619 * _w95_walkrgkn [Internal]
1621 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1622 struct _w95_info
*info
)
1625 /* Disk Key Entry structure (RGKN part) */
1629 unsigned long x3
;/*usually 0xFFFFFFFF */
1630 unsigned long prevlvl
;
1631 unsigned long nextsub
;
1633 unsigned short nrLS
;
1634 unsigned short nrMS
;
1635 } *dke
= (struct dke
*)off
;
1639 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1642 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1643 /* XXX <-- This is a hack*/
1648 if (dke
->nextsub
!= -1 &&
1649 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1650 && (dke
->nextsub
> 0x20)) {
1652 _w95_walkrgkn(lpxkey
,
1653 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1657 if (dke
->next
!= -1 &&
1658 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1659 (dke
->next
> 0x20)) {
1660 _w95_walkrgkn(prevkey
,
1661 info
->rgknbuffer
+ dke
->next
- 0x20,
1669 /******************************************************************************
1670 * _w95_loadreg [Internal]
1672 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1676 unsigned long where
,version
,rgdbsection
,end
;
1677 struct _w95_info info
;
1679 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1681 TRACE_(reg
)("Loading Win95 registry database '%s'\n",fn
);
1682 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1683 if (hfd
==HFILE_ERROR
)
1686 if (4!=_lread(hfd
,magic
,4))
1688 if (strcmp(magic
,"CREG")) {
1689 WARN_(reg
)("%s is not a w95 registry.\n",fn
);
1692 if (4!=_lread(hfd
,&version
,4))
1694 if (4!=_lread(hfd
,&rgdbsection
,4))
1696 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1698 if (4!=_lread(hfd
,magic
,4))
1700 if (strcmp(magic
,"RGKN")) {
1701 WARN_(reg
)("second IFF header not RGKN, but %s\n", magic
);
1705 /* STEP 1: Keylink structures */
1706 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1711 info
.rgknsize
= end
- where
;
1712 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1713 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1716 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1719 end
= hfdinfo
.nFileSizeLow
;
1720 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1722 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1725 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1726 info
.rgdbsize
= end
- rgdbsection
;
1728 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1732 _w95_walkrgkn(lpkey
, NULL
, &info
);
1734 free (info
.rgdbbuffer
);
1735 free (info
.rgknbuffer
);
1739 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1742 reghack - windows 3.11 registry data format demo program.
1744 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1745 a combined hash table and tree description, and finally a text table.
1747 The header is obvious from the struct header. The taboff1 and taboff2
1748 fields are always 0x20, and their usage is unknown.
1750 The 8-byte entry table has various entry types.
1752 tabent[0] is a root index. The second word has the index of the root of
1754 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1755 the index of the key/value that has that hash. Data with the same
1756 hash value are on a circular list. The other three words in the
1757 hash entry are always zero.
1758 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1759 entry: dirent and keyent/valent. They are identified by context.
1760 tabent[freeidx] is the first free entry. The first word in a free entry
1761 is the index of the next free entry. The last has 0 as a link.
1762 The other three words in the free list are probably irrelevant.
1764 Entries in text table are preceeded by a word at offset-2. This word
1765 has the value (2*index)+1, where index is the referring keyent/valent
1766 entry in the table. I have no suggestion for the 2* and the +1.
1767 Following the word, there are N bytes of data, as per the keyent/valent
1768 entry length. The offset of the keyent/valent entry is from the start
1769 of the text table to the first data byte.
1771 This information is not available from Microsoft. The data format is
1772 deduced from the reg.dat file by me. Mistakes may
1773 have been made. I claim no rights and give no guarantees for this program.
1775 Tor Sjøwall, tor@sn.no
1778 /* reg.dat header format */
1779 struct _w31_header
{
1780 char cookie
[8]; /* 'SHCC3.10' */
1781 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1782 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1783 unsigned long tabcnt
; /* number of entries in index table */
1784 unsigned long textoff
; /* offset of text part */
1785 unsigned long textsize
; /* byte size of text part */
1786 unsigned short hashsize
; /* hash size */
1787 unsigned short freeidx
; /* free index */
1790 /* generic format of table entries */
1791 struct _w31_tabent
{
1792 unsigned short w0
, w1
, w2
, w3
;
1795 /* directory tabent: */
1796 struct _w31_dirent
{
1797 unsigned short sibling_idx
; /* table index of sibling dirent */
1798 unsigned short child_idx
; /* table index of child dirent */
1799 unsigned short key_idx
; /* table index of key keyent */
1800 unsigned short value_idx
; /* table index of value valent */
1804 struct _w31_keyent
{
1805 unsigned short hash_idx
; /* hash chain index for string */
1806 unsigned short refcnt
; /* reference count */
1807 unsigned short length
; /* length of string */
1808 unsigned short string_off
; /* offset of string in text table */
1812 struct _w31_valent
{
1813 unsigned short hash_idx
; /* hash chain index for string */
1814 unsigned short refcnt
; /* reference count */
1815 unsigned short length
; /* length of string */
1816 unsigned short string_off
; /* offset of string in text table */
1819 /* recursive helper function to display a directory tree */
1821 __w31_dumptree( unsigned short idx
,
1823 struct _w31_tabent
*tab
,
1824 struct _w31_header
*head
,
1826 time_t lastmodified
,
1829 struct _w31_dirent
*dir
;
1830 struct _w31_keyent
*key
;
1831 struct _w31_valent
*val
;
1832 LPKEYSTRUCT xlpkey
= NULL
;
1834 static char tail
[400];
1837 dir
=(struct _w31_dirent
*)&tab
[idx
];
1840 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1842 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1843 tail
[key
->length
]='\0';
1844 /* all toplevel entries AND the entries in the
1845 * toplevel subdirectory belong to \SOFTWARE\Classes
1847 if (!level
&& !lstrcmpA(tail
,".classes")) {
1848 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1849 idx
=dir
->sibling_idx
;
1852 name
=strdupA2W(tail
);
1854 xlpkey
=_find_or_add_key(lpkey
,name
);
1856 /* only add if leaf node or valued node */
1857 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1858 if (dir
->value_idx
) {
1859 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1860 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1861 tail
[val
->length
]='\0';
1862 value
=strdupA2W(tail
);
1863 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1867 TRACE_(reg
)("strange: no directory key name, idx=%04x\n", idx
);
1869 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1870 idx
=dir
->sibling_idx
;
1875 /******************************************************************************
1876 * _w31_loadreg [Internal]
1878 void _w31_loadreg(void) {
1880 struct _w31_header head
;
1881 struct _w31_tabent
*tab
;
1885 BY_HANDLE_FILE_INFORMATION hfinfo
;
1886 time_t lastmodified
;
1889 TRACE_(reg
)("(void)\n");
1891 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1892 if (hf
==HFILE_ERROR
)
1895 /* read & dump header */
1896 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1897 ERR_(reg
)("reg.dat is too short.\n");
1901 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1902 ERR_(reg
)("reg.dat has bad signature.\n");
1907 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1908 /* read and dump index table */
1910 if (len
!=_lread(hf
,tab
,len
)) {
1911 ERR_(reg
)("couldn't read %d bytes.\n",len
);
1918 txt
= xmalloc(head
.textsize
);
1919 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1920 ERR_(reg
)("couldn't seek to textblock.\n");
1926 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1927 ERR_(reg
)("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1934 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1935 ERR_(reg
)("GetFileInformationByHandle failed?.\n");
1941 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1942 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1943 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1951 /**********************************************************************************
1952 * SHELL_LoadRegistry [Internal]
1954 void SHELL_LoadRegistry( void )
1957 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1960 TRACE_(reg
)("(void)\n");
1962 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1963 HKU
= lookup_hkey(HKEY_USERS
);
1964 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1966 if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1))
1968 /* Load windows 3.1 entries */
1970 /* Load windows 95 entries */
1971 _w95_loadreg("C:\\system.1st", HKLM
);
1972 _w95_loadreg("system.dat", HKLM
);
1973 _w95_loadreg("user.dat", HKU
);
1976 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1979 * Load the global HKU hive directly from sysconfdir
1981 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1984 * Load the global machine defaults directly form sysconfdir
1986 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1990 * Load the user saved registries
1992 if (!(home
= getenv( "HOME" )))
1993 WARN_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1994 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1997 * Load user's personal versions of global HKU/.Default keys
1999 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
) +
2000 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
2002 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2003 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
2006 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) + strlen(SAVE_CURRENT_USER
)+2);
2008 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
2009 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
2013 * Load HKLM, attempt to get the registry location from the config
2014 * file first, if exist, load and keep going.
2016 fn
=(char*)xmalloc( strlen(home
)+ strlen(WINE_PREFIX
)+ strlen(SAVE_LOCAL_MACHINE
)+2);
2018 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
2019 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
2024 * Load HKCU, get the registry location from the config
2025 * file, if exist, load and keep going.
2027 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
2029 fn
= xmalloc( MAX_PATHNAME_LEN
);
2030 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
2031 fn
, MAX_PATHNAME_LEN
- 1))
2033 _wine_loadreg(HKCU
,fn
,REG_OPTION_TAINTED
);
2037 * Load HKU, get the registry location from the config
2038 * file, if exist, load and keep going.
2040 fn
= xmalloc ( MAX_PATHNAME_LEN
);
2041 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
2042 fn
, MAX_PATHNAME_LEN
- 1))
2044 _wine_loadreg(HKU
,fn
,REG_OPTION_TAINTED
);
2048 * Load HKLM, get the registry location from the config
2049 * file, if exist, load and keep going.
2051 fn
= xmalloc ( MAX_PATHNAME_LEN
);
2052 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
2053 fn
, MAX_PATHNAME_LEN
- 1))
2055 _wine_loadreg(HKLM
,fn
,REG_OPTION_TAINTED
);
2061 * Obtain the handle of the HKU\.Default key.
2062 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2064 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
2065 lpkey
= lookup_hkey(hkey
);
2067 WARN_(reg
)("Could not create global user default key\n");
2069 _copy_registry(lpkey
, HKCU
);
2075 * Since HKU is built from the global HKU and the local user HKU file we must
2076 * flush the HKU tree we have built at this point otherwise the part brought
2077 * in from the global HKU is saved into the local HKU. To avoid this
2078 * useless dupplication of HKU keys we reread the local HKU key.
2081 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2082 _flush_registry(HKU
);
2084 /* Reload user's local HKU hive */
2085 if (home
&& PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
2087 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
)
2088 + strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
2091 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2093 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2099 * Make sure the update mode is there
2101 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2103 DWORD junk
,type
,len
;
2107 if (( RegQueryValueExA(
2113 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2115 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2123 /********************* API FUNCTIONS ***************************************/
2127 * All functions are stubs to RegOpenKeyEx32W where all the
2131 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2132 * RegOpenKey32W -> RegOpenKeyEx32W
2136 /******************************************************************************
2137 * RegOpenKeyEx32W [ADVAPI32.150]
2138 * Opens the specified key
2140 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2143 * hkey [I] Handle of open key
2144 * lpszSubKey [I] Name of subkey to open
2145 * dwReserved [I] Reserved - must be zero
2146 * samDesired [I] Security access mask
2147 * retkey [O] Address of handle of open key
2150 * Success: ERROR_SUCCESS
2151 * Failure: Error code
2153 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2154 REGSAM samDesired
, LPHKEY retkey
)
2156 LPKEYSTRUCT lpNextKey
,lpxkey
;
2160 TRACE_(reg
)("(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2163 lpNextKey
= lookup_hkey( hkey
);
2165 return ERROR_INVALID_HANDLE
;
2167 if (!lpszSubKey
|| !*lpszSubKey
) {
2168 /* Either NULL or pointer to empty string, so return a new handle
2169 to the original hkey */
2171 add_handle(currenthandle
,lpNextKey
,samDesired
);
2172 *retkey
=currenthandle
;
2173 return ERROR_SUCCESS
;
2176 if (lpszSubKey
[0] == '\\') {
2177 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2178 return ERROR_BAD_PATHNAME
;
2181 split_keypath(lpszSubKey
,&wps
,&wpc
);
2183 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2187 lpxkey
=lpNextKey
->nextsub
;
2189 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2192 lpxkey
=lpxkey
->next
;
2196 TRACE_(reg
)("Could not find subkey %s\n",debugstr_w(wps
[i
]));
2198 return ERROR_FILE_NOT_FOUND
;
2205 add_handle(currenthandle
,lpxkey
,samDesired
);
2206 *retkey
= currenthandle
;
2207 TRACE_(reg
)(" Returning %x\n", currenthandle
);
2209 return ERROR_SUCCESS
;
2213 /******************************************************************************
2214 * RegOpenKeyEx32A [ADVAPI32.149]
2216 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2217 REGSAM samDesired
, LPHKEY retkey
)
2219 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2222 TRACE_(reg
)("(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2224 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2230 /******************************************************************************
2231 * RegOpenKey32W [ADVAPI32.151]
2234 * hkey [I] Handle of open key
2235 * lpszSubKey [I] Address of name of subkey to open
2236 * retkey [O] Address of handle of open key
2239 * Success: ERROR_SUCCESS
2240 * Failure: Error code
2242 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2244 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2245 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2249 /******************************************************************************
2250 * RegOpenKey32A [ADVAPI32.148]
2252 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2255 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2256 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2257 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2263 /******************************************************************************
2264 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2266 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2268 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2269 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2276 * All those functions convert their respective
2277 * arguments and call RegCreateKeyExW at the end.
2279 * We stay away from the Ex functions as long as possible because there are
2280 * differences in the return values
2283 * RegCreateKeyEx32A \
2284 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2288 /******************************************************************************
2289 * RegCreateKeyEx32W [ADVAPI32.131]
2292 * hkey [I] Handle of an open key
2293 * lpszSubKey [I] Address of subkey name
2294 * dwReserved [I] Reserved - must be 0
2295 * lpszClass [I] Address of class string
2296 * fdwOptions [I] Special options flag
2297 * samDesired [I] Desired security access
2298 * lpSecAttribs [I] Address of key security structure
2299 * retkey [O] Address of buffer for opened handle
2300 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2302 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2303 DWORD dwReserved
, LPWSTR lpszClass
,
2304 DWORD fdwOptions
, REGSAM samDesired
,
2305 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2306 LPHKEY retkey
, LPDWORD lpDispos
)
2308 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2312 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2313 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2314 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2316 lpNextKey
= lookup_hkey(hkey
);
2318 return ERROR_INVALID_HANDLE
;
2320 /* Check for valid options */
2321 switch(fdwOptions
) {
2322 case REG_OPTION_NON_VOLATILE
:
2323 case REG_OPTION_VOLATILE
:
2324 case REG_OPTION_BACKUP_RESTORE
:
2327 return ERROR_INVALID_PARAMETER
;
2330 /* Sam has to be a combination of the following */
2332 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2333 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2334 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2335 return ERROR_INVALID_PARAMETER
;
2337 if (!lpszSubKey
|| !*lpszSubKey
) {
2339 add_handle(currenthandle
,lpNextKey
,samDesired
);
2340 *retkey
=currenthandle
;
2341 TRACE_(reg
)("Returning %x\n", currenthandle
);
2342 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2343 return ERROR_SUCCESS
;
2346 if (lpszSubKey
[0] == '\\') {
2347 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2348 return ERROR_BAD_PATHNAME
;
2351 split_keypath(lpszSubKey
,&wps
,&wpc
);
2353 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2356 lpxkey
=lpNextKey
->nextsub
;
2358 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2360 lpxkey
=lpxkey
->next
;
2369 add_handle(currenthandle
,lpxkey
,samDesired
);
2370 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2371 *retkey
= currenthandle
;
2372 TRACE_(reg
)("Returning %x\n", currenthandle
);
2374 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2376 return ERROR_SUCCESS
;
2379 /* Good. Now the hard part */
2381 lplpPrevKey
= &(lpNextKey
->nextsub
);
2382 lpxkey
= *lplpPrevKey
;
2384 lplpPrevKey
= &(lpxkey
->next
);
2385 lpxkey
= *lplpPrevKey
;
2387 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2388 if (!*lplpPrevKey
) {
2390 TRACE_(reg
)("Returning OUTOFMEMORY\n");
2391 return ERROR_OUTOFMEMORY
;
2393 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2394 TRACE_(reg
)("Adding %s\n", debugstr_w(wps
[i
]));
2395 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2396 (*lplpPrevKey
)->next
= NULL
;
2397 (*lplpPrevKey
)->nextsub
= NULL
;
2398 (*lplpPrevKey
)->values
= NULL
;
2399 (*lplpPrevKey
)->nrofvalues
= 0;
2400 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2402 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2404 (*lplpPrevKey
)->class = NULL
;
2405 lpNextKey
= *lplpPrevKey
;
2409 add_handle(currenthandle
,lpNextKey
,samDesired
);
2411 /*FIXME: flag handling correct? */
2412 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2414 lpNextKey
->class = strdupW(lpszClass
);
2416 lpNextKey
->class = NULL
;
2417 *retkey
= currenthandle
;
2418 TRACE_(reg
)("Returning %x\n", currenthandle
);
2420 *lpDispos
= REG_CREATED_NEW_KEY
;
2422 return ERROR_SUCCESS
;
2426 /******************************************************************************
2427 * RegCreateKeyEx32A [ADVAPI32.130]
2429 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2430 LPSTR lpszClass
, DWORD fdwOptions
,
2432 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2433 LPHKEY retkey
, LPDWORD lpDispos
)
2435 LPWSTR lpszSubKeyW
, lpszClassW
;
2438 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2439 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2442 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2443 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2445 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2446 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2449 if(lpszSubKeyW
) free(lpszSubKeyW
);
2450 if(lpszClassW
) free(lpszClassW
);
2456 /******************************************************************************
2457 * RegCreateKey32W [ADVAPI32.132]
2459 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2462 LPKEYSTRUCT lpNextKey
;
2464 TRACE_(reg
)("(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2466 /* This check is here because the return value is different than the
2467 one from the Ex functions */
2468 lpNextKey
= lookup_hkey(hkey
);
2470 return ERROR_BADKEY
;
2472 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2473 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2478 /******************************************************************************
2479 * RegCreateKey32A [ADVAPI32.129]
2481 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2486 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2487 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2488 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2489 if(lpszSubKeyW
) free(lpszSubKeyW
);
2494 /******************************************************************************
2495 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2497 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2499 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2500 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2505 * Query Value Functions
2506 * Win32 differs between keynames and valuenames.
2507 * multiple values may belong to one key, the special value
2508 * with name NULL is the default value used by the win31
2512 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2513 * RegQueryValue32W -> RegQueryValueEx32W
2517 /******************************************************************************
2518 * RegQueryValueEx32W [ADVAPI32.158]
2519 * Retrieves type and data for a specified name associated with an open key
2522 * hkey [I] Handle of key to query
2523 * lpValueName [I] Name of value to query
2524 * lpdwReserved [I] Reserved - must be NULL
2525 * lpdwType [O] Address of buffer for value type. If NULL, the type
2527 * lpbData [O] Address of data buffer. If NULL, the actual data is
2529 * lpcbData [I/O] Address of data buffer size
2532 * ERROR_SUCCESS: Success
2533 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2534 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2536 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR lpValueName
,
2537 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2538 LPBYTE lpbData
, LPDWORD lpcbData
)
2544 TRACE_(reg
)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2545 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2547 lpkey
= lookup_hkey(hkey
);
2550 return ERROR_INVALID_HANDLE
;
2552 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2553 return ERROR_INVALID_PARAMETER
;
2555 /* An empty name string is equivalent to NULL */
2556 if (lpValueName
&& !*lpValueName
)
2559 if (lpValueName
==NULL
)
2560 { /* Use key's unnamed or default value, if any */
2561 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2562 if (lpkey
->values
[i
].name
==NULL
)
2566 { /* Search for the key name */
2567 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2568 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2572 if (i
==lpkey
->nrofvalues
)
2573 { TRACE_(reg
)(" Key not found\n");
2574 if (lpValueName
==NULL
)
2575 { /* Empty keyname not found */
2577 { *(WCHAR
*)lpbData
= 0;
2582 TRACE_(reg
)(" Returning an empty string\n");
2583 return ERROR_SUCCESS
;
2585 return ERROR_FILE_NOT_FOUND
;
2588 ret
= ERROR_SUCCESS
;
2590 if (lpdwType
) /* type required ?*/
2591 *lpdwType
= lpkey
->values
[i
].type
;
2593 if (lpbData
) /* data required ?*/
2594 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2595 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2597 *lpcbData
= lpkey
->values
[i
].len
;
2598 ret
= ERROR_MORE_DATA
;
2602 if (lpcbData
) /* size required ?*/
2603 { *lpcbData
= lpkey
->values
[i
].len
;
2606 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2608 TRACE_(reg
)(" (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2614 /******************************************************************************
2615 * RegQueryValue32W [ADVAPI32.159]
2617 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2623 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2624 lpcbData
?*lpcbData
:0);
2626 /* Only open subkey, if we really do descend */
2627 if (lpszSubKey
&& *lpszSubKey
) {
2628 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2629 if (ret
!= ERROR_SUCCESS
) {
2630 WARN_(reg
)("Could not open %s\n", debugstr_w(lpszSubKey
));
2637 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2645 /******************************************************************************
2646 * RegQueryValueEx32A [ADVAPI32.157]
2649 * the documantation is wrong: if the buffer is to small it remains untouched
2651 * FIXME: check returnvalue (len) for an empty key
2653 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2654 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2655 LPBYTE lpbData
, LPDWORD lpcbData
)
2657 LPWSTR lpszValueNameW
;
2658 LPBYTE mybuf
= NULL
;
2659 DWORD ret
, mytype
, mylen
= 0;
2661 TRACE_(reg
)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2662 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2664 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2665 { return ERROR_INVALID_PARAMETER
;
2668 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2670 /* get just the type first */
2671 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2673 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2674 { if(lpszValueNameW
) free(lpszValueNameW
);
2678 if (lpcbData
) /* at least length requested? */
2679 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2680 { if (lpbData
) /* value requested? */
2681 { mylen
= 2*( *lpcbData
);
2682 mybuf
= (LPBYTE
)xmalloc( mylen
);
2685 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2687 if (ret
== ERROR_SUCCESS
)
2689 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2693 *lpcbData
= mylen
/2; /* size is in byte! */
2695 else /* no strings, call it straight */
2696 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2700 if (lpdwType
) /* type when requested */
2701 { *lpdwType
= mytype
;
2704 TRACE_(reg
)(" (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2706 if(mybuf
) free(mybuf
);
2707 if(lpszValueNameW
) free(lpszValueNameW
);
2712 /******************************************************************************
2713 * RegQueryValueEx16 [KERNEL.225]
2715 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2716 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2717 LPBYTE lpbData
, LPDWORD lpcbData
)
2719 TRACE_(reg
)("(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2720 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2721 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2722 lpbData
, lpcbData
);
2726 /******************************************************************************
2727 * RegQueryValue32A [ADVAPI32.156]
2729 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2735 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2736 lpcbData
?*lpcbData
:0);
2738 if (lpszSubKey
&& *lpszSubKey
) {
2739 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2740 if( ret
!= ERROR_SUCCESS
)
2746 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2749 RegCloseKey( xhkey
);
2754 /******************************************************************************
2755 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2758 * Is this HACK still applicable?
2761 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2762 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2765 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2768 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2769 lpcbData
?*lpcbData
:0);
2772 *lpcbData
&= 0xFFFF;
2773 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2778 * Setting values of Registry keys
2781 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2782 * RegSetValue32W -> RegSetValueEx32W
2786 /******************************************************************************
2787 * RegSetValueEx32W [ADVAPI32.170]
2788 * Sets the data and type of a value under a register key
2791 * hkey [I] Handle of key to set value for
2792 * lpszValueName [I] Name of value to set
2793 * dwReserved [I] Reserved - must be zero
2794 * dwType [I] Flag for value type
2795 * lpbData [I] Address of value data
2796 * cbData [I] Size of value data
2799 * Success: ERROR_SUCCESS
2800 * Failure: Error code
2803 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2805 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR lpszValueName
,
2806 DWORD dwReserved
, DWORD dwType
,
2807 CONST BYTE
*lpbData
, DWORD cbData
)
2812 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2813 dwReserved
, dwType
, lpbData
, cbData
);
2815 lpkey
= lookup_hkey( hkey
);
2818 return ERROR_INVALID_HANDLE
;
2820 lpkey
->flags
|= REG_OPTION_TAINTED
;
2822 if (lpszValueName
==NULL
) {
2823 /* Sets type and name for key's unnamed or default value */
2824 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2825 if (lpkey
->values
[i
].name
==NULL
)
2828 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2829 if ( lpkey
->values
[i
].name
&&
2830 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2834 if (i
==lpkey
->nrofvalues
) {
2835 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2837 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2839 lpkey
->nrofvalues
++;
2840 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2842 if (lpkey
->values
[i
].name
==NULL
) {
2844 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2846 lpkey
->values
[i
].name
= NULL
;
2849 if (dwType
== REG_SZ
)
2850 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2852 lpkey
->values
[i
].len
= cbData
;
2853 lpkey
->values
[i
].type
= dwType
;
2854 if (lpkey
->values
[i
].data
!=NULL
)
2855 free(lpkey
->values
[i
].data
);
2856 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2857 lpkey
->values
[i
].lastmodified
= time(NULL
);
2858 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2859 return ERROR_SUCCESS
;
2863 /******************************************************************************
2864 * RegSetValueEx32A [ADVAPI32.169]
2867 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2869 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2870 DWORD dwReserved
, DWORD dwType
,
2871 CONST BYTE
*lpbData
, DWORD cbData
)
2874 LPWSTR lpszValueNameW
;
2878 return (ERROR_INVALID_PARAMETER
);
2880 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2881 dwReserved
,dwType
,lpbData
,cbData
);
2883 if ((1<<dwType
) & UNICONVMASK
)
2884 { if (dwType
== REG_SZ
)
2885 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2887 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2888 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2892 buf
=(LPBYTE
)lpbData
;
2895 lpszValueNameW
= strdupA2W(lpszValueName
);
2897 lpszValueNameW
= NULL
;
2899 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2902 free(lpszValueNameW
);
2911 /******************************************************************************
2912 * RegSetValueEx16 [KERNEL.226]
2914 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2915 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2917 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2918 dwReserved
,dwType
,lpbData
,cbData
);
2919 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2924 /******************************************************************************
2925 * RegSetValue32W [ADVAPI32.171]
2927 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2928 LPCWSTR lpszData
, DWORD cbData
)
2933 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",
2934 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2936 if (lpszSubKey
&& *lpszSubKey
) {
2937 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2938 if (ret
!=ERROR_SUCCESS
)
2942 if (dwType
!=REG_SZ
) {
2943 TRACE_(reg
)("dwType=%ld - Changing to REG_SZ\n",dwType
);
2946 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2947 TRACE_(reg
)("Len=%ld != strlen(%s)+1=%d!\n",
2948 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2950 cbData
=2*lstrlenW(lpszData
)+2;
2952 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2959 /******************************************************************************
2960 * RegSetValue32A [ADVAPI32.168]
2963 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2964 LPCSTR lpszData
, DWORD cbData
)
2969 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2970 if (lpszSubKey
&& *lpszSubKey
) {
2971 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2972 if (ret
!=ERROR_SUCCESS
)
2977 if (dwType
!=REG_SZ
) {
2978 TRACE_(reg
)("dwType=%ld!\n",dwType
);
2981 if (cbData
!=strlen(lpszData
)+1)
2982 cbData
=strlen(lpszData
)+1;
2983 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2990 /******************************************************************************
2991 * RegSetValue16 [KERNEL.221] [SHELL.5]
2993 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2994 LPCSTR lpszData
, DWORD cbData
)
2996 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2997 debugstr_a(lpszData
),cbData
);
2998 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
3006 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
3007 * RegEnumKey32W -> RegEnumKeyEx32W
3011 /******************************************************************************
3012 * RegEnumKeyEx32W [ADVAPI32.139]
3015 * hkey [I] Handle to key to enumerate
3016 * iSubKey [I] Index of subkey to enumerate
3017 * lpszName [O] Buffer for subkey name
3018 * lpcchName [O] Size of subkey buffer
3019 * lpdwReserved [I] Reserved
3020 * lpszClass [O] Buffer for class string
3021 * lpcchClass [O] Size of class buffer
3022 * ft [O] Time key last written to
3024 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3025 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3026 LPWSTR lpszClass
, LPDWORD lpcchClass
,
3029 LPKEYSTRUCT lpkey
,lpxkey
;
3031 TRACE_(reg
)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
3032 lpcchName
,lpcchName
? *lpcchName
: -1,lpdwReserved
,lpszClass
,
3035 lpkey
= lookup_hkey( hkey
);
3037 return ERROR_INVALID_HANDLE
;
3040 return ERROR_INVALID_PARAMETER
;
3042 if (!lpkey
->nextsub
)
3043 return ERROR_NO_MORE_ITEMS
;
3044 lpxkey
=lpkey
->nextsub
;
3046 /* Traverse the subkeys */
3047 while (iSubkey
&& lpxkey
) {
3049 lpxkey
=lpxkey
->next
;
3052 if (iSubkey
|| !lpxkey
)
3053 return ERROR_NO_MORE_ITEMS
;
3054 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
) {
3055 *lpcchName
= lstrlenW(lpxkey
->keyname
);
3056 return ERROR_MORE_DATA
;
3058 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
3059 *lpcchName
= lstrlenW(lpszName
);
3062 /* FIXME: what should we write into it? */
3066 return ERROR_SUCCESS
;
3070 /******************************************************************************
3071 * RegEnumKeyW [ADVAPI32.140]
3073 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3077 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3078 ret
= RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,NULL
);
3080 /* If lpszName is NULL then we have a slightly different behaviour than
3082 if(lpszName
== NULL
&& ret
== ERROR_MORE_DATA
)
3083 ret
= ERROR_SUCCESS
;
3089 /******************************************************************************
3090 * RegEnumKeyEx32A [ADVAPI32.138]
3092 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3093 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3094 LPSTR lpszClass
, LPDWORD lpcchClass
,
3098 LPWSTR lpszNameW
, lpszClassW
;
3100 TRACE_(reg
)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",
3101 hkey
,iSubkey
,lpszName
,lpcchName
,lpcchName
? *lpcchName
: -1,
3102 lpdwReserved
,lpszClass
,lpcchClass
,ft
);
3104 lpszNameW
= lpszName
? (LPWSTR
)xmalloc(*lpcchName
* 2) : NULL
;
3105 lpszClassW
= lpszClass
? (LPWSTR
)xmalloc(*lpcchClass
* 2) : NULL
;
3107 ret
= RegEnumKeyExW(hkey
, iSubkey
, lpszNameW
, lpcchName
, lpdwReserved
,
3108 lpszClassW
, lpcchClass
, ft
);
3110 if (ret
== ERROR_SUCCESS
) {
3111 lstrcpyWtoA(lpszName
,lpszNameW
);
3113 lstrcpyWtoA(lpszClass
,lpszClassW
);
3123 /******************************************************************************
3124 * RegEnumKeyA [ADVAPI32.137]
3126 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3130 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3131 ret
= RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3134 /* If lpszName is NULL then we have a slightly different behaviour than
3136 if(lpszName
== NULL
&& ret
== ERROR_MORE_DATA
)
3137 ret
= ERROR_SUCCESS
;
3143 /******************************************************************************
3144 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3146 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3149 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3150 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3155 * Enumerate Registry Values
3158 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3162 /******************************************************************************
3163 * RegEnumValue32W [ADVAPI32.142]
3166 * hkey [I] Handle to key to query
3167 * iValue [I] Index of value to query
3168 * lpszValue [O] Value string
3169 * lpcchValue [I/O] Size of value buffer (in wchars)
3170 * lpdReserved [I] Reserved
3171 * lpdwType [O] Type code
3172 * lpbData [O] Value data
3173 * lpcbData [I/O] Size of data buffer (in bytes)
3175 * Note: wide character functions that take and/or return "character counts"
3176 * use TCHAR (that is unsigned short or char) not byte counts.
3178 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3179 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3180 LPDWORD lpdwType
, LPBYTE lpbData
,
3186 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3187 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3189 lpkey
= lookup_hkey( hkey
);
3191 if (!lpcbData
&& lpbData
)
3192 return ERROR_INVALID_PARAMETER
;
3195 return ERROR_INVALID_HANDLE
;
3197 if (lpkey
->nrofvalues
<= iValue
)
3198 return ERROR_NO_MORE_ITEMS
;
3200 val
= &(lpkey
->values
[iValue
]);
3203 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3204 *lpcchValue
= lstrlenW(val
->name
)+1;
3205 return ERROR_MORE_DATA
;
3207 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3208 *lpcchValue
=lstrlenW(val
->name
);
3214 /* Can be NULL if the type code is not required */
3216 *lpdwType
= val
->type
;
3219 if (val
->len
>*lpcbData
) {
3220 *lpcbData
= val
->len
;
3221 return ERROR_MORE_DATA
;
3223 memcpy(lpbData
,val
->data
,val
->len
);
3224 *lpcbData
= val
->len
;
3227 debug_print_value ( val
->data
, val
);
3228 return ERROR_SUCCESS
;
3232 /******************************************************************************
3233 * RegEnumValue32A [ADVAPI32.141]
3235 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3236 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3237 LPDWORD lpdwType
, LPBYTE lpbData
,
3242 DWORD ret
,lpcbDataW
;
3245 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3246 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3248 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3250 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3251 lpcbDataW
= *lpcbData
;
3255 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3256 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3261 if (ret
==ERROR_SUCCESS
) {
3262 lstrcpyWtoA(lpszValue
,lpszValueW
);
3264 if ((1<<dwType
) & UNICONVMASK
) {
3265 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3267 if (lpcbDataW
> *lpcbData
) {
3268 *lpcbData
= lpcbDataW
;
3269 ret
= ERROR_MORE_DATA
;
3271 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3273 *lpcbData
= lpcbDataW
;
3276 if (lpbDataW
) free(lpbDataW
);
3277 if (lpszValueW
) free(lpszValueW
);
3282 /******************************************************************************
3283 * RegEnumValue16 [KERNEL.223]
3285 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3286 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3287 LPDWORD lpdwType
, LPBYTE lpbData
,
3290 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3291 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3292 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3293 lpdwType
, lpbData
, lpcbData
);
3297 /******************************************************************************
3298 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3299 * Releases the handle of the specified key
3302 * hkey [I] Handle of key to close
3305 * Success: ERROR_SUCCESS
3306 * Failure: Error code
3308 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3310 TRACE_(reg
)("(%x)\n",hkey
);
3312 /* The standard handles are allowed to succeed, even though they are not
3314 if (is_standard_hkey(hkey
))
3315 return ERROR_SUCCESS
;
3317 return remove_handle(hkey
);
3322 * Delete registry key
3325 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3329 /******************************************************************************
3330 * RegDeleteKey32W [ADVAPI32.134]
3333 * hkey [I] Handle to open key
3334 * lpszSubKey [I] Name of subkey to delete
3337 * Success: ERROR_SUCCESS
3338 * Failure: Error code
3340 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR lpszSubKey
)
3342 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3346 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3348 lpNextKey
= lookup_hkey(hkey
);
3350 return ERROR_INVALID_HANDLE
;
3352 /* Subkey param cannot be NULL */
3353 if (!lpszSubKey
|| !*lpszSubKey
)
3354 return ERROR_BADKEY
;
3356 /* We need to know the previous key in the hier. */
3357 split_keypath(lpszSubKey
,&wps
,&wpc
);
3361 lpxkey
=lpNextKey
->nextsub
;
3363 TRACE_(reg
)(" Scanning [%s]\n",
3364 debugstr_w(lpxkey
->keyname
));
3365 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3367 lpxkey
=lpxkey
->next
;
3371 TRACE_(reg
)(" Not found.\n");
3372 /* not found is success */
3373 return ERROR_SUCCESS
;
3378 lpxkey
= lpNextKey
->nextsub
;
3379 lplpPrevKey
= &(lpNextKey
->nextsub
);
3381 TRACE_(reg
)(" Scanning [%s]\n",
3382 debugstr_w(lpxkey
->keyname
));
3383 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3385 lplpPrevKey
= &(lpxkey
->next
);
3386 lpxkey
= lpxkey
->next
;
3391 WARN_(reg
)(" Not found.\n");
3392 return ERROR_FILE_NOT_FOUND
;
3395 if (lpxkey
->nextsub
) {
3397 WARN_(reg
)(" Not empty.\n");
3398 return ERROR_CANTWRITE
;
3400 *lplpPrevKey
= lpxkey
->next
;
3401 free(lpxkey
->keyname
);
3403 free(lpxkey
->class);
3405 free(lpxkey
->values
);
3408 TRACE_(reg
)(" Done.\n");
3409 return ERROR_SUCCESS
;
3413 /******************************************************************************
3414 * RegDeleteKey32A [ADVAPI32.133]
3416 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3421 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3422 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3423 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3424 if(lpszSubKeyW
) free(lpszSubKeyW
);
3429 /******************************************************************************
3430 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3432 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3434 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3435 return RegDeleteKeyA( hkey
, lpszSubKey
);
3440 * Delete registry value
3443 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3447 /******************************************************************************
3448 * RegDeleteValue32W [ADVAPI32.136]
3456 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR lpszValue
)
3462 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3464 lpkey
= lookup_hkey( hkey
);
3466 return ERROR_INVALID_HANDLE
;
3469 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3470 if ( lpkey
->values
[i
].name
&&
3471 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3475 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3476 if (lpkey
->values
[i
].name
==NULL
)
3480 if (i
== lpkey
->nrofvalues
)
3481 return ERROR_FILE_NOT_FOUND
;
3483 val
= lpkey
->values
+i
;
3484 if (val
->name
) free(val
->name
);
3485 if (val
->data
) free(val
->data
);
3489 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3491 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3493 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3495 lpkey
->nrofvalues
--;
3496 return ERROR_SUCCESS
;
3500 /******************************************************************************
3501 * RegDeleteValue32A [ADVAPI32.135]
3503 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR lpszValue
)
3508 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3509 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3510 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3511 if(lpszValueW
) free(lpszValueW
);
3516 /******************************************************************************
3517 * RegDeleteValue16 [KERNEL.222]
3519 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3521 TRACE_(reg
)("(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3522 return RegDeleteValueA( hkey
, lpszValue
);
3526 /******************************************************************************
3527 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3528 * Immediately writes key to registry.
3529 * Only returns after data has been written to disk.
3531 * FIXME: does it really wait until data is written ?
3533 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3534 * written if this function really works (and only if !).
3537 * hkey [I] Handle of key to write
3540 * Success: ERROR_SUCCESS
3541 * Failure: Error code
3543 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3547 TRACE_(reg
)("(%x)\n", hkey
);
3549 lpkey
= lookup_hkey( hkey
);
3551 return ERROR_BADKEY
;
3553 SHELL_SaveRegistryBranch(find_root_key(lpkey
), TRUE
);
3554 return ERROR_SUCCESS
;
3558 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3561 /******************************************************************************
3562 * RegQueryInfoKey32W [ADVAPI32.153]
3565 * hkey [I] Handle to key to query
3566 * lpszClass [O] Buffer for class string
3567 * lpcchClass [O] Size of class string buffer
3568 * lpdwReserved [I] Reserved
3569 * lpcSubKeys [I] Buffer for number of subkeys
3570 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3571 * lpcchMaxClass [O] Buffer for longest class string length
3572 * lpcValues [O] Buffer for number of value entries
3573 * lpcchMaxValueName [O] Buffer for longest value name length
3574 * lpccbMaxValueData [O] Buffer for longest value data length
3575 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3577 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3578 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3579 * lpcchClass is NULL
3580 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3581 * (it's hard to test validity, so test !NULL instead)
3583 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3584 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3585 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3586 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3587 LPDWORD lpcchMaxValueName
,
3588 LPDWORD lpccbMaxValueData
,
3589 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3591 LPKEYSTRUCT lpkey
,lpxkey
;
3592 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3595 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3596 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3597 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3598 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3600 lpkey
= lookup_hkey(hkey
);
3602 return ERROR_INVALID_HANDLE
;
3604 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3605 return ERROR_INVALID_PARAMETER
;
3607 /* either lpcchClass is valid or this is win95 and lpcchClass
3610 DWORD classLen
= lstrlenW(lpkey
->class);
3612 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3613 *lpcchClass
=classLen
+1;
3614 return ERROR_MORE_DATA
;
3617 *lpcchClass
=classLen
;
3618 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3626 *lpcchClass
= lstrlenW(lpkey
->class);
3628 lpxkey
=lpkey
->nextsub
;
3629 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3632 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3633 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3634 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3635 maxclass
=lstrlenW(lpxkey
->class);
3636 lpxkey
=lpxkey
->next
;
3638 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3639 LPKEYVALUE val
=lpkey
->values
+i
;
3641 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3642 maxvname
=lstrlenW(val
->name
);
3643 if (val
->len
>maxvdata
)
3646 if (!maxclass
) maxclass
= 1;
3647 if (!maxvname
) maxvname
= 1;
3649 *lpcValues
= lpkey
->nrofvalues
;
3651 *lpcSubKeys
= nrofkeys
;
3653 *lpcchMaxSubkey
= maxsubkey
;
3655 *lpcchMaxClass
= maxclass
;
3656 if (lpcchMaxValueName
)
3657 *lpcchMaxValueName
= maxvname
;
3658 if (lpccbMaxValueData
)
3659 *lpccbMaxValueData
= maxvdata
;
3660 return ERROR_SUCCESS
;
3664 /******************************************************************************
3665 * RegQueryInfoKey32A [ADVAPI32.152]
3667 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3668 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3669 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3670 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3671 LPDWORD lpccbMaxValueData
,
3672 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3674 LPWSTR lpszClassW
= NULL
;
3677 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3678 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3679 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3680 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3684 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3685 } else if (VERSION_GetVersion() == WIN95
) {
3686 /* win95 allows lpcchClass to be null */
3687 /* we don't know how big lpszClass is, would
3688 MAX_PATHNAME_LEN be the correct default? */
3689 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3694 ret
=RegQueryInfoKeyW(
3705 lpcbSecurityDescriptor
,
3708 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3709 lstrcpyWtoA(lpszClass
,lpszClassW
);
3716 /******************************************************************************
3717 * RegConnectRegistry32W [ADVAPI32.128]
3720 * lpMachineName [I] Address of name of remote computer
3721 * hHey [I] Predefined registry handle
3722 * phkResult [I] Address of buffer for remote registry handle
3724 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3727 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3729 if (!lpMachineName
|| !*lpMachineName
) {
3730 /* Use the local machine name */
3731 return RegOpenKey16( hKey
, "", phkResult
);
3734 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
3735 return ERROR_BAD_NETPATH
;
3739 /******************************************************************************
3740 * RegConnectRegistry32A [ADVAPI32.127]
3742 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3745 LPWSTR machineW
= strdupA2W(machine
);
3746 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3752 /******************************************************************************
3753 * RegGetKeySecurity [ADVAPI32.144]
3754 * Retrieves a copy of security descriptor protecting the registry key
3757 * hkey [I] Open handle of key to set
3758 * SecurityInformation [I] Descriptor contents
3759 * pSecurityDescriptor [O] Address of descriptor for key
3760 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3763 * Success: ERROR_SUCCESS
3764 * Failure: Error code
3766 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3767 SECURITY_INFORMATION SecurityInformation
,
3768 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3769 LPDWORD lpcbSecurityDescriptor
)
3773 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3774 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3776 lpkey
= lookup_hkey( hkey
);
3778 return ERROR_INVALID_HANDLE
;
3780 /* FIXME: Check for valid SecurityInformation values */
3782 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3783 return ERROR_INSUFFICIENT_BUFFER
;
3785 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3786 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3788 return ERROR_SUCCESS
;
3792 /******************************************************************************
3793 * RegLoadKey32W [ADVAPI32.???]
3796 * hkey [I] Handle of open key
3797 * lpszSubKey [I] Address of name of subkey
3798 * lpszFile [I] Address of filename for registry information
3800 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3803 TRACE_(reg
)("(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3805 /* Do this check before the hkey check */
3806 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3807 return ERROR_INVALID_PARAMETER
;
3809 lpkey
= lookup_hkey( hkey
);
3811 return ERROR_INVALID_HANDLE
;
3813 FIXME_(reg
)("(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3814 debugstr_w(lpszFile
));
3816 return ERROR_SUCCESS
;
3820 /******************************************************************************
3821 * RegLoadKey32A [ADVAPI32.???]
3823 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3826 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3827 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3828 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3829 if(lpszFileW
) free(lpszFileW
);
3830 if(lpszSubKeyW
) free(lpszSubKeyW
);
3835 /******************************************************************************
3836 * RegNotifyChangeKeyValue [ADVAPI32.???]
3839 * hkey [I] Handle of key to watch
3840 * fWatchSubTree [I] Flag for subkey notification
3841 * fdwNotifyFilter [I] Changes to be reported
3842 * hEvent [I] Handle of signaled event
3843 * fAsync [I] Flag for asynchronous reporting
3845 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3846 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3850 TRACE_(reg
)("(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3853 lpkey
= lookup_hkey( hkey
);
3855 return ERROR_INVALID_HANDLE
;
3857 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3860 return ERROR_SUCCESS
;
3864 /******************************************************************************
3865 * RegUnLoadKey32W [ADVAPI32.173]
3868 * hkey [I] Handle of open key
3869 * lpSubKey [I] Address of name of subkey to unload
3871 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3873 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3874 return ERROR_SUCCESS
;
3878 /******************************************************************************
3879 * RegUnLoadKey32A [ADVAPI32.172]
3881 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3884 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3885 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3886 if(lpSubKeyW
) free(lpSubKeyW
);
3891 /******************************************************************************
3892 * RegSetKeySecurity [ADVAPI32.167]
3895 * hkey [I] Open handle of key to set
3896 * SecurityInfo [I] Descriptor contents
3897 * pSecurityDesc [I] Address of descriptor for key
3899 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3900 PSECURITY_DESCRIPTOR pSecurityDesc
)
3904 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3906 /* It seems to perform this check before the hkey check */
3907 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3908 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3909 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3910 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3913 return ERROR_INVALID_PARAMETER
;
3916 return ERROR_INVALID_PARAMETER
;
3918 lpkey
= lookup_hkey( hkey
);
3920 return ERROR_INVALID_HANDLE
;
3922 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3924 return ERROR_SUCCESS
;
3928 /******************************************************************************
3929 * RegSaveKey32W [ADVAPI32.166]
3932 * hkey [I] Handle of key where save begins
3933 * lpFile [I] Address of filename to save to
3934 * sa [I] Address of security structure
3936 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3937 LPSECURITY_ATTRIBUTES sa
)
3941 TRACE_(reg
)("(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3943 /* It appears to do this check before the hkey check */
3944 if (!lpFile
|| !*lpFile
)
3945 return ERROR_INVALID_PARAMETER
;
3947 lpkey
= lookup_hkey( hkey
);
3949 return ERROR_INVALID_HANDLE
;
3951 FIXME_(reg
)("(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3953 return ERROR_SUCCESS
;
3957 /******************************************************************************
3958 * RegSaveKey32A [ADVAPI32.165]
3960 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3961 LPSECURITY_ATTRIBUTES sa
)
3964 LPWSTR lpFileW
= strdupA2W(lpFile
);
3965 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3971 /******************************************************************************
3972 * RegRestoreKey32W [ADVAPI32.164]
3975 * hkey [I] Handle of key where restore begins
3976 * lpFile [I] Address of filename containing saved tree
3977 * dwFlags [I] Optional flags
3979 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3983 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3985 /* It seems to do this check before the hkey check */
3986 if (!lpFile
|| !*lpFile
)
3987 return ERROR_INVALID_PARAMETER
;
3989 lpkey
= lookup_hkey( hkey
);
3991 return ERROR_INVALID_HANDLE
;
3993 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3995 /* Check for file existence */
3997 return ERROR_SUCCESS
;
4001 /******************************************************************************
4002 * RegRestoreKey32A [ADVAPI32.163]
4004 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
4007 LPWSTR lpFileW
= strdupA2W(lpFile
);
4008 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
4009 if(lpFileW
) free(lpFileW
);
4014 /******************************************************************************
4015 * RegReplaceKey32W [ADVAPI32.162]
4018 * hkey [I] Handle of open key
4019 * lpSubKey [I] Address of name of subkey
4020 * lpNewFile [I] Address of filename for file with new data
4021 * lpOldFile [I] Address of filename for backup file
4023 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
4028 TRACE_(reg
)("(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
4029 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
4031 lpkey
= lookup_hkey( hkey
);
4033 return ERROR_INVALID_HANDLE
;
4035 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
4036 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
4038 return ERROR_SUCCESS
;
4042 /******************************************************************************
4043 * RegReplaceKey32A [ADVAPI32.161]
4045 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
4049 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
4050 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
4051 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
4052 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);