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 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
45 #include "winversion.h"
47 DECLARE_DEBUG_CHANNEL(reg
)
48 DECLARE_DEBUG_CHANNEL(string
)
50 static void REGISTRY_Init(void);
51 /* FIXME: following defines should be configured global ... */
53 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
54 #define WINE_PREFIX "/.wine"
55 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
56 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
58 /* relative in ~user/.wine/ : */
59 #define SAVE_CURRENT_USER "user.reg"
60 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
61 #define SAVE_LOCAL_MACHINE "system.reg"
63 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
64 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
66 /* one value of a key */
67 typedef struct tagKEYVALUE
69 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
70 DWORD type
; /* type of value */
71 DWORD len
; /* length of data in BYTEs */
72 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
73 LPBYTE data
; /* content, may be strings, binaries, etc. */
74 } KEYVALUE
,*LPKEYVALUE
;
77 typedef struct tagKEYSTRUCT
79 LPWSTR keyname
; /* name of THIS key (UNICODE) */
80 DWORD flags
; /* flags. */
83 DWORD nrofvalues
; /* nr of values in THIS key */
84 LPKEYVALUE values
; /* values in THIS key */
85 /* key management pointers */
86 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
87 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
88 } KEYSTRUCT
, *LPKEYSTRUCT
;
91 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
92 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
93 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
94 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
96 /* dynamic, not saved */
97 static KEYSTRUCT
*key_performance_data
=NULL
;
98 static KEYSTRUCT
*key_current_config
=NULL
;
99 static KEYSTRUCT
*key_dyn_data
=NULL
;
101 /* what valuetypes do we need to convert? */
102 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
105 static struct openhandle
{
110 static int nrofopenhandles
=0;
111 /* Starts after 1 because 0,1 are reserved for Win16 */
112 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
113 HKEYs for remote registry access */
114 static int currenthandle
=2;
119 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
120 * If so, can we remove them?
122 * No, the memory handling functions are called very often in here,
123 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
124 * loading 100 times slower. -MM
126 static LPWSTR
strdupA2W(LPCSTR src
)
129 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
130 lstrcpyAtoW(dest
,src
);
136 static LPWSTR
strdupW(LPCWSTR a
) {
141 len
=sizeof(WCHAR
)*(lstrlenW(a
)+1);
142 b
=(LPWSTR
)xmalloc(len
);
149 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
152 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
154 lstrcpynAtoW(dest
,src
,nchars
+1);
159 * we need to convert A to W with '\0' in strings (MULTI_SZ)
162 static LPWSTR
lmemcpynAtoW( LPWSTR dst
, LPCSTR src
, INT n
)
165 TRACE(reg
,"\"%s\" %i\n",src
, n
);
167 while (n
-- > 0) *p
++ = (WCHAR
)(unsigned char)*src
++;
171 static LPSTR
lmemcpynWtoA( LPSTR dst
, LPCWSTR src
, INT n
)
174 TRACE(string
,"L\"%s\" %i\n",debugstr_w(src
), n
);
176 while (n
-- > 0) *p
++ = (CHAR
)*src
++;
181 static void debug_print_value (LPBYTE lpbData
, LPKEYVALUE key
)
183 if (TRACE_ON(reg
) && lpbData
)
187 case HEX_REG_EXPAND_SZ
:
190 TRACE(reg
," Value %s, Data(sz)=%s\n",
191 debugstr_w(key
->name
),
192 debugstr_w((LPCWSTR
)lpbData
));
197 TRACE(reg
," Value %s, Data(dword)=0x%08lx\n",
198 debugstr_w(key
->name
),
202 case HEX_REG_MULTI_SZ
:
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;
222 case HEX_REG_RESOURCE_LIST
:
223 case HEX_REG_FULL_RESOURCE_DESCRIPTOR
:
226 case REG_RESOURCE_LIST
:
227 case REG_FULL_RESOURCE_DESCRIPTOR
:
230 char szTemp
[100]; /* 3*32 + 3 + 1 */
232 for ( i
= 0; i
< key
->len
; i
++)
234 sprintf (&(szTemp
[i
*3]),"%02x ", lpbData
[i
]);
237 sprintf (&(szTemp
[i
*3+3]),"...");
241 TRACE(reg
," Value %s, Data(raw)=(%s)\n",
242 debugstr_w(key
->name
),
248 FIXME(reg
, " Value %s, Unknown data type %ld\n",
249 debugstr_w(key
->name
),
256 /******************************************************************************
257 * is_standard_hkey [Internal]
258 * Determines if a hkey is a standard key
260 static BOOL
is_standard_hkey( HKEY hkey
)
265 case HKEY_CLASSES_ROOT
:
266 case HKEY_CURRENT_CONFIG
:
267 case HKEY_CURRENT_USER
:
268 case HKEY_LOCAL_MACHINE
:
270 case HKEY_PERFORMANCE_DATA
:
278 /******************************************************************************
279 * add_handle [Internal]
281 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
285 TRACE(reg
,"(0x%x,%p,0x%lx)\n",hkey
,lpkey
,accessmask
);
286 /* Check for duplicates */
287 for (i
=0;i
<nrofopenhandles
;i
++) {
288 if (openhandles
[i
].lpkey
==lpkey
) {
289 /* This is not really an error - the user is allowed to create
290 two (or more) handles to the same key */
291 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
293 if (openhandles
[i
].hkey
==hkey
) {
294 WARN(reg
, "Adding handle %x twice\n",hkey
);
297 openhandles
=xrealloc( openhandles
,
298 sizeof(struct openhandle
)*(nrofopenhandles
+1));
300 openhandles
[i
].lpkey
= lpkey
;
301 openhandles
[i
].hkey
= hkey
;
302 openhandles
[i
].accessmask
= accessmask
;
307 /******************************************************************************
308 * get_handle [Internal]
311 * Success: Pointer to key
314 static LPKEYSTRUCT
get_handle( HKEY hkey
)
318 for (i
=0; i
<nrofopenhandles
; i
++)
319 if (openhandles
[i
].hkey
== hkey
)
320 return openhandles
[i
].lpkey
;
321 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
326 /******************************************************************************
327 * remove_handle [Internal]
330 * hkey [I] Handle of key to remove
333 * Success: ERROR_SUCCESS
334 * Failure: ERROR_INVALID_HANDLE
336 static DWORD
remove_handle( HKEY hkey
)
340 for (i
=0;i
<nrofopenhandles
;i
++)
341 if (openhandles
[i
].hkey
==hkey
)
344 if (i
== nrofopenhandles
) {
345 WARN(reg
, "Could not find handle 0x%x\n",hkey
);
346 return ERROR_INVALID_HANDLE
;
349 memcpy( openhandles
+i
,
351 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
353 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
355 return ERROR_SUCCESS
;
358 /******************************************************************************
359 * lookup_hkey [Internal]
361 * Just as the name says. Creates the root keys on demand, so we can call the
362 * Reg* functions at any time.
365 * Success: Pointer to key structure
368 #define ADD_ROOT_KEY(xx) \
369 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
370 memset(xx,'\0',sizeof(KEYSTRUCT));\
371 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
373 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
376 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
377 * some programs. Do not remove those cases. -MM
381 case HKEY_CLASSES_ROOT
:
383 if (!key_classes_root
)
387 /* calls lookup_hkey recursively, TWICE */
391 &cl_r_hkey
) != ERROR_SUCCESS
)
395 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
399 key_classes_root
= lookup_hkey(cl_r_hkey
);
401 return key_classes_root
;
404 case HKEY_CURRENT_USER
:
405 if (!key_current_user
) {
406 ADD_ROOT_KEY(key_current_user
);
408 return key_current_user
;
410 case HKEY_LOCAL_MACHINE
:
411 if (!key_local_machine
) {
412 ADD_ROOT_KEY(key_local_machine
);
415 return key_local_machine
;
419 ADD_ROOT_KEY(key_users
);
423 case HKEY_PERFORMANCE_DATA
:
424 if (!key_performance_data
) {
425 ADD_ROOT_KEY(key_performance_data
);
427 return key_performance_data
;
431 ADD_ROOT_KEY(key_dyn_data
);
435 case HKEY_CURRENT_CONFIG
:
436 if (!key_current_config
) {
437 ADD_ROOT_KEY(key_current_config
);
439 return key_current_config
;
442 return get_handle(hkey
);
448 /* so we don't accidently access them ... */
449 #define key_current_config NULL NULL
450 #define key_current_user NULL NULL
451 #define key_users NULL NULL
452 #define key_local_machine NULL NULL
453 #define key_classes_root NULL NULL
454 #define key_dyn_data NULL NULL
455 #define key_performance_data NULL NULL
457 /******************************************************************************
458 * split_keypath [Internal]
459 * splits the unicode string 'wp' into an array of strings.
460 * the array is allocated by this function.
461 * Free the array using FREE_KEY_PATH
464 * wp [I] String to split up
465 * wpv [O] Array of pointers to strings
466 * wpc [O] Number of components
468 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
473 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
475 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
477 /* We know we have at least one substring */
480 /* Replace each backslash with NULL, and increment the count */
481 for (i
=0;ws
[i
];i
++) {
490 /* Allocate the space for the array of pointers, leaving room for the
492 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
495 /* Assign each pointer to the appropriate character in the string */
500 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
505 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
510 /******************************************************************************
511 * REGISTRY_Init [Internal]
512 * Registry initialisation, allocates some default keys.
514 static void REGISTRY_Init(void) {
518 TRACE(reg
,"(void)\n");
520 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
523 /* This was an Open, but since it is called before the real registries
524 are loaded, it was changed to a Create - MTB 980507*/
525 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
526 RegSetValueExA(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
529 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
533 * string RegisteredOwner
534 * string RegisteredOrganization
537 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
542 if (-1!=gethostname(buf
,200)) {
543 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
544 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
550 /************************ SAVE Registry Function ****************************/
552 #define REGISTRY_SAVE_VERSION 0x00000001
554 /* Registry saveformat:
555 * If you change it, increase above number by 1, which will flush
556 * old registry database files.
559 * "WINE REGISTRY Version %d"
563 * valuename=lastmodified,type,data
567 * keyname,valuename,stringdata:
568 * the usual ascii characters from 0x00-0xff (well, not 0x00)
569 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
570 * ( "=\\\t" escaped in \uXXXX form.)
574 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
576 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
577 * SaveOnlyUpdatedKeys=yes
580 /******************************************************************************
581 * _save_check_tainted [Internal]
583 static int _save_check_tainted( LPKEYSTRUCT lpkey
)
589 if (lpkey
->flags
& REG_OPTION_TAINTED
)
594 if (_save_check_tainted(lpkey
->nextsub
)) {
595 lpkey
->flags
|= REG_OPTION_TAINTED
;
603 /******************************************************************************
604 * _save_USTRING [Internal]
606 static void _save_USTRING( FILE *F
, LPWSTR wstr
, int escapeeq
)
620 if (escapeeq
&& *s
=='=')
623 fputc(*s
,F
); /* if \\ then put it twice. */
625 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
632 /******************************************************************************
633 * _savesubkey [Internal]
636 * REG_MULTI_SZ is handled as binary (like in win95) (js)
638 static int _savesubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, int all
)
645 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
646 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
648 for (tabs
=level
;tabs
--;)
650 _save_USTRING(F
,lpxkey
->keyname
,1);
652 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
653 LPKEYVALUE val
=lpxkey
->values
+i
;
655 for (tabs
=level
+1;tabs
--;)
657 _save_USTRING(F
,val
->name
,0);
659 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
660 if ( val
->type
== REG_SZ
|| val
->type
== REG_EXPAND_SZ
)
661 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
663 for (j
=0;j
<val
->len
;j
++)
664 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
667 /* descend recursively */
668 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
677 /******************************************************************************
678 * _savesubreg [Internal]
680 static int _savesubreg( FILE *F
, LPKEYSTRUCT lpkey
, int all
)
682 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
683 _save_check_tainted(lpkey
->nextsub
);
684 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
688 /******************************************************************************
689 * _savereg [Internal]
691 static BOOL
_savereg( LPKEYSTRUCT lpkey
, char *fn
, int all
)
697 WARN(reg
,"Couldn't open %s for writing: %s\n",
702 if (!_savesubreg(F
,lpkey
,all
)) {
705 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
713 /******************************************************************************
714 * SHELL_SaveRegistry [Internal]
716 void SHELL_SaveRegistry( void )
726 TRACE(reg
,"(void)\n");
729 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
)
738 if ( (ERROR_SUCCESS
!=RegQueryValueExA(
744 &len
)) || (type
!=REG_SZ
))
751 if (lstrcmpiA(buf
,"yes"))
754 pwd
=getpwuid(getuid());
755 if ( (pwd
!=NULL
) && (pwd
->pw_dir
!=NULL
))
759 * Save HKEY_CURRENT_USER
760 * Try first saving according to the defined location in .winerc
762 fn
= xmalloc( MAX_PATHNAME_LEN
);
763 if (PROFILE_GetWineIniString (
768 MAX_PATHNAME_LEN
- 1))
770 _savereg(lookup_hkey(HKEY_CURRENT_USER
),fn
,all
);
775 if (usedCfgUser
!= 1)
778 strlen(pwd
->pw_dir
) +
779 strlen(WINE_PREFIX
) +
780 strlen(SAVE_CURRENT_USER
) + 2 );
782 strcpy(fn
,pwd
->pw_dir
);
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");
804 * Save HKEY_LOCAL_MACHINE
805 * Try first saving according to the defined location in .winerc
807 fn
= xmalloc ( MAX_PATHNAME_LEN
);
808 if (PROFILE_GetWineIniString (
810 "LocalMachineFileName",
813 MAX_PATHNAME_LEN
- 1))
815 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE
), fn
, all
);
825 strlen(SAVE_LOCAL_MACHINE
)+2);
827 strcpy(fn
,pwd
->pw_dir
);
828 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
830 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
834 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
835 if (-1==rename(tmp
,fn
)) {
836 perror("rename tmp registry");
850 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
852 strcpy(fn
,pwd
->pw_dir
);
853 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
855 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
856 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
857 if ( _savereg(lookup_hkey(HKEY_USERS
),tmp
,FALSE
)) {
858 if (-1==rename(tmp
,fn
)) {
859 perror("rename tmp registry");
868 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
873 /************************ LOAD Registry Function ****************************/
877 /******************************************************************************
878 * _find_or_add_key [Internal]
880 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
882 LPKEYSTRUCT lpxkey
,*lplpkey
;
884 if ((!keyname
) || (keyname
[0]==0)) {
888 lplpkey
= &(lpkey
->nextsub
);
891 if ( (lpxkey
->keyname
[0]==keyname
[0]) &&
892 !lstrcmpiW(lpxkey
->keyname
,keyname
)
895 lplpkey
= &(lpxkey
->next
);
899 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
901 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
902 lpxkey
->keyname
= keyname
;
908 /******************************************************************************
909 * _find_or_add_value [Internal]
911 static void _find_or_add_value( LPKEYSTRUCT lpkey
, LPWSTR name
, DWORD type
,
912 LPBYTE data
, DWORD len
, DWORD lastmodified
)
917 if (name
&& !*name
) {/* empty string equals default (NULL) value */
922 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
928 if ( val
->name
!=NULL
&&
929 val
->name
[0]==name
[0] &&
930 !lstrcmpiW(val
->name
,name
)
935 if (i
==lpkey
->nrofvalues
) {
936 lpkey
->values
= xrealloc(
938 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
941 memset(val
,'\0',sizeof(KEYVALUE
));
947 if (val
->lastmodified
<lastmodified
) {
948 val
->lastmodified
=lastmodified
;
959 /******************************************************************************
960 * _wine_read_line [Internal]
962 * reads a line including dynamically enlarging the readbuffer and throwing
965 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
975 s
=fgets(curread
,mylen
,F
);
978 if (NULL
==(s
=strchr(curread
,'\n'))) {
979 /* buffer wasn't large enough */
980 curoff
= strlen(*buf
);
981 *buf
= xrealloc(*buf
,*len
*2);
982 curread
= *buf
+ curoff
;
983 mylen
= *len
; /* we filled up the buffer and
984 * got new '*len' bytes to fill
992 /* throw away comments */
993 if (**buf
=='#' || **buf
==';') {
998 if (s
) /* got end of line */
1005 /******************************************************************************
1006 * _wine_read_USTRING [Internal]
1008 * converts a char* into a UNICODE string (up to a special char)
1009 * and returns the position exactly after that string
1011 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
1016 /* read up to "=" or "\0" or "\n" */
1019 /* empty string is the win3.1 default value(NULL)*/
1023 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
1025 while (*s
&& (*s
!='\n') && (*s
!='=')) {
1027 *ws
++=*((unsigned char*)s
++);
1031 /* Dangling \ ... may only happen if a registry
1032 * write was short. FIXME: What do to?
1042 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1050 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1051 if (!sscanf(xbuf
,"%x",&wc
))
1052 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1054 *ws
++ =(unsigned short)wc
;
1061 *str
= strdupW(*str
);
1069 /******************************************************************************
1070 * _wine_loadsubkey [Internal]
1073 * It seems like this is returning a boolean. Should it?
1079 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1080 int *buflen
, DWORD optflag
)
1087 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1090 lpkey
->flags
|= optflag
;
1092 /* Good. We already got a line here ... so parse it */
1102 WARN(reg
,"Got a subhierarchy without resp. key?\n");
1105 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1109 /* let the caller handle this line */
1110 if (i
<level
|| **buf
=='\0')
1113 /* it can be: a value or a keyname. Parse the name first */
1114 s
=_wine_read_USTRING(s
,&name
);
1116 /* switch() default: hack to avoid gotos */
1120 lpxkey
=_find_or_add_key(lpkey
,name
);
1123 int len
,lastmodified
,type
;
1126 WARN(reg
,"Unexpected character: %c\n",*s
);
1130 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1131 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
1135 s
=strchr(s
,',');s
++;
1136 s
=strchr(s
,',');s
++;
1137 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1138 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1140 len
= lstrlenW((LPWSTR
)data
)*2+2;
1145 data
= (LPBYTE
)xmalloc(len
+1);
1146 for (i
=0;i
<len
;i
++) {
1148 if (*s
>='0' && *s
<='9')
1149 data
[i
]=(*s
-'0')<<4;
1150 if (*s
>='a' && *s
<='f')
1151 data
[i
]=(*s
-'a'+'\xa')<<4;
1152 if (*s
>='A' && *s
<='F')
1153 data
[i
]=(*s
-'A'+'\xa')<<4;
1155 if (*s
>='0' && *s
<='9')
1157 if (*s
>='a' && *s
<='f')
1158 data
[i
]|=*s
-'a'+'\xa';
1159 if (*s
>='A' && *s
<='F')
1160 data
[i
]|=*s
-'A'+'\xa';
1164 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1167 /* read the next line */
1168 if (!_wine_read_line(F
,buf
,buflen
))
1175 /******************************************************************************
1176 * _wine_loadsubreg [Internal]
1178 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1184 buf
=xmalloc(10);buflen
=10;
1185 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1189 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1193 if (ver
!=REGISTRY_SAVE_VERSION
) {
1194 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1198 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1202 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1211 /******************************************************************************
1212 * _wine_loadreg [Internal]
1214 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1218 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1222 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1225 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1233 /******************************************************************************
1234 * _flush_registry [Internal]
1236 * This function allow to flush section of the internal registry. It is mainly
1237 * implements to fix a problem with the global HKU and the local HKU.
1238 * Those two files are read to build the HKU\.Default branch to finaly copy
1239 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1240 * all the global HKU are saved onto the user's personal version of HKU hive.
1244 /* Forward declaration of recusive agent */
1245 static void _flush_reg(LPKEYSTRUCT from
);
1247 static void _flush_registry( LPKEYSTRUCT from
)
1249 /* make sure we have something... */
1253 /* Launch the recusive agent on sub branches */
1254 _flush_reg( from
->nextsub
);
1255 _flush_reg( from
->next
);
1257 /* Initialize pointers */
1258 from
->nextsub
= NULL
;
1261 static void _flush_reg( LPKEYSTRUCT from
)
1265 /* make sure we have something... */
1270 * do the same for the child keys
1272 if (from
->nextsub
!= NULL
)
1273 _flush_reg(from
->nextsub
);
1276 * do the same for the sibling keys
1278 if (from
->next
!= NULL
)
1279 _flush_reg(from
->next
);
1282 * iterate through this key's values and delete them
1284 for (j
=0;j
<from
->nrofvalues
;j
++)
1286 free( (from
->values
+j
)->name
);
1287 free( (from
->values
+j
)->data
);
1291 * free the structure
1298 /******************************************************************************
1299 * _copy_registry [Internal]
1301 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1309 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1311 for (j
=0;j
<from
->nrofvalues
;j
++) {
1315 valfrom
= from
->values
+j
;
1317 if (name
) name
=strdupW(name
);
1318 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1319 memcpy(data
,valfrom
->data
,valfrom
->len
);
1327 valfrom
->lastmodified
1330 _copy_registry(from
,lpxkey
);
1336 /* WINDOWS 95 REGISTRY LOADER */
1338 * Structure of a win95 registry database.
1340 * 0 : "CREG" - magic
1342 * 8 : DWORD offset_of_RGDB_part
1343 * 0C..0F: ? (someone fill in please)
1344 * 10: WORD number of RGDB blocks
1346 * 14: WORD always 0000?
1347 * 16: WORD always 0001?
1348 * 18..1F: ? (someone fill in please)
1352 * 0 : "RGKN" - magic
1353 * 4 : DWORD offset to first RGDB section
1354 * 8 : DWORD offset to the root record
1355 * C..0x1B: ? (fill in)
1356 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1358 * Disk Key Entry Structure:
1359 * 00: DWORD - Free entry indicator(?)
1360 * 04: DWORD - Hash = sum of bytes of keyname
1361 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1362 * 0C: DWORD - disk address of PreviousLevel Key.
1363 * 10: DWORD - disk address of Next Sublevel Key.
1364 * 14: DWORD - disk address of Next Key (on same level).
1365 * DKEP>18: WORD - Nr, Low Significant part.
1366 * 1A: WORD - Nr, High Significant part.
1368 * The disk address always points to the nr part of the previous key entry
1369 * of the referenced key. Don't ask me why, or even if I got this correct
1370 * from staring at 1kg of hexdumps. (DKEP)
1372 * The High significant part of the structure seems to equal the number
1373 * of the RGDB section. The low significant part is a unique ID within
1376 * There are two minor corrections to the position of that structure.
1377 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1378 * the DKE reread from there.
1379 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1380 * CPS - I have not experienced the above phenomenon in my registry files
1383 * 00: "RGDB" - magic
1384 * 04: DWORD offset to next RGDB section
1386 * 0C: WORD always 000d?
1387 * 0E: WORD RGDB block number
1388 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1390 * 20.....: disk keys
1393 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1394 * 08: WORD nrLS - low significant part of NR
1395 * 0A: WORD nrHS - high significant part of NR
1396 * 0C: DWORD bytesused - bytes used in this structure.
1397 * 10: WORD name_len - length of name in bytes. without \0
1398 * 12: WORD nr_of_values - number of values.
1399 * 14: char name[name_len] - name string. No \0.
1400 * 14+name_len: disk values
1401 * nextkeyoffset: ... next disk key
1404 * 00: DWORD type - value type (hmm, could be WORD too)
1405 * 04: DWORD - unknown, usually 0
1406 * 08: WORD namelen - length of Name. 0 means name=NULL
1407 * 0C: WORD datalen - length of Data.
1408 * 10: char name[namelen] - name, no \0
1409 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1410 * 10+namelen+datalen: next values or disk key
1412 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1413 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1414 * structure) and reading another RGDB_section.
1415 * repeat until end of file.
1417 * An interesting relationship exists in RGDB_section. The value at offset
1418 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1419 * idea at the moment what this means. (Kevin Cozens)
1421 * FIXME: this description needs some serious help, yes.
1424 struct _w95keyvalue
{
1426 unsigned short datalen
;
1428 unsigned char *data
;
1436 struct _w95keyvalue
*values
;
1437 struct _w95key
*prevlvl
;
1438 struct _w95key
*nextsub
;
1439 struct _w95key
*next
;
1453 /******************************************************************************
1454 * _w95_processKey [Internal]
1456 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1457 int nrLS
, int nrMS
, struct _w95_info
*info
)
1460 /* Disk Key Header structure (RGDB part) */
1462 unsigned long nextkeyoff
;
1463 unsigned short nrLS
;
1464 unsigned short nrMS
;
1465 unsigned long bytesused
;
1466 unsigned short keynamelen
;
1467 unsigned short values
;
1470 /* disk key values or nothing */
1472 /* Disk Key Value structure */
1476 unsigned short valnamelen
;
1477 unsigned short valdatalen
;
1478 /* valname, valdata */
1484 char *rgdbdata
= info
->rgdbbuffer
;
1485 int nbytes
= info
->rgdbsize
;
1486 char *curdata
= rgdbdata
;
1487 char *end
= rgdbdata
+ nbytes
;
1489 char *next
= rgdbdata
;
1495 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1497 memcpy(&off_next_rgdb
,curdata
+4,4);
1498 next
= curdata
+ off_next_rgdb
;
1499 nrgdb
= (int) *((short *)curdata
+ 7);
1501 } while (nrgdb
!= nrMS
&& (next
< end
));
1503 /* curdata now points to the start of the right RGDB section */
1506 #define XREAD(whereto,len) \
1507 if ((curdata + len) <= end) {\
1508 memcpy(whereto,curdata,len);\
1513 while (curdata
< next
) {
1514 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1516 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1517 if (xdkh
->nrLS
== nrLS
) {
1518 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1519 curdata
+= sizeof(dkh
);
1522 curdata
+= xdkh
->nextkeyoff
;
1525 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1527 if (nrgdb
!= dkh
.nrMS
)
1530 assert((dkh
.keynamelen
<2) || curdata
[0]);
1531 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1532 curdata
+= dkh
.keynamelen
;
1534 for (i
=0;i
< dkh
.values
; i
++) {
1540 XREAD(&dkv
,sizeof(dkv
));
1542 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1543 curdata
+= dkv
.valnamelen
;
1545 if ((1 << dkv
.type
) & UNICONVMASK
) {
1546 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1547 len
= 2*(dkv
.valdatalen
+ 1);
1549 /* I don't think we want to NULL terminate all data */
1550 data
= xmalloc(dkv
.valdatalen
);
1551 memcpy (data
, curdata
, dkv
.valdatalen
);
1552 len
= dkv
.valdatalen
;
1555 curdata
+= dkv
.valdatalen
;
1569 /******************************************************************************
1570 * _w95_walkrgkn [Internal]
1572 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1573 struct _w95_info
*info
)
1576 /* Disk Key Entry structure (RGKN part) */
1580 unsigned long x3
;/*usually 0xFFFFFFFF */
1581 unsigned long prevlvl
;
1582 unsigned long nextsub
;
1584 unsigned short nrLS
;
1585 unsigned short nrMS
;
1586 } *dke
= (struct dke
*)off
;
1590 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1593 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1594 /* XXX <-- This is a hack*/
1599 if (dke
->nextsub
!= -1 &&
1600 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1601 && (dke
->nextsub
> 0x20)) {
1603 _w95_walkrgkn(lpxkey
,
1604 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1608 if (dke
->next
!= -1 &&
1609 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1610 (dke
->next
> 0x20)) {
1611 _w95_walkrgkn(prevkey
,
1612 info
->rgknbuffer
+ dke
->next
- 0x20,
1620 /******************************************************************************
1621 * _w95_loadreg [Internal]
1623 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1627 unsigned long where
,version
,rgdbsection
,end
;
1628 struct _w95_info info
;
1630 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1632 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1633 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1634 if (hfd
==HFILE_ERROR
)
1637 if (4!=_lread(hfd
,magic
,4))
1639 if (strcmp(magic
,"CREG")) {
1640 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1643 if (4!=_lread(hfd
,&version
,4))
1645 if (4!=_lread(hfd
,&rgdbsection
,4))
1647 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1649 if (4!=_lread(hfd
,magic
,4))
1651 if (strcmp(magic
,"RGKN")) {
1652 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1656 /* STEP 1: Keylink structures */
1657 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1662 info
.rgknsize
= end
- where
;
1663 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1664 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1667 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1670 end
= hfdinfo
.nFileSizeLow
;
1671 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1673 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1676 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1677 info
.rgdbsize
= end
- rgdbsection
;
1679 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1683 _w95_walkrgkn(lpkey
, NULL
, &info
);
1685 free (info
.rgdbbuffer
);
1686 free (info
.rgknbuffer
);
1690 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1693 reghack - windows 3.11 registry data format demo program.
1695 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1696 a combined hash table and tree description, and finally a text table.
1698 The header is obvious from the struct header. The taboff1 and taboff2
1699 fields are always 0x20, and their usage is unknown.
1701 The 8-byte entry table has various entry types.
1703 tabent[0] is a root index. The second word has the index of the root of
1705 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1706 the index of the key/value that has that hash. Data with the same
1707 hash value are on a circular list. The other three words in the
1708 hash entry are always zero.
1709 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1710 entry: dirent and keyent/valent. They are identified by context.
1711 tabent[freeidx] is the first free entry. The first word in a free entry
1712 is the index of the next free entry. The last has 0 as a link.
1713 The other three words in the free list are probably irrelevant.
1715 Entries in text table are preceeded by a word at offset-2. This word
1716 has the value (2*index)+1, where index is the referring keyent/valent
1717 entry in the table. I have no suggestion for the 2* and the +1.
1718 Following the word, there are N bytes of data, as per the keyent/valent
1719 entry length. The offset of the keyent/valent entry is from the start
1720 of the text table to the first data byte.
1722 This information is not available from Microsoft. The data format is
1723 deduced from the reg.dat file by me. Mistakes may
1724 have been made. I claim no rights and give no guarantees for this program.
1726 Tor Sjøwall, tor@sn.no
1729 /* reg.dat header format */
1730 struct _w31_header
{
1731 char cookie
[8]; /* 'SHCC3.10' */
1732 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1733 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1734 unsigned long tabcnt
; /* number of entries in index table */
1735 unsigned long textoff
; /* offset of text part */
1736 unsigned long textsize
; /* byte size of text part */
1737 unsigned short hashsize
; /* hash size */
1738 unsigned short freeidx
; /* free index */
1741 /* generic format of table entries */
1742 struct _w31_tabent
{
1743 unsigned short w0
, w1
, w2
, w3
;
1746 /* directory tabent: */
1747 struct _w31_dirent
{
1748 unsigned short sibling_idx
; /* table index of sibling dirent */
1749 unsigned short child_idx
; /* table index of child dirent */
1750 unsigned short key_idx
; /* table index of key keyent */
1751 unsigned short value_idx
; /* table index of value valent */
1755 struct _w31_keyent
{
1756 unsigned short hash_idx
; /* hash chain index for string */
1757 unsigned short refcnt
; /* reference count */
1758 unsigned short length
; /* length of string */
1759 unsigned short string_off
; /* offset of string in text table */
1763 struct _w31_valent
{
1764 unsigned short hash_idx
; /* hash chain index for string */
1765 unsigned short refcnt
; /* reference count */
1766 unsigned short length
; /* length of string */
1767 unsigned short string_off
; /* offset of string in text table */
1770 /* recursive helper function to display a directory tree */
1772 __w31_dumptree( unsigned short idx
,
1774 struct _w31_tabent
*tab
,
1775 struct _w31_header
*head
,
1777 time_t lastmodified
,
1780 struct _w31_dirent
*dir
;
1781 struct _w31_keyent
*key
;
1782 struct _w31_valent
*val
;
1783 LPKEYSTRUCT xlpkey
= NULL
;
1785 static char tail
[400];
1788 dir
=(struct _w31_dirent
*)&tab
[idx
];
1791 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1793 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1794 tail
[key
->length
]='\0';
1795 /* all toplevel entries AND the entries in the
1796 * toplevel subdirectory belong to \SOFTWARE\Classes
1798 if (!level
&& !lstrcmpA(tail
,".classes")) {
1799 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1800 idx
=dir
->sibling_idx
;
1803 name
=strdupA2W(tail
);
1805 xlpkey
=_find_or_add_key(lpkey
,name
);
1807 /* only add if leaf node or valued node */
1808 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1809 if (dir
->value_idx
) {
1810 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1811 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1812 tail
[val
->length
]='\0';
1813 value
=strdupA2W(tail
);
1814 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1818 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1820 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1821 idx
=dir
->sibling_idx
;
1826 /******************************************************************************
1827 * _w31_loadreg [Internal]
1829 void _w31_loadreg(void) {
1831 struct _w31_header head
;
1832 struct _w31_tabent
*tab
;
1836 BY_HANDLE_FILE_INFORMATION hfinfo
;
1837 time_t lastmodified
;
1840 TRACE(reg
,"(void)\n");
1842 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1843 if (hf
==HFILE_ERROR
)
1846 /* read & dump header */
1847 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1848 ERR(reg
, "reg.dat is too short.\n");
1852 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1853 ERR(reg
, "reg.dat has bad signature.\n");
1858 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1859 /* read and dump index table */
1861 if (len
!=_lread(hf
,tab
,len
)) {
1862 ERR(reg
,"couldn't read %d bytes.\n",len
);
1869 txt
= xmalloc(head
.textsize
);
1870 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1871 ERR(reg
,"couldn't seek to textblock.\n");
1877 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1878 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1885 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1886 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1892 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1893 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1894 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1902 /**********************************************************************************
1903 * SHELL_LoadRegistry [Internal]
1905 void SHELL_LoadRegistry( void )
1909 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1912 TRACE(reg
,"(void)\n");
1914 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1915 HKU
= lookup_hkey(HKEY_USERS
);
1916 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1918 /* Load windows 3.1 entries */
1920 /* Load windows 95 entries */
1921 _w95_loadreg("C:\\system.1st", HKLM
);
1922 _w95_loadreg("system.dat", HKLM
);
1923 _w95_loadreg("user.dat", HKU
);
1926 * Load the global HKU hive directly from /usr/local/etc
1928 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1931 * Load the global machine defaults directly form /usr/local/etc
1933 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1935 /* Get current user info */
1936 pwd
=getpwuid(getuid());
1939 * Load the user saved registries
1941 if ( (pwd
!= NULL
) &&
1942 (pwd
->pw_dir
!= NULL
) )
1945 * Load user's personal versions of global HKU/.Default keys
1948 strlen(pwd
->pw_dir
)+
1949 strlen(WINE_PREFIX
)+
1950 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1952 strcpy(fn
, pwd
->pw_dir
);
1953 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1954 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1958 * Load HKCU, attempt to get the registry location from the config
1959 * file first, if exist, load and keep going.
1961 fn
= xmalloc( MAX_PATHNAME_LEN
);
1962 if ( PROFILE_GetWineIniString(
1967 MAX_PATHNAME_LEN
- 1))
1969 _wine_loadreg(HKCU
,fn
,0);
1974 strlen(pwd
->pw_dir
)+
1975 strlen(WINE_PREFIX
)+
1976 strlen(SAVE_CURRENT_USER
)+2);
1978 strcpy(fn
, pwd
->pw_dir
);
1979 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1980 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
1984 * Load HKLM, attempt to get the registry location from the config
1985 * file first, if exist, load and keep going.
1987 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1988 if ( PROFILE_GetWineIniString(
1990 "LocalMachineFileName",
1993 MAX_PATHNAME_LEN
- 1))
1995 _wine_loadreg(HKLM
, fn
, 0);
2000 strlen(pwd
->pw_dir
)+
2001 strlen(WINE_PREFIX
)+
2002 strlen(SAVE_LOCAL_MACHINE
)+2);
2004 strcpy(fn
,pwd
->pw_dir
);
2005 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
2006 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
2011 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
2015 * Obtain the handle of the HKU\.Default key.
2016 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2018 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
2019 lpkey
= lookup_hkey(hkey
);
2021 WARN(reg
,"Could not create global user default key\n");
2023 _copy_registry(lpkey
, HKCU
);
2028 * Since HKU is built from the global HKU and the local user HKU file we must
2029 * flush the HKU tree we have built at this point otherwise the part brought
2030 * in from the global HKU is saved into the local HKU. To avoid this
2031 * useless dupplication of HKU keys we reread the local HKU key.
2034 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2035 _flush_registry(HKU
);
2037 /* Reload user's local HKU hive */
2039 strlen(pwd
->pw_dir
)+
2040 strlen(WINE_PREFIX
)+
2041 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
2043 strcpy(fn
,pwd
->pw_dir
);
2044 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2046 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2051 * Make sure the update mode is there
2053 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2055 DWORD junk
,type
,len
;
2059 if (( RegQueryValueExA(
2065 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2067 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2075 /********************* API FUNCTIONS ***************************************/
2079 * All functions are stubs to RegOpenKeyEx32W where all the
2083 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2084 * RegOpenKey32W -> RegOpenKeyEx32W
2088 /******************************************************************************
2089 * RegOpenKeyEx32W [ADVAPI32.150]
2090 * Opens the specified key
2092 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2095 * hkey [I] Handle of open key
2096 * lpszSubKey [I] Name of subkey to open
2097 * dwReserved [I] Reserved - must be zero
2098 * samDesired [I] Security access mask
2099 * retkey [O] Address of handle of open key
2102 * Success: ERROR_SUCCESS
2103 * Failure: Error code
2105 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2106 REGSAM samDesired
, LPHKEY retkey
)
2108 LPKEYSTRUCT lpNextKey
,lpxkey
;
2112 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2115 lpNextKey
= lookup_hkey( hkey
);
2117 return ERROR_INVALID_HANDLE
;
2119 if (!lpszSubKey
|| !*lpszSubKey
) {
2120 /* Either NULL or pointer to empty string, so return a new handle
2121 to the original hkey */
2123 add_handle(currenthandle
,lpNextKey
,samDesired
);
2124 *retkey
=currenthandle
;
2125 return ERROR_SUCCESS
;
2128 if (lpszSubKey
[0] == '\\') {
2129 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2130 return ERROR_BAD_PATHNAME
;
2133 split_keypath(lpszSubKey
,&wps
,&wpc
);
2135 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2139 lpxkey
=lpNextKey
->nextsub
;
2141 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2144 lpxkey
=lpxkey
->next
;
2148 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
2150 return ERROR_FILE_NOT_FOUND
;
2157 add_handle(currenthandle
,lpxkey
,samDesired
);
2158 *retkey
= currenthandle
;
2159 TRACE(reg
," Returning %x\n", currenthandle
);
2161 return ERROR_SUCCESS
;
2165 /******************************************************************************
2166 * RegOpenKeyEx32A [ADVAPI32.149]
2168 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2169 REGSAM samDesired
, LPHKEY retkey
)
2171 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2174 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2176 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2182 /******************************************************************************
2183 * RegOpenKey32W [ADVAPI32.151]
2186 * hkey [I] Handle of open key
2187 * lpszSubKey [I] Address of name of subkey to open
2188 * retkey [O] Address of handle of open key
2191 * Success: ERROR_SUCCESS
2192 * Failure: Error code
2194 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2196 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2197 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2201 /******************************************************************************
2202 * RegOpenKey32A [ADVAPI32.148]
2204 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2207 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2208 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2209 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2215 /******************************************************************************
2216 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2218 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2220 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2221 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2228 * All those functions convert their respective
2229 * arguments and call RegCreateKeyExW at the end.
2231 * We stay away from the Ex functions as long as possible because there are
2232 * differences in the return values
2235 * RegCreateKeyEx32A \
2236 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2240 /******************************************************************************
2241 * RegCreateKeyEx32W [ADVAPI32.131]
2244 * hkey [I] Handle of an open key
2245 * lpszSubKey [I] Address of subkey name
2246 * dwReserved [I] Reserved - must be 0
2247 * lpszClass [I] Address of class string
2248 * fdwOptions [I] Special options flag
2249 * samDesired [I] Desired security access
2250 * lpSecAttribs [I] Address of key security structure
2251 * retkey [O] Address of buffer for opened handle
2252 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2254 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2255 DWORD dwReserved
, LPWSTR lpszClass
,
2256 DWORD fdwOptions
, REGSAM samDesired
,
2257 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2258 LPHKEY retkey
, LPDWORD lpDispos
)
2260 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2264 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2265 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2266 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2268 lpNextKey
= lookup_hkey(hkey
);
2270 return ERROR_INVALID_HANDLE
;
2272 /* Check for valid options */
2273 switch(fdwOptions
) {
2274 case REG_OPTION_NON_VOLATILE
:
2275 case REG_OPTION_VOLATILE
:
2276 case REG_OPTION_BACKUP_RESTORE
:
2279 return ERROR_INVALID_PARAMETER
;
2282 /* Sam has to be a combination of the following */
2284 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2285 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2286 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2287 return ERROR_INVALID_PARAMETER
;
2289 if (!lpszSubKey
|| !*lpszSubKey
) {
2291 add_handle(currenthandle
,lpNextKey
,samDesired
);
2292 *retkey
=currenthandle
;
2293 TRACE(reg
, "Returning %x\n", currenthandle
);
2294 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2295 return ERROR_SUCCESS
;
2298 if (lpszSubKey
[0] == '\\') {
2299 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2300 return ERROR_BAD_PATHNAME
;
2303 split_keypath(lpszSubKey
,&wps
,&wpc
);
2305 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2308 lpxkey
=lpNextKey
->nextsub
;
2310 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2312 lpxkey
=lpxkey
->next
;
2321 add_handle(currenthandle
,lpxkey
,samDesired
);
2322 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2323 *retkey
= currenthandle
;
2324 TRACE(reg
, "Returning %x\n", currenthandle
);
2326 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2328 return ERROR_SUCCESS
;
2331 /* Good. Now the hard part */
2333 lplpPrevKey
= &(lpNextKey
->nextsub
);
2334 lpxkey
= *lplpPrevKey
;
2336 lplpPrevKey
= &(lpxkey
->next
);
2337 lpxkey
= *lplpPrevKey
;
2339 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2340 if (!*lplpPrevKey
) {
2342 TRACE(reg
, "Returning OUTOFMEMORY\n");
2343 return ERROR_OUTOFMEMORY
;
2345 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2346 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
2347 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2348 (*lplpPrevKey
)->next
= NULL
;
2349 (*lplpPrevKey
)->nextsub
= NULL
;
2350 (*lplpPrevKey
)->values
= NULL
;
2351 (*lplpPrevKey
)->nrofvalues
= 0;
2352 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2354 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2356 (*lplpPrevKey
)->class = NULL
;
2357 lpNextKey
= *lplpPrevKey
;
2361 add_handle(currenthandle
,lpNextKey
,samDesired
);
2363 /*FIXME: flag handling correct? */
2364 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2366 lpNextKey
->class = strdupW(lpszClass
);
2368 lpNextKey
->class = NULL
;
2369 *retkey
= currenthandle
;
2370 TRACE(reg
, "Returning %x\n", currenthandle
);
2372 *lpDispos
= REG_CREATED_NEW_KEY
;
2374 return ERROR_SUCCESS
;
2378 /******************************************************************************
2379 * RegCreateKeyEx32A [ADVAPI32.130]
2381 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2382 LPSTR lpszClass
, DWORD fdwOptions
,
2384 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2385 LPHKEY retkey
, LPDWORD lpDispos
)
2387 LPWSTR lpszSubKeyW
, lpszClassW
;
2390 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2391 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2394 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2395 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2397 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2398 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2401 if(lpszSubKeyW
) free(lpszSubKeyW
);
2402 if(lpszClassW
) free(lpszClassW
);
2408 /******************************************************************************
2409 * RegCreateKey32W [ADVAPI32.132]
2411 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2414 LPKEYSTRUCT lpNextKey
;
2416 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2418 /* This check is here because the return value is different than the
2419 one from the Ex functions */
2420 lpNextKey
= lookup_hkey(hkey
);
2422 return ERROR_BADKEY
;
2424 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2425 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2430 /******************************************************************************
2431 * RegCreateKey32A [ADVAPI32.129]
2433 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2438 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2439 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2440 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2441 if(lpszSubKeyW
) free(lpszSubKeyW
);
2446 /******************************************************************************
2447 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2449 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2451 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2452 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2457 * Query Value Functions
2458 * Win32 differs between keynames and valuenames.
2459 * multiple values may belong to one key, the special value
2460 * with name NULL is the default value used by the win31
2464 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2465 * RegQueryValue32W -> RegQueryValueEx32W
2469 /******************************************************************************
2470 * RegQueryValueEx32W [ADVAPI32.158]
2471 * Retrieves type and data for a specified name associated with an open key
2474 * hkey [I] Handle of key to query
2475 * lpValueName [I] Name of value to query
2476 * lpdwReserved [I] Reserved - must be NULL
2477 * lpdwType [O] Address of buffer for value type. If NULL, the type
2479 * lpbData [O] Address of data buffer. If NULL, the actual data is
2481 * lpcbData [I/O] Address of data buffer size
2484 * ERROR_SUCCESS: Success
2485 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2486 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2488 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2489 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2490 LPBYTE lpbData
, LPDWORD lpcbData
)
2496 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2497 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2499 lpkey
= lookup_hkey(hkey
);
2502 return ERROR_INVALID_HANDLE
;
2504 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2505 return ERROR_INVALID_PARAMETER
;
2507 /* An empty name string is equivalent to NULL */
2508 if (lpValueName
&& !*lpValueName
)
2511 if (lpValueName
==NULL
)
2512 { /* Use key's unnamed or default value, if any */
2513 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2514 if (lpkey
->values
[i
].name
==NULL
)
2518 { /* Search for the key name */
2519 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2520 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2524 if (i
==lpkey
->nrofvalues
)
2525 { TRACE(reg
," Key not found\n");
2526 if (lpValueName
==NULL
)
2527 { /* Empty keyname not found */
2529 { *(WCHAR
*)lpbData
= 0;
2534 TRACE(reg
, " Returning an empty string\n");
2535 return ERROR_SUCCESS
;
2537 return ERROR_FILE_NOT_FOUND
;
2540 ret
= ERROR_SUCCESS
;
2542 if (lpdwType
) /* type required ?*/
2543 *lpdwType
= lpkey
->values
[i
].type
;
2545 if (lpbData
) /* data required ?*/
2546 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2547 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2549 ret
= ERROR_MORE_DATA
;
2552 if (lpcbData
) /* size required ?*/
2553 { *lpcbData
= lpkey
->values
[i
].len
;
2556 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2558 TRACE(reg
," (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2564 /******************************************************************************
2565 * RegQueryValue32W [ADVAPI32.159]
2567 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2573 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2574 lpcbData
?*lpcbData
:0);
2576 /* Only open subkey, if we really do descend */
2577 if (lpszSubKey
&& *lpszSubKey
) {
2578 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2579 if (ret
!= ERROR_SUCCESS
) {
2580 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2587 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2595 /******************************************************************************
2596 * RegQueryValueEx32A [ADVAPI32.157]
2599 * the documantation is wrong: if the buffer is to small it remains untouched
2601 * FIXME: check returnvalue (len) for an empty key
2603 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2604 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2605 LPBYTE lpbData
, LPDWORD lpcbData
)
2607 LPWSTR lpszValueNameW
;
2608 LPBYTE mybuf
= NULL
;
2609 DWORD ret
, mytype
, mylen
= 0;
2611 TRACE(reg
,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2612 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2614 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2615 { return ERROR_INVALID_PARAMETER
;
2618 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2620 /* get just the type first */
2621 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2623 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2624 { if(lpszValueNameW
) free(lpszValueNameW
);
2628 if (lpcbData
) /* at least length requested? */
2629 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2630 { if (lpbData
) /* value requested? */
2631 { mylen
= 2*( *lpcbData
);
2632 mybuf
= (LPBYTE
)xmalloc( mylen
);
2635 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2637 if (ret
== ERROR_SUCCESS
)
2639 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2643 *lpcbData
= mylen
/2; /* size is in byte! */
2645 else /* no strings, call it straight */
2646 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2650 if (lpdwType
) /* type when requested */
2651 { *lpdwType
= mytype
;
2654 TRACE(reg
," (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2656 if(mybuf
) free(mybuf
);
2657 if(lpszValueNameW
) free(lpszValueNameW
);
2662 /******************************************************************************
2663 * RegQueryValueEx16 [KERNEL.225]
2665 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2666 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2667 LPBYTE lpbData
, LPDWORD lpcbData
)
2669 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2670 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2671 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2672 lpbData
, lpcbData
);
2676 /******************************************************************************
2677 * RegQueryValue32A [ADVAPI32.156]
2679 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2685 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2686 lpcbData
?*lpcbData
:0);
2688 if (lpszSubKey
&& *lpszSubKey
) {
2689 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2690 if( ret
!= ERROR_SUCCESS
)
2696 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2699 RegCloseKey( xhkey
);
2704 /******************************************************************************
2705 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2708 * Is this HACK still applicable?
2711 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2712 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2715 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2718 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2719 lpcbData
?*lpcbData
:0);
2722 *lpcbData
&= 0xFFFF;
2723 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2728 * Setting values of Registry keys
2731 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2732 * RegSetValue32W -> RegSetValueEx32W
2736 /******************************************************************************
2737 * RegSetValueEx32W [ADVAPI32.170]
2738 * Sets the data and type of a value under a register key
2741 * hkey [I] Handle of key to set value for
2742 * lpszValueName [I] Name of value to set
2743 * dwReserved [I] Reserved - must be zero
2744 * dwType [I] Flag for value type
2745 * lpbData [I] Address of value data
2746 * cbData [I] Size of value data
2749 * Success: ERROR_SUCCESS
2750 * Failure: Error code
2753 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2755 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2756 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2762 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2763 dwReserved
, dwType
, lpbData
, cbData
);
2765 lpkey
= lookup_hkey( hkey
);
2768 return ERROR_INVALID_HANDLE
;
2770 lpkey
->flags
|= REG_OPTION_TAINTED
;
2772 if (lpszValueName
==NULL
) {
2773 /* Sets type and name for key's unnamed or default value */
2774 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2775 if (lpkey
->values
[i
].name
==NULL
)
2778 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2779 if ( lpkey
->values
[i
].name
&&
2780 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2784 if (i
==lpkey
->nrofvalues
) {
2785 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2787 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2789 lpkey
->nrofvalues
++;
2790 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2792 if (lpkey
->values
[i
].name
==NULL
) {
2794 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2796 lpkey
->values
[i
].name
= NULL
;
2799 if (dwType
== REG_SZ
)
2800 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2802 lpkey
->values
[i
].len
= cbData
;
2803 lpkey
->values
[i
].type
= dwType
;
2804 if (lpkey
->values
[i
].data
!=NULL
)
2805 free(lpkey
->values
[i
].data
);
2806 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2807 lpkey
->values
[i
].lastmodified
= time(NULL
);
2808 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2809 return ERROR_SUCCESS
;
2813 /******************************************************************************
2814 * RegSetValueEx32A [ADVAPI32.169]
2817 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2819 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2820 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2824 LPWSTR lpszValueNameW
;
2828 return (ERROR_INVALID_PARAMETER
);
2830 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2831 dwReserved
,dwType
,lpbData
,cbData
);
2833 if ((1<<dwType
) & UNICONVMASK
)
2834 { if (dwType
== REG_SZ
)
2835 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2837 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2838 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2845 lpszValueNameW
= strdupA2W(lpszValueName
);
2847 lpszValueNameW
= NULL
;
2849 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2852 free(lpszValueNameW
);
2861 /******************************************************************************
2862 * RegSetValueEx16 [KERNEL.226]
2864 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2865 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2867 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2868 dwReserved
,dwType
,lpbData
,cbData
);
2869 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2874 /******************************************************************************
2875 * RegSetValue32W [ADVAPI32.171]
2877 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2878 LPCWSTR lpszData
, DWORD cbData
)
2883 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2884 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2886 if (lpszSubKey
&& *lpszSubKey
) {
2887 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2888 if (ret
!=ERROR_SUCCESS
)
2892 if (dwType
!=REG_SZ
) {
2893 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2896 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2897 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2898 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2900 cbData
=2*lstrlenW(lpszData
)+2;
2902 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2909 /******************************************************************************
2910 * RegSetValue32A [ADVAPI32.168]
2913 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2914 LPCSTR lpszData
, DWORD cbData
)
2919 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2920 if (lpszSubKey
&& *lpszSubKey
) {
2921 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2922 if (ret
!=ERROR_SUCCESS
)
2927 if (dwType
!=REG_SZ
) {
2928 TRACE(reg
,"dwType=%ld!\n",dwType
);
2931 if (cbData
!=strlen(lpszData
)+1)
2932 cbData
=strlen(lpszData
)+1;
2933 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2940 /******************************************************************************
2941 * RegSetValue16 [KERNEL.221] [SHELL.5]
2943 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2944 LPCSTR lpszData
, DWORD cbData
)
2946 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2947 debugstr_a(lpszData
),cbData
);
2948 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2956 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2957 * RegEnumKey32W -> RegEnumKeyEx32W
2961 /******************************************************************************
2962 * RegEnumKeyEx32W [ADVAPI32.139]
2965 * hkey [I] Handle to key to enumerate
2966 * iSubKey [I] Index of subkey to enumerate
2967 * lpszName [O] Buffer for subkey name
2968 * lpcchName [O] Size of subkey buffer
2969 * lpdwReserved [I] Reserved
2970 * lpszClass [O] Buffer for class string
2971 * lpcchClass [O] Size of class buffer
2972 * ft [O] Time key last written to
2974 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2975 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2976 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2979 LPKEYSTRUCT lpkey
,lpxkey
;
2981 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2982 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2984 lpkey
= lookup_hkey( hkey
);
2986 return ERROR_INVALID_HANDLE
;
2988 if (!lpkey
->nextsub
)
2989 return ERROR_NO_MORE_ITEMS
;
2990 lpxkey
=lpkey
->nextsub
;
2992 /* Traverse the subkeys */
2993 while (iSubkey
&& lpxkey
) {
2995 lpxkey
=lpxkey
->next
;
2998 if (iSubkey
|| !lpxkey
)
2999 return ERROR_NO_MORE_ITEMS
;
3000 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
3001 return ERROR_MORE_DATA
;
3002 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
3005 *lpcchName
= lstrlenW(lpszName
);
3008 /* FIXME: what should we write into it? */
3012 return ERROR_SUCCESS
;
3016 /******************************************************************************
3017 * RegEnumKey32W [ADVAPI32.140]
3019 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3024 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3025 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
3029 /******************************************************************************
3030 * RegEnumKeyEx32A [ADVAPI32.138]
3032 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3033 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3034 LPSTR lpszClass
, LPDWORD lpcchClass
,
3037 DWORD ret
,lpcchNameW
,lpcchClassW
;
3038 LPWSTR lpszNameW
,lpszClassW
;
3041 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3042 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3045 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3046 lpcchNameW
= *lpcchName
;
3052 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3053 lpcchClassW
= *lpcchClass
;
3068 if (ret
==ERROR_SUCCESS
) {
3069 lstrcpyWtoA(lpszName
,lpszNameW
);
3070 *lpcchName
=strlen(lpszName
);
3072 lstrcpyWtoA(lpszClass
,lpszClassW
);
3073 *lpcchClass
=strlen(lpszClass
);
3084 /******************************************************************************
3085 * RegEnumKey32A [ADVAPI32.137]
3087 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3092 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3093 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3098 /******************************************************************************
3099 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3101 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3104 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3105 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3110 * Enumerate Registry Values
3113 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3117 /******************************************************************************
3118 * RegEnumValue32W [ADVAPI32.142]
3121 * hkey [I] Handle to key to query
3122 * iValue [I] Index of value to query
3123 * lpszValue [O] Value string
3124 * lpcchValue [I/O] Size of value buffer (in wchars)
3125 * lpdReserved [I] Reserved
3126 * lpdwType [O] Type code
3127 * lpbData [O] Value data
3128 * lpcbData [I/O] Size of data buffer (in bytes)
3130 * Note: wide character functions that take and/or return "character counts"
3131 * use TCHAR (that is unsigned short or char) not byte counts.
3133 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3134 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3135 LPDWORD lpdwType
, LPBYTE lpbData
,
3141 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3142 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3144 lpkey
= lookup_hkey( hkey
);
3146 if (!lpcbData
&& lpbData
)
3147 return ERROR_INVALID_PARAMETER
;
3150 return ERROR_INVALID_HANDLE
;
3152 if (lpkey
->nrofvalues
<= iValue
)
3153 return ERROR_NO_MORE_ITEMS
;
3155 val
= &(lpkey
->values
[iValue
]);
3158 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3159 *lpcchValue
= lstrlenW(val
->name
)+1;
3160 return ERROR_MORE_DATA
;
3162 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3163 *lpcchValue
=lstrlenW(val
->name
);
3169 /* Can be NULL if the type code is not required */
3171 *lpdwType
= val
->type
;
3174 if (val
->len
>*lpcbData
)
3175 return ERROR_MORE_DATA
;
3176 memcpy(lpbData
,val
->data
,val
->len
);
3177 *lpcbData
= val
->len
;
3180 debug_print_value ( val
->data
, val
);
3181 return ERROR_SUCCESS
;
3185 /******************************************************************************
3186 * RegEnumValue32A [ADVAPI32.141]
3188 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3189 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3190 LPDWORD lpdwType
, LPBYTE lpbData
,
3195 DWORD ret
,lpcbDataW
;
3198 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3199 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3201 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3203 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3204 lpcbDataW
= *lpcbData
;
3208 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3209 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3214 if (ret
==ERROR_SUCCESS
) {
3215 lstrcpyWtoA(lpszValue
,lpszValueW
);
3217 if ((1<<dwType
) & UNICONVMASK
) {
3218 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3220 if (lpcbDataW
> *lpcbData
)
3221 ret
= ERROR_MORE_DATA
;
3223 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3225 *lpcbData
= lpcbDataW
;
3228 if (lpbDataW
) free(lpbDataW
);
3229 if (lpszValueW
) free(lpszValueW
);
3234 /******************************************************************************
3235 * RegEnumValue16 [KERNEL.223]
3237 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3238 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3239 LPDWORD lpdwType
, LPBYTE lpbData
,
3242 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3243 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3244 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3245 lpdwType
, lpbData
, lpcbData
);
3249 /******************************************************************************
3250 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3251 * Releases the handle of the specified key
3254 * hkey [I] Handle of key to close
3257 * Success: ERROR_SUCCESS
3258 * Failure: Error code
3260 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3262 TRACE(reg
,"(%x)\n",hkey
);
3264 /* The standard handles are allowed to succeed, even though they are not
3266 if (is_standard_hkey(hkey
))
3267 return ERROR_SUCCESS
;
3269 return remove_handle(hkey
);
3274 * Delete registry key
3277 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3281 /******************************************************************************
3282 * RegDeleteKey32W [ADVAPI32.134]
3285 * hkey [I] Handle to open key
3286 * lpszSubKey [I] Name of subkey to delete
3289 * Success: ERROR_SUCCESS
3290 * Failure: Error code
3292 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3294 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3298 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3300 lpNextKey
= lookup_hkey(hkey
);
3302 return ERROR_INVALID_HANDLE
;
3304 /* Subkey param cannot be NULL */
3305 if (!lpszSubKey
|| !*lpszSubKey
)
3306 return ERROR_BADKEY
;
3308 /* We need to know the previous key in the hier. */
3309 split_keypath(lpszSubKey
,&wps
,&wpc
);
3313 lpxkey
=lpNextKey
->nextsub
;
3315 TRACE(reg
, " Scanning [%s]\n",
3316 debugstr_w(lpxkey
->keyname
));
3317 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3319 lpxkey
=lpxkey
->next
;
3323 TRACE(reg
, " Not found.\n");
3324 /* not found is success */
3325 return ERROR_SUCCESS
;
3330 lpxkey
= lpNextKey
->nextsub
;
3331 lplpPrevKey
= &(lpNextKey
->nextsub
);
3333 TRACE(reg
, " Scanning [%s]\n",
3334 debugstr_w(lpxkey
->keyname
));
3335 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3337 lplpPrevKey
= &(lpxkey
->next
);
3338 lpxkey
= lpxkey
->next
;
3343 WARN(reg
, " Not found.\n");
3344 return ERROR_FILE_NOT_FOUND
;
3347 if (lpxkey
->nextsub
) {
3349 WARN(reg
, " Not empty.\n");
3350 return ERROR_CANTWRITE
;
3352 *lplpPrevKey
= lpxkey
->next
;
3353 free(lpxkey
->keyname
);
3355 free(lpxkey
->class);
3357 free(lpxkey
->values
);
3360 TRACE(reg
, " Done.\n");
3361 return ERROR_SUCCESS
;
3365 /******************************************************************************
3366 * RegDeleteKey32A [ADVAPI32.133]
3368 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3373 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3374 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3375 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3376 if(lpszSubKeyW
) free(lpszSubKeyW
);
3381 /******************************************************************************
3382 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3384 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3386 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3387 return RegDeleteKeyA( hkey
, lpszSubKey
);
3392 * Delete registry value
3395 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3399 /******************************************************************************
3400 * RegDeleteValue32W [ADVAPI32.136]
3408 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3414 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3416 lpkey
= lookup_hkey( hkey
);
3418 return ERROR_INVALID_HANDLE
;
3421 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3422 if ( lpkey
->values
[i
].name
&&
3423 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3427 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3428 if (lpkey
->values
[i
].name
==NULL
)
3432 if (i
== lpkey
->nrofvalues
)
3433 return ERROR_FILE_NOT_FOUND
;
3435 val
= lpkey
->values
+i
;
3436 if (val
->name
) free(val
->name
);
3437 if (val
->data
) free(val
->data
);
3441 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3443 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3445 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3447 lpkey
->nrofvalues
--;
3448 return ERROR_SUCCESS
;
3452 /******************************************************************************
3453 * RegDeleteValue32A [ADVAPI32.135]
3455 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3460 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3461 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3462 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3463 if(lpszValueW
) free(lpszValueW
);
3468 /******************************************************************************
3469 * RegDeleteValue16 [KERNEL.222]
3471 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3473 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3474 return RegDeleteValueA( hkey
, lpszValue
);
3478 /******************************************************************************
3479 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3480 * Writes key to registry
3483 * hkey [I] Handle of key to write
3486 * Success: ERROR_SUCCESS
3487 * Failure: Error code
3489 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3494 TRACE(reg
, "(%x)\n", hkey
);
3496 lpkey
= lookup_hkey( hkey
);
3498 return ERROR_BADKEY
;
3500 ERR(reg
, "What is the correct filename?\n");
3502 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3505 return ERROR_SUCCESS
;
3507 return ERROR_UNKNOWN
; /* FIXME */
3511 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3514 /******************************************************************************
3515 * RegQueryInfoKey32W [ADVAPI32.153]
3518 * hkey [I] Handle to key to query
3519 * lpszClass [O] Buffer for class string
3520 * lpcchClass [O] Size of class string buffer
3521 * lpdwReserved [I] Reserved
3522 * lpcSubKeys [I] Buffer for number of subkeys
3523 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3524 * lpcchMaxClass [O] Buffer for longest class string length
3525 * lpcValues [O] Buffer for number of value entries
3526 * lpcchMaxValueName [O] Buffer for longest value name length
3527 * lpccbMaxValueData [O] Buffer for longest value data length
3528 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3530 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3531 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3532 * lpcchClass is NULL
3533 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3534 * (it's hard to test validity, so test !NULL instead)
3536 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3537 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3538 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3539 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3540 LPDWORD lpcchMaxValueName
,
3541 LPDWORD lpccbMaxValueData
,
3542 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3544 LPKEYSTRUCT lpkey
,lpxkey
;
3545 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3548 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3549 lpkey
= lookup_hkey(hkey
);
3551 return ERROR_INVALID_HANDLE
;
3553 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3554 return ERROR_INVALID_PARAMETER
;
3556 /* either lpcchClass is valid or this is win95 and lpcchClass
3559 DWORD classLen
= lstrlenW(lpkey
->class);
3561 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3562 *lpcchClass
=classLen
+1;
3563 return ERROR_MORE_DATA
;
3566 *lpcchClass
=classLen
;
3567 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3575 *lpcchClass
= lstrlenW(lpkey
->class);
3577 lpxkey
=lpkey
->nextsub
;
3578 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3581 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3582 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3583 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3584 maxclass
=lstrlenW(lpxkey
->class);
3585 lpxkey
=lpxkey
->next
;
3587 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3588 LPKEYVALUE val
=lpkey
->values
+i
;
3590 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3591 maxvname
=lstrlenW(val
->name
);
3592 if (val
->len
>maxvdata
)
3595 if (!maxclass
) maxclass
= 1;
3596 if (!maxvname
) maxvname
= 1;
3598 *lpcValues
= lpkey
->nrofvalues
;
3600 *lpcSubKeys
= nrofkeys
;
3602 *lpcchMaxSubkey
= maxsubkey
;
3604 *lpcchMaxClass
= maxclass
;
3605 if (lpcchMaxValueName
)
3606 *lpcchMaxValueName
= maxvname
;
3607 if (lpccbMaxValueData
)
3608 *lpccbMaxValueData
= maxvdata
;
3609 return ERROR_SUCCESS
;
3613 /******************************************************************************
3614 * RegQueryInfoKey32A [ADVAPI32.152]
3616 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3617 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3618 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3619 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3620 LPDWORD lpccbMaxValueData
,
3621 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3623 LPWSTR lpszClassW
= NULL
;
3626 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3629 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3630 } else if (VERSION_GetVersion() == WIN95
) {
3631 /* win95 allows lpcchClass to be null */
3632 /* we don't know how big lpszClass is, would
3633 MAX_PATHNAME_LEN be the correct default? */
3634 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3639 ret
=RegQueryInfoKeyW(
3650 lpcbSecurityDescriptor
,
3653 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3654 lstrcpyWtoA(lpszClass
,lpszClassW
);
3661 /******************************************************************************
3662 * RegConnectRegistry32W [ADVAPI32.128]
3665 * lpMachineName [I] Address of name of remote computer
3666 * hHey [I] Predefined registry handle
3667 * phkResult [I] Address of buffer for remote registry handle
3669 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3672 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3674 if (!lpMachineName
|| !*lpMachineName
) {
3675 /* Use the local machine name */
3676 return RegOpenKey16( hKey
, "", phkResult
);
3679 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3680 return ERROR_BAD_NETPATH
;
3684 /******************************************************************************
3685 * RegConnectRegistry32A [ADVAPI32.127]
3687 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3690 LPWSTR machineW
= strdupA2W(machine
);
3691 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3697 /******************************************************************************
3698 * RegGetKeySecurity [ADVAPI32.144]
3699 * Retrieves a copy of security descriptor protecting the registry key
3702 * hkey [I] Open handle of key to set
3703 * SecurityInformation [I] Descriptor contents
3704 * pSecurityDescriptor [O] Address of descriptor for key
3705 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3708 * Success: ERROR_SUCCESS
3709 * Failure: Error code
3711 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3712 SECURITY_INFORMATION SecurityInformation
,
3713 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3714 LPDWORD lpcbSecurityDescriptor
)
3718 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3719 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3721 lpkey
= lookup_hkey( hkey
);
3723 return ERROR_INVALID_HANDLE
;
3725 /* FIXME: Check for valid SecurityInformation values */
3727 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3728 return ERROR_INSUFFICIENT_BUFFER
;
3730 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3731 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3733 return ERROR_SUCCESS
;
3737 /******************************************************************************
3738 * RegLoadKey32W [ADVAPI32.???]
3741 * hkey [I] Handle of open key
3742 * lpszSubKey [I] Address of name of subkey
3743 * lpszFile [I] Address of filename for registry information
3745 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3748 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3750 /* Do this check before the hkey check */
3751 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3752 return ERROR_INVALID_PARAMETER
;
3754 lpkey
= lookup_hkey( hkey
);
3756 return ERROR_INVALID_HANDLE
;
3758 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3759 debugstr_w(lpszFile
));
3761 return ERROR_SUCCESS
;
3765 /******************************************************************************
3766 * RegLoadKey32A [ADVAPI32.???]
3768 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3771 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3772 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3773 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3774 if(lpszFileW
) free(lpszFileW
);
3775 if(lpszSubKeyW
) free(lpszSubKeyW
);
3780 /******************************************************************************
3781 * RegNotifyChangeKeyValue [ADVAPI32.???]
3784 * hkey [I] Handle of key to watch
3785 * fWatchSubTree [I] Flag for subkey notification
3786 * fdwNotifyFilter [I] Changes to be reported
3787 * hEvent [I] Handle of signaled event
3788 * fAsync [I] Flag for asynchronous reporting
3790 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3791 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3795 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3798 lpkey
= lookup_hkey( hkey
);
3800 return ERROR_INVALID_HANDLE
;
3802 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3805 return ERROR_SUCCESS
;
3809 /******************************************************************************
3810 * RegUnLoadKey32W [ADVAPI32.173]
3813 * hkey [I] Handle of open key
3814 * lpSubKey [I] Address of name of subkey to unload
3816 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3818 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3819 return ERROR_SUCCESS
;
3823 /******************************************************************************
3824 * RegUnLoadKey32A [ADVAPI32.172]
3826 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3829 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3830 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3831 if(lpSubKeyW
) free(lpSubKeyW
);
3836 /******************************************************************************
3837 * RegSetKeySecurity [ADVAPI32.167]
3840 * hkey [I] Open handle of key to set
3841 * SecurityInfo [I] Descriptor contents
3842 * pSecurityDesc [I] Address of descriptor for key
3844 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3845 PSECURITY_DESCRIPTOR pSecurityDesc
)
3849 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3851 /* It seems to perform this check before the hkey check */
3852 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3853 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3854 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3855 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3858 return ERROR_INVALID_PARAMETER
;
3861 return ERROR_INVALID_PARAMETER
;
3863 lpkey
= lookup_hkey( hkey
);
3865 return ERROR_INVALID_HANDLE
;
3867 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3869 return ERROR_SUCCESS
;
3873 /******************************************************************************
3874 * RegSaveKey32W [ADVAPI32.166]
3877 * hkey [I] Handle of key where save begins
3878 * lpFile [I] Address of filename to save to
3879 * sa [I] Address of security structure
3881 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3882 LPSECURITY_ATTRIBUTES sa
)
3886 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3888 /* It appears to do this check before the hkey check */
3889 if (!lpFile
|| !*lpFile
)
3890 return ERROR_INVALID_PARAMETER
;
3892 lpkey
= lookup_hkey( hkey
);
3894 return ERROR_INVALID_HANDLE
;
3896 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3898 return ERROR_SUCCESS
;
3902 /******************************************************************************
3903 * RegSaveKey32A [ADVAPI32.165]
3905 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3906 LPSECURITY_ATTRIBUTES sa
)
3909 LPWSTR lpFileW
= strdupA2W(lpFile
);
3910 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3916 /******************************************************************************
3917 * RegRestoreKey32W [ADVAPI32.164]
3920 * hkey [I] Handle of key where restore begins
3921 * lpFile [I] Address of filename containing saved tree
3922 * dwFlags [I] Optional flags
3924 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3928 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3930 /* It seems to do this check before the hkey check */
3931 if (!lpFile
|| !*lpFile
)
3932 return ERROR_INVALID_PARAMETER
;
3934 lpkey
= lookup_hkey( hkey
);
3936 return ERROR_INVALID_HANDLE
;
3938 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3940 /* Check for file existence */
3942 return ERROR_SUCCESS
;
3946 /******************************************************************************
3947 * RegRestoreKey32A [ADVAPI32.163]
3949 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3952 LPWSTR lpFileW
= strdupA2W(lpFile
);
3953 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3954 if(lpFileW
) free(lpFileW
);
3959 /******************************************************************************
3960 * RegReplaceKey32W [ADVAPI32.162]
3963 * hkey [I] Handle of open key
3964 * lpSubKey [I] Address of name of subkey
3965 * lpNewFile [I] Address of filename for file with new data
3966 * lpOldFile [I] Address of filename for backup file
3968 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3973 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3974 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3976 lpkey
= lookup_hkey( hkey
);
3978 return ERROR_INVALID_HANDLE
;
3980 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3981 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3983 return ERROR_SUCCESS
;
3987 /******************************************************************************
3988 * RegReplaceKey32A [ADVAPI32.161]
3990 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3994 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3995 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
3996 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
3997 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);