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*
27 #ifdef HAVE_SYS_ERRNO_H
28 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
37 #include "wine/winbase16.h"
38 #include "wine/winestring.h"
42 #include "debugtools.h"
46 #include "winversion.h"
48 DECLARE_DEBUG_CHANNEL(reg
)
49 DECLARE_DEBUG_CHANNEL(string
)
51 static void REGISTRY_Init(void);
52 /* FIXME: following defines should be configured global ... */
54 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
55 #define WINE_PREFIX "/.wine"
56 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
57 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
59 /* relative in ~user/.wine/ : */
60 #define SAVE_CURRENT_USER "user.reg"
61 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
62 #define SAVE_LOCAL_MACHINE "system.reg"
64 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
65 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
67 /* one value of a key */
68 typedef struct tagKEYVALUE
70 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
71 DWORD type
; /* type of value */
72 DWORD len
; /* length of data in BYTEs */
73 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
74 LPBYTE data
; /* content, may be strings, binaries, etc. */
75 } KEYVALUE
,*LPKEYVALUE
;
78 typedef struct tagKEYSTRUCT
80 LPWSTR keyname
; /* name of THIS key (UNICODE) */
81 DWORD flags
; /* flags. */
84 DWORD nrofvalues
; /* nr of values in THIS key */
85 LPKEYVALUE values
; /* values in THIS key */
86 /* key management pointers */
87 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
88 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
89 } KEYSTRUCT
, *LPKEYSTRUCT
;
92 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
93 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
94 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
95 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
97 /* dynamic, not saved */
98 static KEYSTRUCT
*key_performance_data
=NULL
;
99 static KEYSTRUCT
*key_current_config
=NULL
;
100 static KEYSTRUCT
*key_dyn_data
=NULL
;
102 /* what valuetypes do we need to convert? */
103 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
106 static struct openhandle
{
111 static int nrofopenhandles
=0;
112 /* Starts after 1 because 0,1 are reserved for Win16 */
113 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
114 HKEYs for remote registry access */
115 static int currenthandle
=2;
120 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
121 * If so, can we remove them?
123 * No, the memory handling functions are called very often in here,
124 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
125 * loading 100 times slower. -MM
127 static LPWSTR
strdupA2W(LPCSTR src
)
130 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
131 lstrcpyAtoW(dest
,src
);
137 static LPWSTR
strdupW(LPCWSTR a
) {
142 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
143 b
=(LPWSTR
)xmalloc(len
);
150 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
153 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
155 lstrcpynAtoW(dest
,src
,nchars
+1);
160 * we need to convert A to W with '\0' in strings (MULTI_SZ)
163 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
166 TRACE_(reg
)("\"%s\" %i\n",src
, n
);
168 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
172 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
175 TRACE_(string
)("L\"%s\" %i\n",debugstr_w(src
), n
);
177 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
182 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
184 if (TRACE_ON(reg
) && lpbData
)
190 TRACE_(reg
)(" Value %s, Data(sz)=%s\n",
191 debugstr_w(key
->name
),
192 debugstr_w((LPCWSTR
)lpbData
));
196 TRACE_(reg
)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key
->name
),
204 LPCWSTR ptr
= (LPCWSTR
)lpbData
;
207 TRACE_(reg
)(" Value %s, MULTI_SZ(%i=%s)\n",
208 debugstr_w(key
->name
),
212 ptr
+= lstrlenW(ptr
)+1;
219 char szTemp
[100]; /* 3*32 + 3 + 1 */
221 for ( i
= 0; i
< key
->len
; i
++)
223 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
226 sprintf (&(szTemp
[i
*3+3]),"...");
230 TRACE_(reg
)(" Value %s, Data(raw)=(%s)\n",
231 debugstr_w(key
->name
),
239 /******************************************************************************
240 * is_standard_hkey [Internal]
241 * Determines if a hkey is a standard key
243 static BOOL
is_standard_hkey( HKEY hkey
)
248 case HKEY_CLASSES_ROOT
:
249 case HKEY_CURRENT_CONFIG
:
250 case HKEY_CURRENT_USER
:
251 case HKEY_LOCAL_MACHINE
:
253 case HKEY_PERFORMANCE_DATA
:
261 /******************************************************************************
262 * add_handle [Internal]
264 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
268 TRACE_(reg
)("(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
269 /* Check for duplicates */
270 for (i
=0;i
<nrofopenhandles
;i
++) {
271 if (openhandles
[i
].lpkey
==lpkey
) {
272 /* This is not really an error - the user is allowed to create
273 two (or more) handles to the same key */
274 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
276 if (openhandles
[i
].hkey
==hkey
) {
277 WARN_(reg
)("Adding handle %x twice\n",hkey
);
280 openhandles
=xrealloc( openhandles
,
281 sizeof(struct openhandle
)*(nrofopenhandles
+1));
283 openhandles
[i
].lpkey
= lpkey
;
284 openhandles
[i
].hkey
= hkey
;
285 openhandles
[i
].accessmask
= accessmask
;
290 /******************************************************************************
291 * get_handle [Internal]
294 * Success: Pointer to key
297 static LPKEYSTRUCT
get_handle( HKEY hkey
)
301 for (i
=0; i
<nrofopenhandles
; i
++)
302 if (openhandles
[i
].hkey
== hkey
)
303 return openhandles
[i
].lpkey
;
304 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
309 /******************************************************************************
310 * remove_handle [Internal]
313 * hkey [I] Handle of key to remove
316 * Success: ERROR_SUCCESS
317 * Failure: ERROR_INVALID_HANDLE
319 static DWORD
remove_handle( HKEY hkey
)
323 for (i
=0;i
<nrofopenhandles
;i
++)
324 if (openhandles
[i
].hkey
==hkey
)
327 if (i
== nrofopenhandles
) {
328 WARN_(reg
)("Could not find handle 0x%x\n",hkey
);
329 return ERROR_INVALID_HANDLE
;
332 memcpy( openhandles
+i
,
334 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
336 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
338 return ERROR_SUCCESS
;
341 /******************************************************************************
342 * lookup_hkey [Internal]
344 * Just as the name says. Creates the root keys on demand, so we can call the
345 * Reg* functions at any time.
348 * Success: Pointer to key structure
351 #define ADD_ROOT_KEY(xx) \
352 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
353 memset(xx,'\0',sizeof(KEYSTRUCT));\
354 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
356 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
359 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
360 * some programs. Do not remove those cases. -MM
364 case HKEY_CLASSES_ROOT
:
366 if (!key_classes_root
)
370 /* calls lookup_hkey recursively, TWICE */
374 &cl_r_hkey
) != ERROR_SUCCESS
)
376 ERR_(reg
)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
380 key_classes_root
= lookup_hkey(cl_r_hkey
);
382 return key_classes_root
;
385 case HKEY_CURRENT_USER
:
386 if (!key_current_user
) {
387 ADD_ROOT_KEY(key_current_user
);
389 return key_current_user
;
391 case HKEY_LOCAL_MACHINE
:
392 if (!key_local_machine
) {
393 ADD_ROOT_KEY(key_local_machine
);
396 return key_local_machine
;
400 ADD_ROOT_KEY(key_users
);
404 case HKEY_PERFORMANCE_DATA
:
405 if (!key_performance_data
) {
406 ADD_ROOT_KEY(key_performance_data
);
408 return key_performance_data
;
412 ADD_ROOT_KEY(key_dyn_data
);
416 case HKEY_CURRENT_CONFIG
:
417 if (!key_current_config
) {
418 ADD_ROOT_KEY(key_current_config
);
420 return key_current_config
;
423 return get_handle(hkey
);
431 * recursively searches for lpkey_to_find in the root key branch
432 * given in lpcurrkey.
434 static int subkey_found(LPKEYSTRUCT lpcurrkey
, LPKEYSTRUCT lpkey_to_find
)
438 if (lpcurrkey
== lpkey_to_find
)
440 if (subkey_found(lpcurrkey
->nextsub
, lpkey_to_find
))
443 lpcurrkey
= lpcurrkey
->next
;
446 TRACE_(reg
)("No key found in this root key branch\n");
452 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
454 static HKEY
find_root_key(LPKEYSTRUCT lpkey
)
456 typedef struct tagROOT_KEYS
{
460 ROOT_KEYS root_keys
[] = { { key_classes_root
, HKEY_CLASSES_ROOT
},
461 { key_current_user
, HKEY_CURRENT_USER
},
462 { key_local_machine
, HKEY_LOCAL_MACHINE
},
463 { key_users
, HKEY_USERS
} };
468 if (subkey_found(root_keys
[i
].lpkey
, lpkey
))
469 return root_keys
[i
].hkey
;
471 ERR_(reg
)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
476 /* so we don't accidently access them ... */
477 #define key_current_config NULL NULL
478 #define key_current_user NULL NULL
479 #define key_users NULL NULL
480 #define key_local_machine NULL NULL
481 #define key_classes_root NULL NULL
482 #define key_dyn_data NULL NULL
483 #define key_performance_data NULL NULL
485 /******************************************************************************
486 * split_keypath [Internal]
487 * splits the unicode string 'wp' into an array of strings.
488 * the array is allocated by this function.
489 * Free the array using FREE_KEY_PATH
492 * wp [I] String to split up
493 * wpv [O] Array of pointers to strings
494 * wpc [O] Number of components
496 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
501 TRACE_(reg
)("(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
503 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
505 /* We know we have at least one substring */
508 /* Replace each backslash with NULL, and increment the count */
509 for (i
=0;ws
[i
];i
++) {
518 /* Allocate the space for the array of pointers, leaving room for the
520 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
523 /* Assign each pointer to the appropriate character in the string */
528 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
533 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
538 /******************************************************************************
539 * REGISTRY_Init [Internal]
540 * Registry initialisation, allocates some default keys.
542 static void REGISTRY_Init(void) {
546 TRACE_(reg
)("(void)\n");
548 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
551 /* This was an Open, but since it is called before the real registries
552 are loaded, it was changed to a Create - MTB 980507*/
553 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
554 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
557 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
561 * string RegisteredOwner
562 * string RegisteredOrganization
565 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
570 if (-1!=gethostname(buf
,200)) {
571 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
572 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
578 /************************ SAVE Registry Function ****************************/
580 #define REGISTRY_SAVE_VERSION 0x00000001
582 /* Registry saveformat:
583 * If you change it, increase above number by 1, which will flush
584 * old registry database files.
587 * "WINE REGISTRY Version %d"
591 * valuename=lastmodified,type,data
595 * keyname,valuename,stringdata:
596 * the usual ascii characters from 0x00-0xff (well, not 0x00)
597 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
598 * ( "=\\\t" escaped in \uXXXX form.)
602 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
604 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
605 * SaveOnlyUpdatedKeys=yes
608 /******************************************************************************
609 * _save_check_tainted [Internal]
611 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
617 if (lpkey
->flags
& REG_OPTION_TAINTED
)
622 if (_save_check_tainted(lpkey
->nextsub
)) {
623 lpkey
->flags
|= REG_OPTION_TAINTED
;
631 /******************************************************************************
632 * _save_USTRING [Internal]
634 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
648 if (escapeeq
&& *s
=='=')
651 fputc(*s
,F
); /* if \\ then put it twice. */
653 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
660 /******************************************************************************
661 * _savesubkey [Internal]
664 * REG_MULTI_SZ is handled as binary (like in win95) (js)
666 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
673 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
674 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
676 for (tabs
=level
;tabs
--;)
678 _save_USTRING(F
,lpxkey
->keyname
,1);
680 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
681 LPKEYVALUE val
=lpxkey
->values
+i
;
683 for (tabs
=level
+1;tabs
--;)
685 _save_USTRING(F
,val
->name
,0);
687 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
688 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
689 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
691 for (j
=0;j
<val
->len
;j
++)
692 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
695 /* descend recursively */
696 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
705 /******************************************************************************
706 * _savesubreg [Internal]
708 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
710 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
711 _save_check_tainted(lpkey
->nextsub
);
712 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
716 /******************************************************************************
717 * _savereg [Internal]
719 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
725 WARN_(reg
)("Couldn't open %s for writing: %s\n",
730 if (!_savesubreg(F
,lpkey
,all
)) {
733 WARN_(reg
)("Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
741 /******************************************************************************
742 * SHELL_SaveRegistryBranch [Internal]
744 * Saves main registry branch specified by hkey.
746 static void SHELL_SaveRegistryBranch(HKEY hkey
, int all
)
748 char *fn
, *home
, *tmp
;
750 /* FIXME: does this check apply to all keys written below ? */
751 if (!(home
= getenv( "HOME" )))
753 ERR_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
757 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
758 if (hkey
== HKEY_CLASSES_ROOT
)
759 hkey
= HKEY_LOCAL_MACHINE
;
763 case HKEY_CURRENT_USER
:
767 fn
= xmalloc( MAX_PATHNAME_LEN
);
768 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "",
769 fn
, MAX_PATHNAME_LEN
- 1))
771 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
776 if (usedCfgUser
!= 1)
778 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
779 strlen(SAVE_CURRENT_USER
) + 2 );
781 strcat(fn
,WINE_PREFIX
);
783 /* create the directory. don't care about errorcodes. */
784 mkdir(fn
,0755); /* drwxr-xr-x */
785 strcat(fn
,"/"SAVE_CURRENT_USER
);
787 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
791 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
792 if (-1==rename(tmp
,fn
)) {
793 perror("rename tmp registry");
802 case HKEY_LOCAL_MACHINE
:
805 /* Try first saving according to the defined location in .winerc */
806 fn
= xmalloc ( MAX_PATHNAME_LEN
);
807 if (PROFILE_GetWineIniString ( "Registry",
808 "LocalMachineFileName", "", fn
, MAX_PATHNAME_LEN
- 1))
810 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
817 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
818 strlen(SAVE_LOCAL_MACHINE
) + 2);
820 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
822 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
826 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
827 if (-1==rename(tmp
,fn
)) {
828 perror("rename tmp registry");
838 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
) +
839 strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
842 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
844 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
845 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
846 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
847 if (-1==rename(tmp
,fn
)) {
848 perror("rename tmp registry");
856 ERR_(reg
)("unknown/invalid key handle !\n");
861 /******************************************************************************
862 * SHELL_SaveRegistry [Internal]
864 void SHELL_SaveRegistry( void )
870 TRACE_(reg
)("(void)\n");
873 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
882 if ((ERROR_SUCCESS
!=RegQueryValueExA( hkey
,
887 &len
)) || (type
!=REG_SZ
))
894 if (lstrcmpiA(buf
,"yes"))
897 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER
, all
);
898 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE
, all
);
899 SHELL_SaveRegistryBranch(HKEY_USERS
, all
);
903 /************************ LOAD Registry Function ****************************/
907 /******************************************************************************
908 * _find_or_add_key [Internal]
910 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
912 LPKEYSTRUCT lpxkey
,*lplpkey
;
914 if ((!keyname
) || (keyname
[0]==0)) {
918 lplpkey
= &(lpkey
->nextsub
);
921 if ( tolower(lpxkey
->keyname
[0])==tolower(keyname
[0]) &&
922 !lstrcmpiW(lpxkey
->keyname
,keyname
)
925 lplpkey
= &(lpxkey
->next
);
929 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
931 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
932 lpxkey
->keyname
= keyname
;
938 /******************************************************************************
939 * _find_or_add_value [Internal]
941 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
942 LPBYTE data
, DWORD len
, DWORD lastmodified
)
947 if (name
&& !*name
) {/* empty string equals default (NULL) value */
952 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
958 if ( val
->name
!=NULL
&&
959 tolower(val
->name
[0])==tolower(name
[0]) &&
960 !lstrcmpiW(val
->name
,name
)
965 if (i
==lpkey
->nrofvalues
) {
966 lpkey
->values
= xrealloc(
968 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
971 memset(val
,'\0',sizeof(KEYVALUE
));
977 if (val
->lastmodified
<lastmodified
) {
978 val
->lastmodified
=lastmodified
;
981 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && !data
){
983 data
=xmalloc(sizeof(WCHAR
));
984 memset(data
,0,sizeof(WCHAR
));
997 /******************************************************************************
998 * _wine_read_line [Internal]
1000 * reads a line including dynamically enlarging the readbuffer and throwing
1003 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
1013 s
=fgets(curread
,mylen
,F
);
1016 if (NULL
==(s
=strchr(curread
,'\n'))) {
1017 /* buffer wasn't large enough */
1018 curoff
= strlen(*buf
);
1019 *buf
= xrealloc(*buf
,*len
*2);
1020 curread
= *buf
+ curoff
;
1021 mylen
= *len
; /* we filled up the buffer and
1022 * got new '*len' bytes to fill
1030 /* throw away comments */
1031 if (**buf
=='#' || **buf
==';') {
1036 if (s
) /* got end of line */
1043 /******************************************************************************
1044 * _wine_read_USTRING [Internal]
1046 * converts a char* into a UNICODE string (up to a special char)
1047 * and returns the position exactly after that string
1049 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
1054 /* read up to "=" or "\0" or "\n" */
1057 /* empty string is the win3.1 default value(NULL)*/
1061 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
1063 while (*s
&& (*s
!='\n') && (*s
!='=')) {
1065 *ws
++=*((unsigned char*)s
++);
1069 /* Dangling \ ... may only happen if a registry
1070 * write was short. FIXME: What do to?
1080 WARN_(reg
)("Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1088 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1089 if (!sscanf(xbuf
,"%x",&wc
))
1090 WARN_(reg
)("Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1092 *ws
++ =(unsigned short)wc
;
1099 *str
= strdupW(*str
);
1107 /******************************************************************************
1108 * _wine_loadsubkey [Internal]
1111 * It seems like this is returning a boolean. Should it?
1117 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1118 int *buflen
, DWORD optflag
)
1125 TRACE_(reg
)("(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1128 lpkey
->flags
|= optflag
;
1130 /* Good. We already got a line here ... so parse it */
1140 WARN_(reg
)("Got a subhierarchy without resp. key?\n");
1143 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1147 /* let the caller handle this line */
1148 if (i
<level
|| **buf
=='\0')
1151 /* it can be: a value or a keyname. Parse the name first */
1152 s
=_wine_read_USTRING(s
,&name
);
1154 /* switch() default: hack to avoid gotos */
1158 lpxkey
=_find_or_add_key(lpkey
,name
);
1161 int len
,lastmodified
,type
;
1164 WARN_(reg
)("Unexpected character: %c\n",*s
);
1168 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1169 WARN_(reg
)("Haven't understood possible value in |%s|, skipping.\n",*buf
);
1173 s
=strchr(s
,',');s
++;
1174 s
=strchr(s
,',');s
++;
1175 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1176 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1178 len
= lstrlenW((LPWSTR
)data
)*2+2;
1183 data
= (LPBYTE
)xmalloc(len
+1);
1184 for (i
=0;i
<len
;i
++) {
1186 if (*s
>='0' && *s
<='9')
1187 data
[i
]=(*s
-'0')<<4;
1188 if (*s
>='a' && *s
<='f')
1189 data
[i
]=(*s
-'a'+'\xa')<<4;
1190 if (*s
>='A' && *s
<='F')
1191 data
[i
]=(*s
-'A'+'\xa')<<4;
1193 if (*s
>='0' && *s
<='9')
1195 if (*s
>='a' && *s
<='f')
1196 data
[i
]|=*s
-'a'+'\xa';
1197 if (*s
>='A' && *s
<='F')
1198 data
[i
]|=*s
-'A'+'\xa';
1202 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1205 /* read the next line */
1206 if (!_wine_read_line(F
,buf
,buflen
))
1213 /******************************************************************************
1214 * _wine_loadsubreg [Internal]
1216 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1222 buf
=xmalloc(10);buflen
=10;
1223 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1227 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1231 if (ver
!=REGISTRY_SAVE_VERSION
) {
1232 TRACE_(reg
)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1236 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1240 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1249 /******************************************************************************
1250 * _wine_loadreg [Internal]
1252 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1256 TRACE_(reg
)("(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1260 WARN_(reg
)("Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1263 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1271 /******************************************************************************
1272 * _flush_registry [Internal]
1274 * This function allow to flush section of the internal registry. It is mainly
1275 * implements to fix a problem with the global HKU and the local HKU.
1276 * Those two files are read to build the HKU\.Default branch to finaly copy
1277 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1278 * all the global HKU are saved onto the user's personal version of HKU hive.
1282 /* Forward declaration of recusive agent */
1283 static void _flush_reg(LPKEYSTRUCT from
);
1285 static void _flush_registry( LPKEYSTRUCT from
)
1287 /* make sure we have something... */
1291 /* Launch the recusive agent on sub branches */
1292 _flush_reg( from
->nextsub
);
1293 _flush_reg( from
->next
);
1295 /* Initialize pointers */
1296 from
->nextsub
= NULL
;
1299 static void _flush_reg( LPKEYSTRUCT from
)
1303 /* make sure we have something... */
1308 * do the same for the child keys
1310 if (from
->nextsub
!= NULL
)
1311 _flush_reg(from
->nextsub
);
1314 * do the same for the sibling keys
1316 if (from
->next
!= NULL
)
1317 _flush_reg(from
->next
);
1320 * iterate through this key's values and delete them
1322 for (j
=0;j
<from
->nrofvalues
;j
++)
1324 free( (from
->values
+j
)->name
);
1325 free( (from
->values
+j
)->data
);
1329 * free the structure
1336 /******************************************************************************
1337 * _copy_registry [Internal]
1339 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1347 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1349 for (j
=0;j
<from
->nrofvalues
;j
++) {
1353 valfrom
= from
->values
+j
;
1355 if (name
) name
=strdupW(name
);
1356 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1357 memcpy(data
,valfrom
->data
,valfrom
->len
);
1365 valfrom
->lastmodified
1368 _copy_registry(from
,lpxkey
);
1374 /* WINDOWS 95 REGISTRY LOADER */
1376 * Structure of a win95 registry database.
1378 * 0 : "CREG" - magic
1380 * 8 : DWORD offset_of_RGDB_part
1381 * 0C..0F: ? (someone fill in please)
1382 * 10: WORD number of RGDB blocks
1384 * 14: WORD always 0000?
1385 * 16: WORD always 0001?
1386 * 18..1F: ? (someone fill in please)
1390 * 0 : "RGKN" - magic
1391 * 4 : DWORD offset to first RGDB section
1392 * 8 : DWORD offset to the root record
1393 * C..0x1B: ? (fill in)
1394 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1396 * Disk Key Entry Structure:
1397 * 00: DWORD - Free entry indicator(?)
1398 * 04: DWORD - Hash = sum of bytes of keyname
1399 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1400 * 0C: DWORD - disk address of PreviousLevel Key.
1401 * 10: DWORD - disk address of Next Sublevel Key.
1402 * 14: DWORD - disk address of Next Key (on same level).
1403 * DKEP>18: WORD - Nr, Low Significant part.
1404 * 1A: WORD - Nr, High Significant part.
1406 * The disk address always points to the nr part of the previous key entry
1407 * of the referenced key. Don't ask me why, or even if I got this correct
1408 * from staring at 1kg of hexdumps. (DKEP)
1410 * The High significant part of the structure seems to equal the number
1411 * of the RGDB section. The low significant part is a unique ID within
1414 * There are two minor corrections to the position of that structure.
1415 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1416 * the DKE reread from there.
1417 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1418 * CPS - I have not experienced the above phenomenon in my registry files
1421 * 00: "RGDB" - magic
1422 * 04: DWORD offset to next RGDB section
1424 * 0C: WORD always 000d?
1425 * 0E: WORD RGDB block number
1426 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1428 * 20.....: disk keys
1431 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1432 * 08: WORD nrLS - low significant part of NR
1433 * 0A: WORD nrHS - high significant part of NR
1434 * 0C: DWORD bytesused - bytes used in this structure.
1435 * 10: WORD name_len - length of name in bytes. without \0
1436 * 12: WORD nr_of_values - number of values.
1437 * 14: char name[name_len] - name string. No \0.
1438 * 14+name_len: disk values
1439 * nextkeyoffset: ... next disk key
1442 * 00: DWORD type - value type (hmm, could be WORD too)
1443 * 04: DWORD - unknown, usually 0
1444 * 08: WORD namelen - length of Name. 0 means name=NULL
1445 * 0C: WORD datalen - length of Data.
1446 * 10: char name[namelen] - name, no \0
1447 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1448 * 10+namelen+datalen: next values or disk key
1450 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1451 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1452 * structure) and reading another RGDB_section.
1453 * repeat until end of file.
1455 * An interesting relationship exists in RGDB_section. The value at offset
1456 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1457 * idea at the moment what this means. (Kevin Cozens)
1459 * FIXME: this description needs some serious help, yes.
1462 struct _w95keyvalue
{
1464 unsigned short datalen
;
1466 unsigned char *data
;
1474 struct _w95keyvalue
*values
;
1475 struct _w95key
*prevlvl
;
1476 struct _w95key
*nextsub
;
1477 struct _w95key
*next
;
1491 /******************************************************************************
1492 * _w95_processKey [Internal]
1494 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1495 int nrLS
, int nrMS
, struct _w95_info
*info
)
1498 /* Disk Key Header structure (RGDB part) */
1500 unsigned long nextkeyoff
;
1501 unsigned short nrLS
;
1502 unsigned short nrMS
;
1503 unsigned long bytesused
;
1504 unsigned short keynamelen
;
1505 unsigned short values
;
1508 /* disk key values or nothing */
1510 /* Disk Key Value structure */
1514 unsigned short valnamelen
;
1515 unsigned short valdatalen
;
1516 /* valname, valdata */
1522 char *rgdbdata
= info
->rgdbbuffer
;
1523 int nbytes
= info
->rgdbsize
;
1524 char *curdata
= rgdbdata
;
1525 char *end
= rgdbdata
+ nbytes
;
1527 char *next
= rgdbdata
;
1533 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1535 memcpy(&off_next_rgdb
,curdata
+4,4);
1536 next
= curdata
+ off_next_rgdb
;
1537 nrgdb
= (int) *((short *)curdata
+ 7);
1539 } while (nrgdb
!= nrMS
&& (next
< end
));
1541 /* curdata now points to the start of the right RGDB section */
1544 #define XREAD(whereto,len) \
1545 if ((curdata + len) <= end) {\
1546 memcpy(whereto,curdata,len);\
1551 while (curdata
< next
) {
1552 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1554 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1555 if (xdkh
->nrLS
== nrLS
) {
1556 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1557 curdata
+= sizeof(dkh
);
1560 curdata
+= xdkh
->nextkeyoff
;
1563 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1565 if (nrgdb
!= dkh
.nrMS
)
1568 assert((dkh
.keynamelen
<2) || curdata
[0]);
1569 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1570 curdata
+= dkh
.keynamelen
;
1572 for (i
=0;i
< dkh
.values
; i
++) {
1578 XREAD(&dkv
,sizeof(dkv
));
1580 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1581 curdata
+= dkv
.valnamelen
;
1583 if ((1 << dkv
.type
) & UNICONVMASK
) {
1584 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1585 len
= 2*(dkv
.valdatalen
+ 1);
1587 /* I don't think we want to NULL terminate all data */
1588 data
= xmalloc(dkv
.valdatalen
);
1589 memcpy (data
, curdata
, dkv
.valdatalen
);
1590 len
= dkv
.valdatalen
;
1593 curdata
+= dkv
.valdatalen
;
1607 /******************************************************************************
1608 * _w95_walkrgkn [Internal]
1610 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1611 struct _w95_info
*info
)
1614 /* Disk Key Entry structure (RGKN part) */
1618 unsigned long x3
;/*usually 0xFFFFFFFF */
1619 unsigned long prevlvl
;
1620 unsigned long nextsub
;
1622 unsigned short nrLS
;
1623 unsigned short nrMS
;
1624 } *dke
= (struct dke
*)off
;
1628 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1631 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1632 /* XXX <-- This is a hack*/
1637 if (dke
->nextsub
!= -1 &&
1638 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1639 && (dke
->nextsub
> 0x20)) {
1641 _w95_walkrgkn(lpxkey
,
1642 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1646 if (dke
->next
!= -1 &&
1647 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1648 (dke
->next
> 0x20)) {
1649 _w95_walkrgkn(prevkey
,
1650 info
->rgknbuffer
+ dke
->next
- 0x20,
1658 /******************************************************************************
1659 * _w95_loadreg [Internal]
1661 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1665 unsigned long where
,version
,rgdbsection
,end
;
1666 struct _w95_info info
;
1668 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1670 TRACE_(reg
)("Loading Win95 registry database '%s'\n",fn
);
1671 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1672 if (hfd
==HFILE_ERROR
)
1675 if (4!=_lread(hfd
,magic
,4))
1677 if (strcmp(magic
,"CREG")) {
1678 WARN_(reg
)("%s is not a w95 registry.\n",fn
);
1681 if (4!=_lread(hfd
,&version
,4))
1683 if (4!=_lread(hfd
,&rgdbsection
,4))
1685 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1687 if (4!=_lread(hfd
,magic
,4))
1689 if (strcmp(magic
,"RGKN")) {
1690 WARN_(reg
)("second IFF header not RGKN, but %s\n", magic
);
1694 /* STEP 1: Keylink structures */
1695 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1700 info
.rgknsize
= end
- where
;
1701 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1702 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1705 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1708 end
= hfdinfo
.nFileSizeLow
;
1709 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1711 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1714 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1715 info
.rgdbsize
= end
- rgdbsection
;
1717 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1721 _w95_walkrgkn(lpkey
, NULL
, &info
);
1723 free (info
.rgdbbuffer
);
1724 free (info
.rgknbuffer
);
1728 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1731 reghack - windows 3.11 registry data format demo program.
1733 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1734 a combined hash table and tree description, and finally a text table.
1736 The header is obvious from the struct header. The taboff1 and taboff2
1737 fields are always 0x20, and their usage is unknown.
1739 The 8-byte entry table has various entry types.
1741 tabent[0] is a root index. The second word has the index of the root of
1743 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1744 the index of the key/value that has that hash. Data with the same
1745 hash value are on a circular list. The other three words in the
1746 hash entry are always zero.
1747 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1748 entry: dirent and keyent/valent. They are identified by context.
1749 tabent[freeidx] is the first free entry. The first word in a free entry
1750 is the index of the next free entry. The last has 0 as a link.
1751 The other three words in the free list are probably irrelevant.
1753 Entries in text table are preceeded by a word at offset-2. This word
1754 has the value (2*index)+1, where index is the referring keyent/valent
1755 entry in the table. I have no suggestion for the 2* and the +1.
1756 Following the word, there are N bytes of data, as per the keyent/valent
1757 entry length. The offset of the keyent/valent entry is from the start
1758 of the text table to the first data byte.
1760 This information is not available from Microsoft. The data format is
1761 deduced from the reg.dat file by me. Mistakes may
1762 have been made. I claim no rights and give no guarantees for this program.
1764 Tor Sjøwall, tor@sn.no
1767 /* reg.dat header format */
1768 struct _w31_header
{
1769 char cookie
[8]; /* 'SHCC3.10' */
1770 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1771 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1772 unsigned long tabcnt
; /* number of entries in index table */
1773 unsigned long textoff
; /* offset of text part */
1774 unsigned long textsize
; /* byte size of text part */
1775 unsigned short hashsize
; /* hash size */
1776 unsigned short freeidx
; /* free index */
1779 /* generic format of table entries */
1780 struct _w31_tabent
{
1781 unsigned short w0
, w1
, w2
, w3
;
1784 /* directory tabent: */
1785 struct _w31_dirent
{
1786 unsigned short sibling_idx
; /* table index of sibling dirent */
1787 unsigned short child_idx
; /* table index of child dirent */
1788 unsigned short key_idx
; /* table index of key keyent */
1789 unsigned short value_idx
; /* table index of value valent */
1793 struct _w31_keyent
{
1794 unsigned short hash_idx
; /* hash chain index for string */
1795 unsigned short refcnt
; /* reference count */
1796 unsigned short length
; /* length of string */
1797 unsigned short string_off
; /* offset of string in text table */
1801 struct _w31_valent
{
1802 unsigned short hash_idx
; /* hash chain index for string */
1803 unsigned short refcnt
; /* reference count */
1804 unsigned short length
; /* length of string */
1805 unsigned short string_off
; /* offset of string in text table */
1808 /* recursive helper function to display a directory tree */
1810 __w31_dumptree( unsigned short idx
,
1812 struct _w31_tabent
*tab
,
1813 struct _w31_header
*head
,
1815 time_t lastmodified
,
1818 struct _w31_dirent
*dir
;
1819 struct _w31_keyent
*key
;
1820 struct _w31_valent
*val
;
1821 LPKEYSTRUCT xlpkey
= NULL
;
1823 static char tail
[400];
1826 dir
=(struct _w31_dirent
*)&tab
[idx
];
1829 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1831 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1832 tail
[key
->length
]='\0';
1833 /* all toplevel entries AND the entries in the
1834 * toplevel subdirectory belong to \SOFTWARE\Classes
1836 if (!level
&& !lstrcmpA(tail
,".classes")) {
1837 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1838 idx
=dir
->sibling_idx
;
1841 name
=strdupA2W(tail
);
1843 xlpkey
=_find_or_add_key(lpkey
,name
);
1845 /* only add if leaf node or valued node */
1846 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1847 if (dir
->value_idx
) {
1848 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1849 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1850 tail
[val
->length
]='\0';
1851 value
=strdupA2W(tail
);
1852 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1856 TRACE_(reg
)("strange: no directory key name, idx=%04x\n", idx
);
1858 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1859 idx
=dir
->sibling_idx
;
1864 /******************************************************************************
1865 * _w31_loadreg [Internal]
1867 void _w31_loadreg(void) {
1869 struct _w31_header head
;
1870 struct _w31_tabent
*tab
;
1874 BY_HANDLE_FILE_INFORMATION hfinfo
;
1875 time_t lastmodified
;
1878 TRACE_(reg
)("(void)\n");
1880 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1881 if (hf
==HFILE_ERROR
)
1884 /* read & dump header */
1885 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1886 ERR_(reg
)("reg.dat is too short.\n");
1890 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1891 ERR_(reg
)("reg.dat has bad signature.\n");
1896 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1897 /* read and dump index table */
1899 if (len
!=_lread(hf
,tab
,len
)) {
1900 ERR_(reg
)("couldn't read %d bytes.\n",len
);
1907 txt
= xmalloc(head
.textsize
);
1908 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1909 ERR_(reg
)("couldn't seek to textblock.\n");
1915 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1916 ERR_(reg
)("textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1923 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1924 ERR_(reg
)("GetFileInformationByHandle failed?.\n");
1930 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1931 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1932 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1940 /**********************************************************************************
1941 * SHELL_LoadRegistry [Internal]
1943 void SHELL_LoadRegistry( void )
1946 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1949 TRACE_(reg
)("(void)\n");
1951 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1952 HKU
= lookup_hkey(HKEY_USERS
);
1953 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1955 /* Load windows 3.1 entries */
1957 /* Load windows 95 entries */
1958 _w95_loadreg("C:\\system.1st", HKLM
);
1959 _w95_loadreg("system.dat", HKLM
);
1960 _w95_loadreg("user.dat", HKU
);
1963 * Load the global HKU hive directly from sysconfdir
1965 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1968 * Load the global machine defaults directly form sysconfdir
1970 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1973 * Load the user saved registries
1975 if ((home
= getenv( "HOME" )))
1978 * Load user's personal versions of global HKU/.Default keys
1982 strlen(WINE_PREFIX
)+
1983 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1986 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1987 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1991 * Load HKCU, attempt to get the registry location from the config
1992 * file first, if exist, load and keep going.
1994 fn
= xmalloc( MAX_PATHNAME_LEN
);
1995 if ( PROFILE_GetWineIniString(
2000 MAX_PATHNAME_LEN
- 1))
2002 _wine_loadreg(HKCU
,fn
,0);
2008 strlen(WINE_PREFIX
)+
2009 strlen(SAVE_CURRENT_USER
)+2);
2012 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
2013 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
2017 * Load HKLM, attempt to get the registry location from the config
2018 * file first, if exist, load and keep going.
2020 fn
= xmalloc ( MAX_PATHNAME_LEN
);
2021 if ( PROFILE_GetWineIniString(
2023 "LocalMachineFileName",
2026 MAX_PATHNAME_LEN
- 1))
2028 _wine_loadreg(HKLM
, fn
, 0);
2034 strlen(WINE_PREFIX
)+
2035 strlen(SAVE_LOCAL_MACHINE
)+2);
2038 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
2039 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
2044 WARN_(reg
)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
2048 * Obtain the handle of the HKU\.Default key.
2049 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2051 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
2052 lpkey
= lookup_hkey(hkey
);
2054 WARN_(reg
)("Could not create global user default key\n");
2056 _copy_registry(lpkey
, HKCU
);
2061 * Since HKU is built from the global HKU and the local user HKU file we must
2062 * flush the HKU tree we have built at this point otherwise the part brought
2063 * in from the global HKU is saved into the local HKU. To avoid this
2064 * useless dupplication of HKU keys we reread the local HKU key.
2067 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2068 _flush_registry(HKU
);
2070 /* Reload user's local HKU hive */
2073 fn
=(char*)xmalloc( strlen(home
) + strlen(WINE_PREFIX
)
2074 + strlen(SAVE_LOCAL_USERS_DEFAULT
) + 2);
2077 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2079 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2085 * Make sure the update mode is there
2087 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2089 DWORD junk
,type
,len
;
2093 if (( RegQueryValueExA(
2099 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2101 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2109 /********************* API FUNCTIONS ***************************************/
2113 * All functions are stubs to RegOpenKeyEx32W where all the
2117 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2118 * RegOpenKey32W -> RegOpenKeyEx32W
2122 /******************************************************************************
2123 * RegOpenKeyEx32W [ADVAPI32.150]
2124 * Opens the specified key
2126 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2129 * hkey [I] Handle of open key
2130 * lpszSubKey [I] Name of subkey to open
2131 * dwReserved [I] Reserved - must be zero
2132 * samDesired [I] Security access mask
2133 * retkey [O] Address of handle of open key
2136 * Success: ERROR_SUCCESS
2137 * Failure: Error code
2139 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2140 REGSAM samDesired
, LPHKEY retkey
)
2142 LPKEYSTRUCT lpNextKey
,lpxkey
;
2146 TRACE_(reg
)("(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2149 lpNextKey
= lookup_hkey( hkey
);
2151 return ERROR_INVALID_HANDLE
;
2153 if (!lpszSubKey
|| !*lpszSubKey
) {
2154 /* Either NULL or pointer to empty string, so return a new handle
2155 to the original hkey */
2157 add_handle(currenthandle
,lpNextKey
,samDesired
);
2158 *retkey
=currenthandle
;
2159 return ERROR_SUCCESS
;
2162 if (lpszSubKey
[0] == '\\') {
2163 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2164 return ERROR_BAD_PATHNAME
;
2167 split_keypath(lpszSubKey
,&wps
,&wpc
);
2169 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2173 lpxkey
=lpNextKey
->nextsub
;
2175 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2178 lpxkey
=lpxkey
->next
;
2182 TRACE_(reg
)("Could not find subkey %s\n",debugstr_w(wps
[i
]));
2184 return ERROR_FILE_NOT_FOUND
;
2191 add_handle(currenthandle
,lpxkey
,samDesired
);
2192 *retkey
= currenthandle
;
2193 TRACE_(reg
)(" Returning %x\n", currenthandle
);
2195 return ERROR_SUCCESS
;
2199 /******************************************************************************
2200 * RegOpenKeyEx32A [ADVAPI32.149]
2202 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2203 REGSAM samDesired
, LPHKEY retkey
)
2205 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2208 TRACE_(reg
)("(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2210 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2216 /******************************************************************************
2217 * RegOpenKey32W [ADVAPI32.151]
2220 * hkey [I] Handle of open key
2221 * lpszSubKey [I] Address of name of subkey to open
2222 * retkey [O] Address of handle of open key
2225 * Success: ERROR_SUCCESS
2226 * Failure: Error code
2228 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2230 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2231 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2235 /******************************************************************************
2236 * RegOpenKey32A [ADVAPI32.148]
2238 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2241 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2242 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2243 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2249 /******************************************************************************
2250 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2252 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2254 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2255 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2262 * All those functions convert their respective
2263 * arguments and call RegCreateKeyExW at the end.
2265 * We stay away from the Ex functions as long as possible because there are
2266 * differences in the return values
2269 * RegCreateKeyEx32A \
2270 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2274 /******************************************************************************
2275 * RegCreateKeyEx32W [ADVAPI32.131]
2278 * hkey [I] Handle of an open key
2279 * lpszSubKey [I] Address of subkey name
2280 * dwReserved [I] Reserved - must be 0
2281 * lpszClass [I] Address of class string
2282 * fdwOptions [I] Special options flag
2283 * samDesired [I] Desired security access
2284 * lpSecAttribs [I] Address of key security structure
2285 * retkey [O] Address of buffer for opened handle
2286 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2288 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2289 DWORD dwReserved
, LPWSTR lpszClass
,
2290 DWORD fdwOptions
, REGSAM samDesired
,
2291 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2292 LPHKEY retkey
, LPDWORD lpDispos
)
2294 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2298 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2299 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2300 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2302 lpNextKey
= lookup_hkey(hkey
);
2304 return ERROR_INVALID_HANDLE
;
2306 /* Check for valid options */
2307 switch(fdwOptions
) {
2308 case REG_OPTION_NON_VOLATILE
:
2309 case REG_OPTION_VOLATILE
:
2310 case REG_OPTION_BACKUP_RESTORE
:
2313 return ERROR_INVALID_PARAMETER
;
2316 /* Sam has to be a combination of the following */
2318 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2319 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2320 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2321 return ERROR_INVALID_PARAMETER
;
2323 if (!lpszSubKey
|| !*lpszSubKey
) {
2325 add_handle(currenthandle
,lpNextKey
,samDesired
);
2326 *retkey
=currenthandle
;
2327 TRACE_(reg
)("Returning %x\n", currenthandle
);
2328 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2329 return ERROR_SUCCESS
;
2332 if (lpszSubKey
[0] == '\\') {
2333 WARN_(reg
)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2334 return ERROR_BAD_PATHNAME
;
2337 split_keypath(lpszSubKey
,&wps
,&wpc
);
2339 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2342 lpxkey
=lpNextKey
->nextsub
;
2344 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2346 lpxkey
=lpxkey
->next
;
2355 add_handle(currenthandle
,lpxkey
,samDesired
);
2356 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2357 *retkey
= currenthandle
;
2358 TRACE_(reg
)("Returning %x\n", currenthandle
);
2360 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2362 return ERROR_SUCCESS
;
2365 /* Good. Now the hard part */
2367 lplpPrevKey
= &(lpNextKey
->nextsub
);
2368 lpxkey
= *lplpPrevKey
;
2370 lplpPrevKey
= &(lpxkey
->next
);
2371 lpxkey
= *lplpPrevKey
;
2373 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2374 if (!*lplpPrevKey
) {
2376 TRACE_(reg
)("Returning OUTOFMEMORY\n");
2377 return ERROR_OUTOFMEMORY
;
2379 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2380 TRACE_(reg
)("Adding %s\n", debugstr_w(wps
[i
]));
2381 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2382 (*lplpPrevKey
)->next
= NULL
;
2383 (*lplpPrevKey
)->nextsub
= NULL
;
2384 (*lplpPrevKey
)->values
= NULL
;
2385 (*lplpPrevKey
)->nrofvalues
= 0;
2386 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2388 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2390 (*lplpPrevKey
)->class = NULL
;
2391 lpNextKey
= *lplpPrevKey
;
2395 add_handle(currenthandle
,lpNextKey
,samDesired
);
2397 /*FIXME: flag handling correct? */
2398 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2400 lpNextKey
->class = strdupW(lpszClass
);
2402 lpNextKey
->class = NULL
;
2403 *retkey
= currenthandle
;
2404 TRACE_(reg
)("Returning %x\n", currenthandle
);
2406 *lpDispos
= REG_CREATED_NEW_KEY
;
2408 return ERROR_SUCCESS
;
2412 /******************************************************************************
2413 * RegCreateKeyEx32A [ADVAPI32.130]
2415 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2416 LPSTR lpszClass
, DWORD fdwOptions
,
2418 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2419 LPHKEY retkey
, LPDWORD lpDispos
)
2421 LPWSTR lpszSubKeyW
, lpszClassW
;
2424 TRACE_(reg
)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2425 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2428 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2429 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2431 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2432 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2435 if(lpszSubKeyW
) free(lpszSubKeyW
);
2436 if(lpszClassW
) free(lpszClassW
);
2442 /******************************************************************************
2443 * RegCreateKey32W [ADVAPI32.132]
2445 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2448 LPKEYSTRUCT lpNextKey
;
2450 TRACE_(reg
)("(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2452 /* This check is here because the return value is different than the
2453 one from the Ex functions */
2454 lpNextKey
= lookup_hkey(hkey
);
2456 return ERROR_BADKEY
;
2458 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2459 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2464 /******************************************************************************
2465 * RegCreateKey32A [ADVAPI32.129]
2467 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2472 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2473 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2474 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2475 if(lpszSubKeyW
) free(lpszSubKeyW
);
2480 /******************************************************************************
2481 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2483 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2485 TRACE_(reg
)("(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2486 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2491 * Query Value Functions
2492 * Win32 differs between keynames and valuenames.
2493 * multiple values may belong to one key, the special value
2494 * with name NULL is the default value used by the win31
2498 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2499 * RegQueryValue32W -> RegQueryValueEx32W
2503 /******************************************************************************
2504 * RegQueryValueEx32W [ADVAPI32.158]
2505 * Retrieves type and data for a specified name associated with an open key
2508 * hkey [I] Handle of key to query
2509 * lpValueName [I] Name of value to query
2510 * lpdwReserved [I] Reserved - must be NULL
2511 * lpdwType [O] Address of buffer for value type. If NULL, the type
2513 * lpbData [O] Address of data buffer. If NULL, the actual data is
2515 * lpcbData [I/O] Address of data buffer size
2518 * ERROR_SUCCESS: Success
2519 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2520 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2522 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPCWSTR lpValueName
,
2523 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2524 LPBYTE lpbData
, LPDWORD lpcbData
)
2530 TRACE_(reg
)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2531 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2533 lpkey
= lookup_hkey(hkey
);
2536 return ERROR_INVALID_HANDLE
;
2538 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2539 return ERROR_INVALID_PARAMETER
;
2541 /* An empty name string is equivalent to NULL */
2542 if (lpValueName
&& !*lpValueName
)
2545 if (lpValueName
==NULL
)
2546 { /* Use key's unnamed or default value, if any */
2547 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2548 if (lpkey
->values
[i
].name
==NULL
)
2552 { /* Search for the key name */
2553 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2554 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2558 if (i
==lpkey
->nrofvalues
)
2559 { TRACE_(reg
)(" Key not found\n");
2560 if (lpValueName
==NULL
)
2561 { /* Empty keyname not found */
2563 { *(WCHAR
*)lpbData
= 0;
2568 TRACE_(reg
)(" Returning an empty string\n");
2569 return ERROR_SUCCESS
;
2571 return ERROR_FILE_NOT_FOUND
;
2574 ret
= ERROR_SUCCESS
;
2576 if (lpdwType
) /* type required ?*/
2577 *lpdwType
= lpkey
->values
[i
].type
;
2579 if (lpbData
) /* data required ?*/
2580 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2581 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2583 *lpcbData
= lpkey
->values
[i
].len
;
2584 ret
= ERROR_MORE_DATA
;
2588 if (lpcbData
) /* size required ?*/
2589 { *lpcbData
= lpkey
->values
[i
].len
;
2592 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2594 TRACE_(reg
)(" (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2600 /******************************************************************************
2601 * RegQueryValue32W [ADVAPI32.159]
2603 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2609 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2610 lpcbData
?*lpcbData
:0);
2612 /* Only open subkey, if we really do descend */
2613 if (lpszSubKey
&& *lpszSubKey
) {
2614 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2615 if (ret
!= ERROR_SUCCESS
) {
2616 WARN_(reg
)("Could not open %s\n", debugstr_w(lpszSubKey
));
2623 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2631 /******************************************************************************
2632 * RegQueryValueEx32A [ADVAPI32.157]
2635 * the documantation is wrong: if the buffer is to small it remains untouched
2637 * FIXME: check returnvalue (len) for an empty key
2639 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2640 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2641 LPBYTE lpbData
, LPDWORD lpcbData
)
2643 LPWSTR lpszValueNameW
;
2644 LPBYTE mybuf
= NULL
;
2645 DWORD ret
, mytype
, mylen
= 0;
2647 TRACE_(reg
)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2648 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2650 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2651 { return ERROR_INVALID_PARAMETER
;
2654 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2656 /* get just the type first */
2657 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2659 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2660 { if(lpszValueNameW
) free(lpszValueNameW
);
2664 if (lpcbData
) /* at least length requested? */
2665 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2666 { if (lpbData
) /* value requested? */
2667 { mylen
= 2*( *lpcbData
);
2668 mybuf
= (LPBYTE
)xmalloc( mylen
);
2671 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2673 if (ret
== ERROR_SUCCESS
)
2675 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2679 *lpcbData
= mylen
/2; /* size is in byte! */
2681 else /* no strings, call it straight */
2682 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2686 if (lpdwType
) /* type when requested */
2687 { *lpdwType
= mytype
;
2690 TRACE_(reg
)(" (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2692 if(mybuf
) free(mybuf
);
2693 if(lpszValueNameW
) free(lpszValueNameW
);
2698 /******************************************************************************
2699 * RegQueryValueEx16 [KERNEL.225]
2701 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2702 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2703 LPBYTE lpbData
, LPDWORD lpcbData
)
2705 TRACE_(reg
)("(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2706 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2707 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2708 lpbData
, lpcbData
);
2712 /******************************************************************************
2713 * RegQueryValue32A [ADVAPI32.156]
2715 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2721 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2722 lpcbData
?*lpcbData
:0);
2724 if (lpszSubKey
&& *lpszSubKey
) {
2725 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2726 if( ret
!= ERROR_SUCCESS
)
2732 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2735 RegCloseKey( xhkey
);
2740 /******************************************************************************
2741 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2744 * Is this HACK still applicable?
2747 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2748 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2751 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2754 TRACE_(reg
)("(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2755 lpcbData
?*lpcbData
:0);
2758 *lpcbData
&= 0xFFFF;
2759 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2764 * Setting values of Registry keys
2767 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2768 * RegSetValue32W -> RegSetValueEx32W
2772 /******************************************************************************
2773 * RegSetValueEx32W [ADVAPI32.170]
2774 * Sets the data and type of a value under a register key
2777 * hkey [I] Handle of key to set value for
2778 * lpszValueName [I] Name of value to set
2779 * dwReserved [I] Reserved - must be zero
2780 * dwType [I] Flag for value type
2781 * lpbData [I] Address of value data
2782 * cbData [I] Size of value data
2785 * Success: ERROR_SUCCESS
2786 * Failure: Error code
2789 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2791 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPCWSTR lpszValueName
,
2792 DWORD dwReserved
, DWORD dwType
,
2793 CONST BYTE
*lpbData
, DWORD cbData
)
2798 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2799 dwReserved
, dwType
, lpbData
, cbData
);
2801 lpkey
= lookup_hkey( hkey
);
2804 return ERROR_INVALID_HANDLE
;
2806 lpkey
->flags
|= REG_OPTION_TAINTED
;
2808 if (lpszValueName
==NULL
) {
2809 /* Sets type and name for key's unnamed or default value */
2810 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2811 if (lpkey
->values
[i
].name
==NULL
)
2814 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2815 if ( lpkey
->values
[i
].name
&&
2816 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2820 if (i
==lpkey
->nrofvalues
) {
2821 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2823 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2825 lpkey
->nrofvalues
++;
2826 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2828 if (lpkey
->values
[i
].name
==NULL
) {
2830 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2832 lpkey
->values
[i
].name
= NULL
;
2835 if (dwType
== REG_SZ
)
2836 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2838 lpkey
->values
[i
].len
= cbData
;
2839 lpkey
->values
[i
].type
= dwType
;
2840 if (lpkey
->values
[i
].data
!=NULL
)
2841 free(lpkey
->values
[i
].data
);
2842 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2843 lpkey
->values
[i
].lastmodified
= time(NULL
);
2844 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2845 return ERROR_SUCCESS
;
2849 /******************************************************************************
2850 * RegSetValueEx32A [ADVAPI32.169]
2853 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2855 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPCSTR lpszValueName
,
2856 DWORD dwReserved
, DWORD dwType
,
2857 CONST BYTE
*lpbData
, DWORD cbData
)
2860 LPWSTR lpszValueNameW
;
2864 return (ERROR_INVALID_PARAMETER
);
2866 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2867 dwReserved
,dwType
,lpbData
,cbData
);
2869 if ((1<<dwType
) & UNICONVMASK
)
2870 { if (dwType
== REG_SZ
)
2871 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2873 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2874 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2878 buf
=(LPBYTE
)lpbData
;
2881 lpszValueNameW
= strdupA2W(lpszValueName
);
2883 lpszValueNameW
= NULL
;
2885 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2888 free(lpszValueNameW
);
2897 /******************************************************************************
2898 * RegSetValueEx16 [KERNEL.226]
2900 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2901 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2903 TRACE_(reg
)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2904 dwReserved
,dwType
,lpbData
,cbData
);
2905 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2910 /******************************************************************************
2911 * RegSetValue32W [ADVAPI32.171]
2913 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2914 LPCWSTR lpszData
, DWORD cbData
)
2919 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",
2920 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2922 if (lpszSubKey
&& *lpszSubKey
) {
2923 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2924 if (ret
!=ERROR_SUCCESS
)
2928 if (dwType
!=REG_SZ
) {
2929 TRACE_(reg
)("dwType=%ld - Changing to REG_SZ\n",dwType
);
2932 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2933 TRACE_(reg
)("Len=%ld != strlen(%s)+1=%d!\n",
2934 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2936 cbData
=2*lstrlenW(lpszData
)+2;
2938 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2945 /******************************************************************************
2946 * RegSetValue32A [ADVAPI32.168]
2949 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2950 LPCSTR lpszData
, DWORD cbData
)
2955 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2956 if (lpszSubKey
&& *lpszSubKey
) {
2957 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2958 if (ret
!=ERROR_SUCCESS
)
2963 if (dwType
!=REG_SZ
) {
2964 TRACE_(reg
)("dwType=%ld!\n",dwType
);
2967 if (cbData
!=strlen(lpszData
)+1)
2968 cbData
=strlen(lpszData
)+1;
2969 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2976 /******************************************************************************
2977 * RegSetValue16 [KERNEL.221] [SHELL.5]
2979 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2980 LPCSTR lpszData
, DWORD cbData
)
2982 TRACE_(reg
)("(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2983 debugstr_a(lpszData
),cbData
);
2984 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2992 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2993 * RegEnumKey32W -> RegEnumKeyEx32W
2997 /******************************************************************************
2998 * RegEnumKeyEx32W [ADVAPI32.139]
3001 * hkey [I] Handle to key to enumerate
3002 * iSubKey [I] Index of subkey to enumerate
3003 * lpszName [O] Buffer for subkey name
3004 * lpcchName [O] Size of subkey buffer
3005 * lpdwReserved [I] Reserved
3006 * lpszClass [O] Buffer for class string
3007 * lpcchClass [O] Size of class buffer
3008 * ft [O] Time key last written to
3010 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3011 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3012 LPWSTR lpszClass
, LPDWORD lpcchClass
,
3015 LPKEYSTRUCT lpkey
,lpxkey
;
3017 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
3018 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
3020 lpkey
= lookup_hkey( hkey
);
3022 return ERROR_INVALID_HANDLE
;
3024 if (!lpkey
->nextsub
)
3025 return ERROR_NO_MORE_ITEMS
;
3026 lpxkey
=lpkey
->nextsub
;
3028 /* Traverse the subkeys */
3029 while (iSubkey
&& lpxkey
) {
3031 lpxkey
=lpxkey
->next
;
3034 if (iSubkey
|| !lpxkey
)
3035 return ERROR_NO_MORE_ITEMS
;
3036 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
) {
3037 *lpcchName
= lstrlenW(lpxkey
->keyname
)+1;
3038 return ERROR_MORE_DATA
;
3040 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
3043 *lpcchName
= lstrlenW(lpszName
);
3046 /* FIXME: what should we write into it? */
3050 return ERROR_SUCCESS
;
3054 /******************************************************************************
3055 * RegEnumKey32W [ADVAPI32.140]
3057 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3062 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3063 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
3067 /******************************************************************************
3068 * RegEnumKeyEx32A [ADVAPI32.138]
3070 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3071 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3072 LPSTR lpszClass
, LPDWORD lpcchClass
,
3075 DWORD ret
,lpcchNameW
,lpcchClassW
;
3076 LPWSTR lpszNameW
,lpszClassW
;
3079 TRACE_(reg
)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3080 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3083 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3084 lpcchNameW
= *lpcchName
;
3090 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3091 lpcchClassW
= *lpcchClass
;
3106 if (ret
==ERROR_SUCCESS
) {
3107 lstrcpyWtoA(lpszName
,lpszNameW
);
3108 *lpcchName
=strlen(lpszName
);
3110 lstrcpyWtoA(lpszClass
,lpszClassW
);
3111 *lpcchClass
=strlen(lpszClass
);
3122 /******************************************************************************
3123 * RegEnumKey32A [ADVAPI32.137]
3125 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3130 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3131 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3136 /******************************************************************************
3137 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3139 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3142 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3143 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3148 * Enumerate Registry Values
3151 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3155 /******************************************************************************
3156 * RegEnumValue32W [ADVAPI32.142]
3159 * hkey [I] Handle to key to query
3160 * iValue [I] Index of value to query
3161 * lpszValue [O] Value string
3162 * lpcchValue [I/O] Size of value buffer (in wchars)
3163 * lpdReserved [I] Reserved
3164 * lpdwType [O] Type code
3165 * lpbData [O] Value data
3166 * lpcbData [I/O] Size of data buffer (in bytes)
3168 * Note: wide character functions that take and/or return "character counts"
3169 * use TCHAR (that is unsigned short or char) not byte counts.
3171 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3172 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3173 LPDWORD lpdwType
, LPBYTE lpbData
,
3179 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3180 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3182 lpkey
= lookup_hkey( hkey
);
3184 if (!lpcbData
&& lpbData
)
3185 return ERROR_INVALID_PARAMETER
;
3188 return ERROR_INVALID_HANDLE
;
3190 if (lpkey
->nrofvalues
<= iValue
)
3191 return ERROR_NO_MORE_ITEMS
;
3193 val
= &(lpkey
->values
[iValue
]);
3196 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3197 *lpcchValue
= lstrlenW(val
->name
)+1;
3198 return ERROR_MORE_DATA
;
3200 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3201 *lpcchValue
=lstrlenW(val
->name
);
3207 /* Can be NULL if the type code is not required */
3209 *lpdwType
= val
->type
;
3212 if (val
->len
>*lpcbData
) {
3213 *lpcbData
= val
->len
;
3214 return ERROR_MORE_DATA
;
3216 memcpy(lpbData
,val
->data
,val
->len
);
3217 *lpcbData
= val
->len
;
3220 debug_print_value ( val
->data
, val
);
3221 return ERROR_SUCCESS
;
3225 /******************************************************************************
3226 * RegEnumValue32A [ADVAPI32.141]
3228 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3229 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3230 LPDWORD lpdwType
, LPBYTE lpbData
,
3235 DWORD ret
,lpcbDataW
;
3238 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3239 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3241 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3243 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3244 lpcbDataW
= *lpcbData
;
3248 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3249 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3254 if (ret
==ERROR_SUCCESS
) {
3255 lstrcpyWtoA(lpszValue
,lpszValueW
);
3257 if ((1<<dwType
) & UNICONVMASK
) {
3258 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3260 if (lpcbDataW
> *lpcbData
) {
3261 *lpcbData
= lpcbDataW
;
3262 ret
= ERROR_MORE_DATA
;
3264 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3266 *lpcbData
= lpcbDataW
;
3269 if (lpbDataW
) free(lpbDataW
);
3270 if (lpszValueW
) free(lpszValueW
);
3275 /******************************************************************************
3276 * RegEnumValue16 [KERNEL.223]
3278 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3279 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3280 LPDWORD lpdwType
, LPBYTE lpbData
,
3283 TRACE_(reg
)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3284 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3285 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3286 lpdwType
, lpbData
, lpcbData
);
3290 /******************************************************************************
3291 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3292 * Releases the handle of the specified key
3295 * hkey [I] Handle of key to close
3298 * Success: ERROR_SUCCESS
3299 * Failure: Error code
3301 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3303 TRACE_(reg
)("(%x)\n",hkey
);
3305 /* The standard handles are allowed to succeed, even though they are not
3307 if (is_standard_hkey(hkey
))
3308 return ERROR_SUCCESS
;
3310 return remove_handle(hkey
);
3315 * Delete registry key
3318 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3322 /******************************************************************************
3323 * RegDeleteKey32W [ADVAPI32.134]
3326 * hkey [I] Handle to open key
3327 * lpszSubKey [I] Name of subkey to delete
3330 * Success: ERROR_SUCCESS
3331 * Failure: Error code
3333 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPCWSTR lpszSubKey
)
3335 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3339 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3341 lpNextKey
= lookup_hkey(hkey
);
3343 return ERROR_INVALID_HANDLE
;
3345 /* Subkey param cannot be NULL */
3346 if (!lpszSubKey
|| !*lpszSubKey
)
3347 return ERROR_BADKEY
;
3349 /* We need to know the previous key in the hier. */
3350 split_keypath(lpszSubKey
,&wps
,&wpc
);
3354 lpxkey
=lpNextKey
->nextsub
;
3356 TRACE_(reg
)(" Scanning [%s]\n",
3357 debugstr_w(lpxkey
->keyname
));
3358 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3360 lpxkey
=lpxkey
->next
;
3364 TRACE_(reg
)(" Not found.\n");
3365 /* not found is success */
3366 return ERROR_SUCCESS
;
3371 lpxkey
= lpNextKey
->nextsub
;
3372 lplpPrevKey
= &(lpNextKey
->nextsub
);
3374 TRACE_(reg
)(" Scanning [%s]\n",
3375 debugstr_w(lpxkey
->keyname
));
3376 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3378 lplpPrevKey
= &(lpxkey
->next
);
3379 lpxkey
= lpxkey
->next
;
3384 WARN_(reg
)(" Not found.\n");
3385 return ERROR_FILE_NOT_FOUND
;
3388 if (lpxkey
->nextsub
) {
3390 WARN_(reg
)(" Not empty.\n");
3391 return ERROR_CANTWRITE
;
3393 *lplpPrevKey
= lpxkey
->next
;
3394 free(lpxkey
->keyname
);
3396 free(lpxkey
->class);
3398 free(lpxkey
->values
);
3401 TRACE_(reg
)(" Done.\n");
3402 return ERROR_SUCCESS
;
3406 /******************************************************************************
3407 * RegDeleteKey32A [ADVAPI32.133]
3409 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3414 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3415 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3416 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3417 if(lpszSubKeyW
) free(lpszSubKeyW
);
3422 /******************************************************************************
3423 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3425 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3427 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3428 return RegDeleteKeyA( hkey
, lpszSubKey
);
3433 * Delete registry value
3436 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3440 /******************************************************************************
3441 * RegDeleteValue32W [ADVAPI32.136]
3449 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPCWSTR lpszValue
)
3455 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3457 lpkey
= lookup_hkey( hkey
);
3459 return ERROR_INVALID_HANDLE
;
3462 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3463 if ( lpkey
->values
[i
].name
&&
3464 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3468 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3469 if (lpkey
->values
[i
].name
==NULL
)
3473 if (i
== lpkey
->nrofvalues
)
3474 return ERROR_FILE_NOT_FOUND
;
3476 val
= lpkey
->values
+i
;
3477 if (val
->name
) free(val
->name
);
3478 if (val
->data
) free(val
->data
);
3482 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3484 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3486 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3488 lpkey
->nrofvalues
--;
3489 return ERROR_SUCCESS
;
3493 /******************************************************************************
3494 * RegDeleteValue32A [ADVAPI32.135]
3496 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPCSTR lpszValue
)
3501 TRACE_(reg
)("(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3502 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3503 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3504 if(lpszValueW
) free(lpszValueW
);
3509 /******************************************************************************
3510 * RegDeleteValue16 [KERNEL.222]
3512 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3514 TRACE_(reg
)("(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3515 return RegDeleteValueA( hkey
, lpszValue
);
3519 /******************************************************************************
3520 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3521 * Immediately writes key to registry.
3522 * Only returns after data has been written to disk.
3524 * FIXME: does it really wait until data is written ?
3526 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3527 * written if this function really works (and only if !).
3530 * hkey [I] Handle of key to write
3533 * Success: ERROR_SUCCESS
3534 * Failure: Error code
3536 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3540 TRACE_(reg
)("(%x)\n", hkey
);
3542 lpkey
= lookup_hkey( hkey
);
3544 return ERROR_BADKEY
;
3546 SHELL_SaveRegistryBranch(find_root_key(lpkey
), TRUE
);
3547 return ERROR_SUCCESS
;
3551 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3554 /******************************************************************************
3555 * RegQueryInfoKey32W [ADVAPI32.153]
3558 * hkey [I] Handle to key to query
3559 * lpszClass [O] Buffer for class string
3560 * lpcchClass [O] Size of class string buffer
3561 * lpdwReserved [I] Reserved
3562 * lpcSubKeys [I] Buffer for number of subkeys
3563 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3564 * lpcchMaxClass [O] Buffer for longest class string length
3565 * lpcValues [O] Buffer for number of value entries
3566 * lpcchMaxValueName [O] Buffer for longest value name length
3567 * lpccbMaxValueData [O] Buffer for longest value data length
3568 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3570 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3571 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3572 * lpcchClass is NULL
3573 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3574 * (it's hard to test validity, so test !NULL instead)
3576 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3577 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3578 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3579 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3580 LPDWORD lpcchMaxValueName
,
3581 LPDWORD lpccbMaxValueData
,
3582 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3584 LPKEYSTRUCT lpkey
,lpxkey
;
3585 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3588 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3589 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3590 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3591 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3593 lpkey
= lookup_hkey(hkey
);
3595 return ERROR_INVALID_HANDLE
;
3597 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3598 return ERROR_INVALID_PARAMETER
;
3600 /* either lpcchClass is valid or this is win95 and lpcchClass
3603 DWORD classLen
= lstrlenW(lpkey
->class);
3605 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3606 *lpcchClass
=classLen
+1;
3607 return ERROR_MORE_DATA
;
3610 *lpcchClass
=classLen
;
3611 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3619 *lpcchClass
= lstrlenW(lpkey
->class);
3621 lpxkey
=lpkey
->nextsub
;
3622 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3625 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3626 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3627 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3628 maxclass
=lstrlenW(lpxkey
->class);
3629 lpxkey
=lpxkey
->next
;
3631 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3632 LPKEYVALUE val
=lpkey
->values
+i
;
3634 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3635 maxvname
=lstrlenW(val
->name
);
3636 if (val
->len
>maxvdata
)
3639 if (!maxclass
) maxclass
= 1;
3640 if (!maxvname
) maxvname
= 1;
3642 *lpcValues
= lpkey
->nrofvalues
;
3644 *lpcSubKeys
= nrofkeys
;
3646 *lpcchMaxSubkey
= maxsubkey
;
3648 *lpcchMaxClass
= maxclass
;
3649 if (lpcchMaxValueName
)
3650 *lpcchMaxValueName
= maxvname
;
3651 if (lpccbMaxValueData
)
3652 *lpccbMaxValueData
= maxvdata
;
3653 return ERROR_SUCCESS
;
3657 /******************************************************************************
3658 * RegQueryInfoKey32A [ADVAPI32.152]
3660 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3661 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3662 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3663 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3664 LPDWORD lpccbMaxValueData
,
3665 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3667 LPWSTR lpszClassW
= NULL
;
3670 TRACE_(reg
)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3671 hkey
, lpszClass
, lpcchClass
?*lpcchClass
:0,lpdwReserved
,
3672 lpcSubKeys
,lpcchMaxSubkey
,lpcValues
,lpcchMaxValueName
,
3673 lpccbMaxValueData
,lpcbSecurityDescriptor
,ft
3677 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3678 } else if (VERSION_GetVersion() == WIN95
) {
3679 /* win95 allows lpcchClass to be null */
3680 /* we don't know how big lpszClass is, would
3681 MAX_PATHNAME_LEN be the correct default? */
3682 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3687 ret
=RegQueryInfoKeyW(
3698 lpcbSecurityDescriptor
,
3701 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3702 lstrcpyWtoA(lpszClass
,lpszClassW
);
3709 /******************************************************************************
3710 * RegConnectRegistry32W [ADVAPI32.128]
3713 * lpMachineName [I] Address of name of remote computer
3714 * hHey [I] Predefined registry handle
3715 * phkResult [I] Address of buffer for remote registry handle
3717 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3720 TRACE_(reg
)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3722 if (!lpMachineName
|| !*lpMachineName
) {
3723 /* Use the local machine name */
3724 return RegOpenKey16( hKey
, "", phkResult
);
3727 FIXME_(reg
)("Cannot connect to %s\n",debugstr_w(lpMachineName
));
3728 return ERROR_BAD_NETPATH
;
3732 /******************************************************************************
3733 * RegConnectRegistry32A [ADVAPI32.127]
3735 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3738 LPWSTR machineW
= strdupA2W(machine
);
3739 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3745 /******************************************************************************
3746 * RegGetKeySecurity [ADVAPI32.144]
3747 * Retrieves a copy of security descriptor protecting the registry key
3750 * hkey [I] Open handle of key to set
3751 * SecurityInformation [I] Descriptor contents
3752 * pSecurityDescriptor [O] Address of descriptor for key
3753 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3756 * Success: ERROR_SUCCESS
3757 * Failure: Error code
3759 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3760 SECURITY_INFORMATION SecurityInformation
,
3761 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3762 LPDWORD lpcbSecurityDescriptor
)
3766 TRACE_(reg
)("(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3767 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3769 lpkey
= lookup_hkey( hkey
);
3771 return ERROR_INVALID_HANDLE
;
3773 /* FIXME: Check for valid SecurityInformation values */
3775 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3776 return ERROR_INSUFFICIENT_BUFFER
;
3778 FIXME_(reg
)("(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3779 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3781 return ERROR_SUCCESS
;
3785 /******************************************************************************
3786 * RegLoadKey32W [ADVAPI32.???]
3789 * hkey [I] Handle of open key
3790 * lpszSubKey [I] Address of name of subkey
3791 * lpszFile [I] Address of filename for registry information
3793 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3796 TRACE_(reg
)("(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3798 /* Do this check before the hkey check */
3799 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3800 return ERROR_INVALID_PARAMETER
;
3802 lpkey
= lookup_hkey( hkey
);
3804 return ERROR_INVALID_HANDLE
;
3806 FIXME_(reg
)("(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3807 debugstr_w(lpszFile
));
3809 return ERROR_SUCCESS
;
3813 /******************************************************************************
3814 * RegLoadKey32A [ADVAPI32.???]
3816 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3819 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3820 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3821 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3822 if(lpszFileW
) free(lpszFileW
);
3823 if(lpszSubKeyW
) free(lpszSubKeyW
);
3828 /******************************************************************************
3829 * RegNotifyChangeKeyValue [ADVAPI32.???]
3832 * hkey [I] Handle of key to watch
3833 * fWatchSubTree [I] Flag for subkey notification
3834 * fdwNotifyFilter [I] Changes to be reported
3835 * hEvent [I] Handle of signaled event
3836 * fAsync [I] Flag for asynchronous reporting
3838 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3839 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3843 TRACE_(reg
)("(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3846 lpkey
= lookup_hkey( hkey
);
3848 return ERROR_INVALID_HANDLE
;
3850 FIXME_(reg
)("(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3853 return ERROR_SUCCESS
;
3857 /******************************************************************************
3858 * RegUnLoadKey32W [ADVAPI32.173]
3861 * hkey [I] Handle of open key
3862 * lpSubKey [I] Address of name of subkey to unload
3864 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3866 FIXME_(reg
)("(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3867 return ERROR_SUCCESS
;
3871 /******************************************************************************
3872 * RegUnLoadKey32A [ADVAPI32.172]
3874 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3877 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3878 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3879 if(lpSubKeyW
) free(lpSubKeyW
);
3884 /******************************************************************************
3885 * RegSetKeySecurity [ADVAPI32.167]
3888 * hkey [I] Open handle of key to set
3889 * SecurityInfo [I] Descriptor contents
3890 * pSecurityDesc [I] Address of descriptor for key
3892 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3893 PSECURITY_DESCRIPTOR pSecurityDesc
)
3897 TRACE_(reg
)("(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3899 /* It seems to perform this check before the hkey check */
3900 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3901 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3902 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3903 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3906 return ERROR_INVALID_PARAMETER
;
3909 return ERROR_INVALID_PARAMETER
;
3911 lpkey
= lookup_hkey( hkey
);
3913 return ERROR_INVALID_HANDLE
;
3915 FIXME_(reg
)(":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3917 return ERROR_SUCCESS
;
3921 /******************************************************************************
3922 * RegSaveKey32W [ADVAPI32.166]
3925 * hkey [I] Handle of key where save begins
3926 * lpFile [I] Address of filename to save to
3927 * sa [I] Address of security structure
3929 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3930 LPSECURITY_ATTRIBUTES sa
)
3934 TRACE_(reg
)("(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3936 /* It appears to do this check before the hkey check */
3937 if (!lpFile
|| !*lpFile
)
3938 return ERROR_INVALID_PARAMETER
;
3940 lpkey
= lookup_hkey( hkey
);
3942 return ERROR_INVALID_HANDLE
;
3944 FIXME_(reg
)("(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3946 return ERROR_SUCCESS
;
3950 /******************************************************************************
3951 * RegSaveKey32A [ADVAPI32.165]
3953 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3954 LPSECURITY_ATTRIBUTES sa
)
3957 LPWSTR lpFileW
= strdupA2W(lpFile
);
3958 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3964 /******************************************************************************
3965 * RegRestoreKey32W [ADVAPI32.164]
3968 * hkey [I] Handle of key where restore begins
3969 * lpFile [I] Address of filename containing saved tree
3970 * dwFlags [I] Optional flags
3972 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3976 TRACE_(reg
)("(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3978 /* It seems to do this check before the hkey check */
3979 if (!lpFile
|| !*lpFile
)
3980 return ERROR_INVALID_PARAMETER
;
3982 lpkey
= lookup_hkey( hkey
);
3984 return ERROR_INVALID_HANDLE
;
3986 FIXME_(reg
)("(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3988 /* Check for file existence */
3990 return ERROR_SUCCESS
;
3994 /******************************************************************************
3995 * RegRestoreKey32A [ADVAPI32.163]
3997 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
4000 LPWSTR lpFileW
= strdupA2W(lpFile
);
4001 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
4002 if(lpFileW
) free(lpFileW
);
4007 /******************************************************************************
4008 * RegReplaceKey32W [ADVAPI32.162]
4011 * hkey [I] Handle of open key
4012 * lpSubKey [I] Address of name of subkey
4013 * lpNewFile [I] Address of filename for file with new data
4014 * lpOldFile [I] Address of filename for backup file
4016 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
4021 TRACE_(reg
)("(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
4022 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
4024 lpkey
= lookup_hkey( hkey
);
4026 return ERROR_INVALID_HANDLE
;
4028 FIXME_(reg
)("(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
4029 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
4031 return ERROR_SUCCESS
;
4035 /******************************************************************************
4036 * RegReplaceKey32A [ADVAPI32.161]
4038 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
4042 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
4043 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
4044 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
4045 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);