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
;
951 if ((type
== REG_SZ
|| type
== REG_EXPAND_SZ
) && !data
){
953 data
=xmalloc(sizeof(WCHAR
));
954 memset(data
,0,sizeof(WCHAR
));
967 /******************************************************************************
968 * _wine_read_line [Internal]
970 * reads a line including dynamically enlarging the readbuffer and throwing
973 static int _wine_read_line( FILE *F
, char **buf
, int *len
)
983 s
=fgets(curread
,mylen
,F
);
986 if (NULL
==(s
=strchr(curread
,'\n'))) {
987 /* buffer wasn't large enough */
988 curoff
= strlen(*buf
);
989 *buf
= xrealloc(*buf
,*len
*2);
990 curread
= *buf
+ curoff
;
991 mylen
= *len
; /* we filled up the buffer and
992 * got new '*len' bytes to fill
1000 /* throw away comments */
1001 if (**buf
=='#' || **buf
==';') {
1006 if (s
) /* got end of line */
1013 /******************************************************************************
1014 * _wine_read_USTRING [Internal]
1016 * converts a char* into a UNICODE string (up to a special char)
1017 * and returns the position exactly after that string
1019 static char* _wine_read_USTRING( char *buf
, LPWSTR
*str
)
1024 /* read up to "=" or "\0" or "\n" */
1027 /* empty string is the win3.1 default value(NULL)*/
1031 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
1033 while (*s
&& (*s
!='\n') && (*s
!='=')) {
1035 *ws
++=*((unsigned char*)s
++);
1039 /* Dangling \ ... may only happen if a registry
1040 * write was short. FIXME: What do to?
1050 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
1058 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
1059 if (!sscanf(xbuf
,"%x",&wc
))
1060 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
1062 *ws
++ =(unsigned short)wc
;
1069 *str
= strdupW(*str
);
1077 /******************************************************************************
1078 * _wine_loadsubkey [Internal]
1081 * It seems like this is returning a boolean. Should it?
1087 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
1088 int *buflen
, DWORD optflag
)
1095 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
1098 lpkey
->flags
|= optflag
;
1100 /* Good. We already got a line here ... so parse it */
1110 WARN(reg
,"Got a subhierarchy without resp. key?\n");
1113 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
1117 /* let the caller handle this line */
1118 if (i
<level
|| **buf
=='\0')
1121 /* it can be: a value or a keyname. Parse the name first */
1122 s
=_wine_read_USTRING(s
,&name
);
1124 /* switch() default: hack to avoid gotos */
1128 lpxkey
=_find_or_add_key(lpkey
,name
);
1131 int len
,lastmodified
,type
;
1134 WARN(reg
,"Unexpected character: %c\n",*s
);
1138 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
1139 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
1143 s
=strchr(s
,',');s
++;
1144 s
=strchr(s
,',');s
++;
1145 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
1146 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
1148 len
= lstrlenW((LPWSTR
)data
)*2+2;
1153 data
= (LPBYTE
)xmalloc(len
+1);
1154 for (i
=0;i
<len
;i
++) {
1156 if (*s
>='0' && *s
<='9')
1157 data
[i
]=(*s
-'0')<<4;
1158 if (*s
>='a' && *s
<='f')
1159 data
[i
]=(*s
-'a'+'\xa')<<4;
1160 if (*s
>='A' && *s
<='F')
1161 data
[i
]=(*s
-'A'+'\xa')<<4;
1163 if (*s
>='0' && *s
<='9')
1165 if (*s
>='a' && *s
<='f')
1166 data
[i
]|=*s
-'a'+'\xa';
1167 if (*s
>='A' && *s
<='F')
1168 data
[i
]|=*s
-'A'+'\xa';
1172 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
1175 /* read the next line */
1176 if (!_wine_read_line(F
,buf
,buflen
))
1183 /******************************************************************************
1184 * _wine_loadsubreg [Internal]
1186 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
1192 buf
=xmalloc(10);buflen
=10;
1193 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1197 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
1201 if (ver
!=REGISTRY_SAVE_VERSION
) {
1202 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
1206 if (!_wine_read_line(F
,&buf
,&buflen
)) {
1210 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
1219 /******************************************************************************
1220 * _wine_loadreg [Internal]
1222 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
1226 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
1230 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
1233 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
1241 /******************************************************************************
1242 * _flush_registry [Internal]
1244 * This function allow to flush section of the internal registry. It is mainly
1245 * implements to fix a problem with the global HKU and the local HKU.
1246 * Those two files are read to build the HKU\.Default branch to finaly copy
1247 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1248 * all the global HKU are saved onto the user's personal version of HKU hive.
1252 /* Forward declaration of recusive agent */
1253 static void _flush_reg(LPKEYSTRUCT from
);
1255 static void _flush_registry( LPKEYSTRUCT from
)
1257 /* make sure we have something... */
1261 /* Launch the recusive agent on sub branches */
1262 _flush_reg( from
->nextsub
);
1263 _flush_reg( from
->next
);
1265 /* Initialize pointers */
1266 from
->nextsub
= NULL
;
1269 static void _flush_reg( LPKEYSTRUCT from
)
1273 /* make sure we have something... */
1278 * do the same for the child keys
1280 if (from
->nextsub
!= NULL
)
1281 _flush_reg(from
->nextsub
);
1284 * do the same for the sibling keys
1286 if (from
->next
!= NULL
)
1287 _flush_reg(from
->next
);
1290 * iterate through this key's values and delete them
1292 for (j
=0;j
<from
->nrofvalues
;j
++)
1294 free( (from
->values
+j
)->name
);
1295 free( (from
->values
+j
)->data
);
1299 * free the structure
1306 /******************************************************************************
1307 * _copy_registry [Internal]
1309 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
1317 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
1319 for (j
=0;j
<from
->nrofvalues
;j
++) {
1323 valfrom
= from
->values
+j
;
1325 if (name
) name
=strdupW(name
);
1326 data
=(LPBYTE
)xmalloc(valfrom
->len
);
1327 memcpy(data
,valfrom
->data
,valfrom
->len
);
1335 valfrom
->lastmodified
1338 _copy_registry(from
,lpxkey
);
1344 /* WINDOWS 95 REGISTRY LOADER */
1346 * Structure of a win95 registry database.
1348 * 0 : "CREG" - magic
1350 * 8 : DWORD offset_of_RGDB_part
1351 * 0C..0F: ? (someone fill in please)
1352 * 10: WORD number of RGDB blocks
1354 * 14: WORD always 0000?
1355 * 16: WORD always 0001?
1356 * 18..1F: ? (someone fill in please)
1360 * 0 : "RGKN" - magic
1361 * 4 : DWORD offset to first RGDB section
1362 * 8 : DWORD offset to the root record
1363 * C..0x1B: ? (fill in)
1364 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1366 * Disk Key Entry Structure:
1367 * 00: DWORD - Free entry indicator(?)
1368 * 04: DWORD - Hash = sum of bytes of keyname
1369 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1370 * 0C: DWORD - disk address of PreviousLevel Key.
1371 * 10: DWORD - disk address of Next Sublevel Key.
1372 * 14: DWORD - disk address of Next Key (on same level).
1373 * DKEP>18: WORD - Nr, Low Significant part.
1374 * 1A: WORD - Nr, High Significant part.
1376 * The disk address always points to the nr part of the previous key entry
1377 * of the referenced key. Don't ask me why, or even if I got this correct
1378 * from staring at 1kg of hexdumps. (DKEP)
1380 * The High significant part of the structure seems to equal the number
1381 * of the RGDB section. The low significant part is a unique ID within
1384 * There are two minor corrections to the position of that structure.
1385 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1386 * the DKE reread from there.
1387 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1388 * CPS - I have not experienced the above phenomenon in my registry files
1391 * 00: "RGDB" - magic
1392 * 04: DWORD offset to next RGDB section
1394 * 0C: WORD always 000d?
1395 * 0E: WORD RGDB block number
1396 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1398 * 20.....: disk keys
1401 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1402 * 08: WORD nrLS - low significant part of NR
1403 * 0A: WORD nrHS - high significant part of NR
1404 * 0C: DWORD bytesused - bytes used in this structure.
1405 * 10: WORD name_len - length of name in bytes. without \0
1406 * 12: WORD nr_of_values - number of values.
1407 * 14: char name[name_len] - name string. No \0.
1408 * 14+name_len: disk values
1409 * nextkeyoffset: ... next disk key
1412 * 00: DWORD type - value type (hmm, could be WORD too)
1413 * 04: DWORD - unknown, usually 0
1414 * 08: WORD namelen - length of Name. 0 means name=NULL
1415 * 0C: WORD datalen - length of Data.
1416 * 10: char name[namelen] - name, no \0
1417 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1418 * 10+namelen+datalen: next values or disk key
1420 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1421 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1422 * structure) and reading another RGDB_section.
1423 * repeat until end of file.
1425 * An interesting relationship exists in RGDB_section. The value at offset
1426 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1427 * idea at the moment what this means. (Kevin Cozens)
1429 * FIXME: this description needs some serious help, yes.
1432 struct _w95keyvalue
{
1434 unsigned short datalen
;
1436 unsigned char *data
;
1444 struct _w95keyvalue
*values
;
1445 struct _w95key
*prevlvl
;
1446 struct _w95key
*nextsub
;
1447 struct _w95key
*next
;
1461 /******************************************************************************
1462 * _w95_processKey [Internal]
1464 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1465 int nrLS
, int nrMS
, struct _w95_info
*info
)
1468 /* Disk Key Header structure (RGDB part) */
1470 unsigned long nextkeyoff
;
1471 unsigned short nrLS
;
1472 unsigned short nrMS
;
1473 unsigned long bytesused
;
1474 unsigned short keynamelen
;
1475 unsigned short values
;
1478 /* disk key values or nothing */
1480 /* Disk Key Value structure */
1484 unsigned short valnamelen
;
1485 unsigned short valdatalen
;
1486 /* valname, valdata */
1492 char *rgdbdata
= info
->rgdbbuffer
;
1493 int nbytes
= info
->rgdbsize
;
1494 char *curdata
= rgdbdata
;
1495 char *end
= rgdbdata
+ nbytes
;
1497 char *next
= rgdbdata
;
1503 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1505 memcpy(&off_next_rgdb
,curdata
+4,4);
1506 next
= curdata
+ off_next_rgdb
;
1507 nrgdb
= (int) *((short *)curdata
+ 7);
1509 } while (nrgdb
!= nrMS
&& (next
< end
));
1511 /* curdata now points to the start of the right RGDB section */
1514 #define XREAD(whereto,len) \
1515 if ((curdata + len) <= end) {\
1516 memcpy(whereto,curdata,len);\
1521 while (curdata
< next
) {
1522 struct dkh
*xdkh
= (struct dkh
*)curdata
;
1524 bytesread
+= sizeof(dkh
); /* FIXME... nextkeyoff? */
1525 if (xdkh
->nrLS
== nrLS
) {
1526 memcpy(&dkh
,xdkh
,sizeof(dkh
));
1527 curdata
+= sizeof(dkh
);
1530 curdata
+= xdkh
->nextkeyoff
;
1533 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1535 if (nrgdb
!= dkh
.nrMS
)
1538 assert((dkh
.keynamelen
<2) || curdata
[0]);
1539 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1540 curdata
+= dkh
.keynamelen
;
1542 for (i
=0;i
< dkh
.values
; i
++) {
1548 XREAD(&dkv
,sizeof(dkv
));
1550 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1551 curdata
+= dkv
.valnamelen
;
1553 if ((1 << dkv
.type
) & UNICONVMASK
) {
1554 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1555 len
= 2*(dkv
.valdatalen
+ 1);
1557 /* I don't think we want to NULL terminate all data */
1558 data
= xmalloc(dkv
.valdatalen
);
1559 memcpy (data
, curdata
, dkv
.valdatalen
);
1560 len
= dkv
.valdatalen
;
1563 curdata
+= dkv
.valdatalen
;
1577 /******************************************************************************
1578 * _w95_walkrgkn [Internal]
1580 static void _w95_walkrgkn( LPKEYSTRUCT prevkey
, char *off
,
1581 struct _w95_info
*info
)
1584 /* Disk Key Entry structure (RGKN part) */
1588 unsigned long x3
;/*usually 0xFFFFFFFF */
1589 unsigned long prevlvl
;
1590 unsigned long nextsub
;
1592 unsigned short nrLS
;
1593 unsigned short nrMS
;
1594 } *dke
= (struct dke
*)off
;
1598 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1601 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1602 /* XXX <-- This is a hack*/
1607 if (dke
->nextsub
!= -1 &&
1608 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1609 && (dke
->nextsub
> 0x20)) {
1611 _w95_walkrgkn(lpxkey
,
1612 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1616 if (dke
->next
!= -1 &&
1617 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1618 (dke
->next
> 0x20)) {
1619 _w95_walkrgkn(prevkey
,
1620 info
->rgknbuffer
+ dke
->next
- 0x20,
1628 /******************************************************************************
1629 * _w95_loadreg [Internal]
1631 static void _w95_loadreg( char* fn
, LPKEYSTRUCT lpkey
)
1635 unsigned long where
,version
,rgdbsection
,end
;
1636 struct _w95_info info
;
1638 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1640 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1641 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1642 if (hfd
==HFILE_ERROR
)
1645 if (4!=_lread(hfd
,magic
,4))
1647 if (strcmp(magic
,"CREG")) {
1648 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1651 if (4!=_lread(hfd
,&version
,4))
1653 if (4!=_lread(hfd
,&rgdbsection
,4))
1655 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1657 if (4!=_lread(hfd
,magic
,4))
1659 if (strcmp(magic
,"RGKN")) {
1660 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1664 /* STEP 1: Keylink structures */
1665 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1670 info
.rgknsize
= end
- where
;
1671 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1672 if (info
.rgknsize
!= _lread(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1675 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1678 end
= hfdinfo
.nFileSizeLow
;
1679 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1681 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1684 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1685 info
.rgdbsize
= end
- rgdbsection
;
1687 if (info
.rgdbsize
!=_lread(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1691 _w95_walkrgkn(lpkey
, NULL
, &info
);
1693 free (info
.rgdbbuffer
);
1694 free (info
.rgknbuffer
);
1698 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1701 reghack - windows 3.11 registry data format demo program.
1703 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1704 a combined hash table and tree description, and finally a text table.
1706 The header is obvious from the struct header. The taboff1 and taboff2
1707 fields are always 0x20, and their usage is unknown.
1709 The 8-byte entry table has various entry types.
1711 tabent[0] is a root index. The second word has the index of the root of
1713 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1714 the index of the key/value that has that hash. Data with the same
1715 hash value are on a circular list. The other three words in the
1716 hash entry are always zero.
1717 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1718 entry: dirent and keyent/valent. They are identified by context.
1719 tabent[freeidx] is the first free entry. The first word in a free entry
1720 is the index of the next free entry. The last has 0 as a link.
1721 The other three words in the free list are probably irrelevant.
1723 Entries in text table are preceeded by a word at offset-2. This word
1724 has the value (2*index)+1, where index is the referring keyent/valent
1725 entry in the table. I have no suggestion for the 2* and the +1.
1726 Following the word, there are N bytes of data, as per the keyent/valent
1727 entry length. The offset of the keyent/valent entry is from the start
1728 of the text table to the first data byte.
1730 This information is not available from Microsoft. The data format is
1731 deduced from the reg.dat file by me. Mistakes may
1732 have been made. I claim no rights and give no guarantees for this program.
1734 Tor Sjøwall, tor@sn.no
1737 /* reg.dat header format */
1738 struct _w31_header
{
1739 char cookie
[8]; /* 'SHCC3.10' */
1740 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1741 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1742 unsigned long tabcnt
; /* number of entries in index table */
1743 unsigned long textoff
; /* offset of text part */
1744 unsigned long textsize
; /* byte size of text part */
1745 unsigned short hashsize
; /* hash size */
1746 unsigned short freeidx
; /* free index */
1749 /* generic format of table entries */
1750 struct _w31_tabent
{
1751 unsigned short w0
, w1
, w2
, w3
;
1754 /* directory tabent: */
1755 struct _w31_dirent
{
1756 unsigned short sibling_idx
; /* table index of sibling dirent */
1757 unsigned short child_idx
; /* table index of child dirent */
1758 unsigned short key_idx
; /* table index of key keyent */
1759 unsigned short value_idx
; /* table index of value valent */
1763 struct _w31_keyent
{
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 */
1771 struct _w31_valent
{
1772 unsigned short hash_idx
; /* hash chain index for string */
1773 unsigned short refcnt
; /* reference count */
1774 unsigned short length
; /* length of string */
1775 unsigned short string_off
; /* offset of string in text table */
1778 /* recursive helper function to display a directory tree */
1780 __w31_dumptree( unsigned short idx
,
1782 struct _w31_tabent
*tab
,
1783 struct _w31_header
*head
,
1785 time_t lastmodified
,
1788 struct _w31_dirent
*dir
;
1789 struct _w31_keyent
*key
;
1790 struct _w31_valent
*val
;
1791 LPKEYSTRUCT xlpkey
= NULL
;
1793 static char tail
[400];
1796 dir
=(struct _w31_dirent
*)&tab
[idx
];
1799 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1801 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1802 tail
[key
->length
]='\0';
1803 /* all toplevel entries AND the entries in the
1804 * toplevel subdirectory belong to \SOFTWARE\Classes
1806 if (!level
&& !lstrcmpA(tail
,".classes")) {
1807 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1808 idx
=dir
->sibling_idx
;
1811 name
=strdupA2W(tail
);
1813 xlpkey
=_find_or_add_key(lpkey
,name
);
1815 /* only add if leaf node or valued node */
1816 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1817 if (dir
->value_idx
) {
1818 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1819 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1820 tail
[val
->length
]='\0';
1821 value
=strdupA2W(tail
);
1822 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlenW(value
)*2+2,lastmodified
);
1826 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1828 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1829 idx
=dir
->sibling_idx
;
1834 /******************************************************************************
1835 * _w31_loadreg [Internal]
1837 void _w31_loadreg(void) {
1839 struct _w31_header head
;
1840 struct _w31_tabent
*tab
;
1844 BY_HANDLE_FILE_INFORMATION hfinfo
;
1845 time_t lastmodified
;
1848 TRACE(reg
,"(void)\n");
1850 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1851 if (hf
==HFILE_ERROR
)
1854 /* read & dump header */
1855 if (sizeof(head
)!=_lread(hf
,&head
,sizeof(head
))) {
1856 ERR(reg
, "reg.dat is too short.\n");
1860 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1861 ERR(reg
, "reg.dat has bad signature.\n");
1866 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1867 /* read and dump index table */
1869 if (len
!=_lread(hf
,tab
,len
)) {
1870 ERR(reg
,"couldn't read %d bytes.\n",len
);
1877 txt
= xmalloc(head
.textsize
);
1878 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1879 ERR(reg
,"couldn't seek to textblock.\n");
1885 if (head
.textsize
!=_lread(hf
,txt
,head
.textsize
)) {
1886 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1893 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1894 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1900 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1901 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1902 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1910 /**********************************************************************************
1911 * SHELL_LoadRegistry [Internal]
1913 void SHELL_LoadRegistry( void )
1917 LPKEYSTRUCT lpkey
, HKCU
, HKU
, HKLM
;
1920 TRACE(reg
,"(void)\n");
1922 HKCU
= lookup_hkey(HKEY_CURRENT_USER
);
1923 HKU
= lookup_hkey(HKEY_USERS
);
1924 HKLM
= lookup_hkey(HKEY_LOCAL_MACHINE
);
1926 /* Load windows 3.1 entries */
1928 /* Load windows 95 entries */
1929 _w95_loadreg("C:\\system.1st", HKLM
);
1930 _w95_loadreg("system.dat", HKLM
);
1931 _w95_loadreg("user.dat", HKU
);
1934 * Load the global HKU hive directly from /usr/local/etc
1936 _wine_loadreg( HKU
, SAVE_USERS_DEFAULT
, 0);
1939 * Load the global machine defaults directly form /usr/local/etc
1941 _wine_loadreg( HKLM
, SAVE_LOCAL_MACHINE_DEFAULT
, 0);
1943 /* Get current user info */
1944 pwd
=getpwuid(getuid());
1947 * Load the user saved registries
1949 if ( (pwd
!= NULL
) &&
1950 (pwd
->pw_dir
!= NULL
) )
1953 * Load user's personal versions of global HKU/.Default keys
1956 strlen(pwd
->pw_dir
)+
1957 strlen(WINE_PREFIX
)+
1958 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
1960 strcpy(fn
, pwd
->pw_dir
);
1961 strcat(fn
, WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
1962 _wine_loadreg(HKU
, fn
, REG_OPTION_TAINTED
);
1966 * Load HKCU, attempt to get the registry location from the config
1967 * file first, if exist, load and keep going.
1969 fn
= xmalloc( MAX_PATHNAME_LEN
);
1970 if ( PROFILE_GetWineIniString(
1975 MAX_PATHNAME_LEN
- 1))
1977 _wine_loadreg(HKCU
,fn
,0);
1982 strlen(pwd
->pw_dir
)+
1983 strlen(WINE_PREFIX
)+
1984 strlen(SAVE_CURRENT_USER
)+2);
1986 strcpy(fn
, pwd
->pw_dir
);
1987 strcat(fn
, WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1988 _wine_loadreg(HKCU
, fn
, REG_OPTION_TAINTED
);
1992 * Load HKLM, attempt to get the registry location from the config
1993 * file first, if exist, load and keep going.
1995 fn
= xmalloc ( MAX_PATHNAME_LEN
);
1996 if ( PROFILE_GetWineIniString(
1998 "LocalMachineFileName",
2001 MAX_PATHNAME_LEN
- 1))
2003 _wine_loadreg(HKLM
, fn
, 0);
2008 strlen(pwd
->pw_dir
)+
2009 strlen(WINE_PREFIX
)+
2010 strlen(SAVE_LOCAL_MACHINE
)+2);
2012 strcpy(fn
,pwd
->pw_dir
);
2013 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
2014 _wine_loadreg(HKLM
, fn
, REG_OPTION_TAINTED
);
2019 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
2023 * Obtain the handle of the HKU\.Default key.
2024 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2026 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
2027 lpkey
= lookup_hkey(hkey
);
2029 WARN(reg
,"Could not create global user default key\n");
2031 _copy_registry(lpkey
, HKCU
);
2036 * Since HKU is built from the global HKU and the local user HKU file we must
2037 * flush the HKU tree we have built at this point otherwise the part brought
2038 * in from the global HKU is saved into the local HKU. To avoid this
2039 * useless dupplication of HKU keys we reread the local HKU key.
2042 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2043 _flush_registry(HKU
);
2045 /* Reload user's local HKU hive */
2047 strlen(pwd
->pw_dir
)+
2048 strlen(WINE_PREFIX
)+
2049 strlen(SAVE_LOCAL_USERS_DEFAULT
)+2);
2051 strcpy(fn
,pwd
->pw_dir
);
2052 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_USERS_DEFAULT
);
2054 _wine_loadreg( HKU
, fn
, REG_OPTION_TAINTED
);
2059 * Make sure the update mode is there
2061 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
))
2063 DWORD junk
,type
,len
;
2067 if (( RegQueryValueExA(
2073 &len
) != ERROR_SUCCESS
) || (type
!= REG_SZ
))
2075 RegSetValueExA(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
2083 /********************* API FUNCTIONS ***************************************/
2087 * All functions are stubs to RegOpenKeyEx32W where all the
2091 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2092 * RegOpenKey32W -> RegOpenKeyEx32W
2096 /******************************************************************************
2097 * RegOpenKeyEx32W [ADVAPI32.150]
2098 * Opens the specified key
2100 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2103 * hkey [I] Handle of open key
2104 * lpszSubKey [I] Name of subkey to open
2105 * dwReserved [I] Reserved - must be zero
2106 * samDesired [I] Security access mask
2107 * retkey [O] Address of handle of open key
2110 * Success: ERROR_SUCCESS
2111 * Failure: Error code
2113 DWORD WINAPI
RegOpenKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
2114 REGSAM samDesired
, LPHKEY retkey
)
2116 LPKEYSTRUCT lpNextKey
,lpxkey
;
2120 TRACE(reg
,"(0x%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
2123 lpNextKey
= lookup_hkey( hkey
);
2125 return ERROR_INVALID_HANDLE
;
2127 if (!lpszSubKey
|| !*lpszSubKey
) {
2128 /* Either NULL or pointer to empty string, so return a new handle
2129 to the original hkey */
2131 add_handle(currenthandle
,lpNextKey
,samDesired
);
2132 *retkey
=currenthandle
;
2133 return ERROR_SUCCESS
;
2136 if (lpszSubKey
[0] == '\\') {
2137 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2138 return ERROR_BAD_PATHNAME
;
2141 split_keypath(lpszSubKey
,&wps
,&wpc
);
2143 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2147 lpxkey
=lpNextKey
->nextsub
;
2149 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
)) {
2152 lpxkey
=lpxkey
->next
;
2156 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
2158 return ERROR_FILE_NOT_FOUND
;
2165 add_handle(currenthandle
,lpxkey
,samDesired
);
2166 *retkey
= currenthandle
;
2167 TRACE(reg
," Returning %x\n", currenthandle
);
2169 return ERROR_SUCCESS
;
2173 /******************************************************************************
2174 * RegOpenKeyEx32A [ADVAPI32.149]
2176 DWORD WINAPI
RegOpenKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2177 REGSAM samDesired
, LPHKEY retkey
)
2179 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2182 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
2184 ret
= RegOpenKeyExW( hkey
, lpszSubKeyW
, dwReserved
, samDesired
, retkey
);
2190 /******************************************************************************
2191 * RegOpenKey32W [ADVAPI32.151]
2194 * hkey [I] Handle of open key
2195 * lpszSubKey [I] Address of name of subkey to open
2196 * retkey [O] Address of handle of open key
2199 * Success: ERROR_SUCCESS
2200 * Failure: Error code
2202 DWORD WINAPI
RegOpenKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2204 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
2205 return RegOpenKeyExW( hkey
, lpszSubKey
, 0, KEY_ALL_ACCESS
, retkey
);
2209 /******************************************************************************
2210 * RegOpenKey32A [ADVAPI32.148]
2212 DWORD WINAPI
RegOpenKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2215 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
2216 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2217 ret
= RegOpenKeyW( hkey
, lpszSubKeyW
, retkey
);
2223 /******************************************************************************
2224 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2226 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2228 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2229 return RegOpenKeyA( hkey
, lpszSubKey
, retkey
);
2236 * All those functions convert their respective
2237 * arguments and call RegCreateKeyExW at the end.
2239 * We stay away from the Ex functions as long as possible because there are
2240 * differences in the return values
2243 * RegCreateKeyEx32A \
2244 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2248 /******************************************************************************
2249 * RegCreateKeyEx32W [ADVAPI32.131]
2252 * hkey [I] Handle of an open key
2253 * lpszSubKey [I] Address of subkey name
2254 * dwReserved [I] Reserved - must be 0
2255 * lpszClass [I] Address of class string
2256 * fdwOptions [I] Special options flag
2257 * samDesired [I] Desired security access
2258 * lpSecAttribs [I] Address of key security structure
2259 * retkey [O] Address of buffer for opened handle
2260 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2262 DWORD WINAPI
RegCreateKeyExW( HKEY hkey
, LPCWSTR lpszSubKey
,
2263 DWORD dwReserved
, LPWSTR lpszClass
,
2264 DWORD fdwOptions
, REGSAM samDesired
,
2265 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2266 LPHKEY retkey
, LPDWORD lpDispos
)
2268 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2272 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
2273 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
2274 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
2276 lpNextKey
= lookup_hkey(hkey
);
2278 return ERROR_INVALID_HANDLE
;
2280 /* Check for valid options */
2281 switch(fdwOptions
) {
2282 case REG_OPTION_NON_VOLATILE
:
2283 case REG_OPTION_VOLATILE
:
2284 case REG_OPTION_BACKUP_RESTORE
:
2287 return ERROR_INVALID_PARAMETER
;
2290 /* Sam has to be a combination of the following */
2292 (KEY_ALL_ACCESS
| KEY_CREATE_LINK
| KEY_CREATE_SUB_KEY
|
2293 KEY_ENUMERATE_SUB_KEYS
| KEY_EXECUTE
| KEY_NOTIFY
|
2294 KEY_QUERY_VALUE
| KEY_READ
| KEY_SET_VALUE
| KEY_WRITE
)))
2295 return ERROR_INVALID_PARAMETER
;
2297 if (!lpszSubKey
|| !*lpszSubKey
) {
2299 add_handle(currenthandle
,lpNextKey
,samDesired
);
2300 *retkey
=currenthandle
;
2301 TRACE(reg
, "Returning %x\n", currenthandle
);
2302 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
2303 return ERROR_SUCCESS
;
2306 if (lpszSubKey
[0] == '\\') {
2307 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
2308 return ERROR_BAD_PATHNAME
;
2311 split_keypath(lpszSubKey
,&wps
,&wpc
);
2313 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
2316 lpxkey
=lpNextKey
->nextsub
;
2318 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
2320 lpxkey
=lpxkey
->next
;
2329 add_handle(currenthandle
,lpxkey
,samDesired
);
2330 lpxkey
->flags
|= REG_OPTION_TAINTED
;
2331 *retkey
= currenthandle
;
2332 TRACE(reg
, "Returning %x\n", currenthandle
);
2334 *lpDispos
= REG_OPENED_EXISTING_KEY
;
2336 return ERROR_SUCCESS
;
2339 /* Good. Now the hard part */
2341 lplpPrevKey
= &(lpNextKey
->nextsub
);
2342 lpxkey
= *lplpPrevKey
;
2344 lplpPrevKey
= &(lpxkey
->next
);
2345 lpxkey
= *lplpPrevKey
;
2347 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
2348 if (!*lplpPrevKey
) {
2350 TRACE(reg
, "Returning OUTOFMEMORY\n");
2351 return ERROR_OUTOFMEMORY
;
2353 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
2354 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
2355 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
2356 (*lplpPrevKey
)->next
= NULL
;
2357 (*lplpPrevKey
)->nextsub
= NULL
;
2358 (*lplpPrevKey
)->values
= NULL
;
2359 (*lplpPrevKey
)->nrofvalues
= 0;
2360 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
2362 (*lplpPrevKey
)->class = strdupW(lpszClass
);
2364 (*lplpPrevKey
)->class = NULL
;
2365 lpNextKey
= *lplpPrevKey
;
2369 add_handle(currenthandle
,lpNextKey
,samDesired
);
2371 /*FIXME: flag handling correct? */
2372 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
2374 lpNextKey
->class = strdupW(lpszClass
);
2376 lpNextKey
->class = NULL
;
2377 *retkey
= currenthandle
;
2378 TRACE(reg
, "Returning %x\n", currenthandle
);
2380 *lpDispos
= REG_CREATED_NEW_KEY
;
2382 return ERROR_SUCCESS
;
2386 /******************************************************************************
2387 * RegCreateKeyEx32A [ADVAPI32.130]
2389 DWORD WINAPI
RegCreateKeyExA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
2390 LPSTR lpszClass
, DWORD fdwOptions
,
2392 LPSECURITY_ATTRIBUTES lpSecAttribs
,
2393 LPHKEY retkey
, LPDWORD lpDispos
)
2395 LPWSTR lpszSubKeyW
, lpszClassW
;
2398 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
2399 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
2402 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2403 lpszClassW
= lpszClass
?strdupA2W(lpszClass
):NULL
;
2405 ret
= RegCreateKeyExW( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
2406 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
2409 if(lpszSubKeyW
) free(lpszSubKeyW
);
2410 if(lpszClassW
) free(lpszClassW
);
2416 /******************************************************************************
2417 * RegCreateKey32W [ADVAPI32.132]
2419 DWORD WINAPI
RegCreateKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
2422 LPKEYSTRUCT lpNextKey
;
2424 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
2426 /* This check is here because the return value is different than the
2427 one from the Ex functions */
2428 lpNextKey
= lookup_hkey(hkey
);
2430 return ERROR_BADKEY
;
2432 return RegCreateKeyExW( hkey
, lpszSubKey
, 0, NULL
,
2433 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2438 /******************************************************************************
2439 * RegCreateKey32A [ADVAPI32.129]
2441 DWORD WINAPI
RegCreateKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2446 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2447 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
2448 ret
= RegCreateKeyW( hkey
, lpszSubKeyW
, retkey
);
2449 if(lpszSubKeyW
) free(lpszSubKeyW
);
2454 /******************************************************************************
2455 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2457 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
2459 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
2460 return RegCreateKeyA( hkey
, lpszSubKey
, retkey
);
2465 * Query Value Functions
2466 * Win32 differs between keynames and valuenames.
2467 * multiple values may belong to one key, the special value
2468 * with name NULL is the default value used by the win31
2472 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2473 * RegQueryValue32W -> RegQueryValueEx32W
2477 /******************************************************************************
2478 * RegQueryValueEx32W [ADVAPI32.158]
2479 * Retrieves type and data for a specified name associated with an open key
2482 * hkey [I] Handle of key to query
2483 * lpValueName [I] Name of value to query
2484 * lpdwReserved [I] Reserved - must be NULL
2485 * lpdwType [O] Address of buffer for value type. If NULL, the type
2487 * lpbData [O] Address of data buffer. If NULL, the actual data is
2489 * lpcbData [I/O] Address of data buffer size
2492 * ERROR_SUCCESS: Success
2493 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2494 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2496 DWORD WINAPI
RegQueryValueExW( HKEY hkey
, LPWSTR lpValueName
,
2497 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2498 LPBYTE lpbData
, LPDWORD lpcbData
)
2504 TRACE(reg
,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey
, debugstr_w(lpValueName
),
2505 lpdwReserved
, lpdwType
, lpbData
, lpcbData
, lpcbData
?*lpcbData
:0);
2507 lpkey
= lookup_hkey(hkey
);
2510 return ERROR_INVALID_HANDLE
;
2512 if ((lpbData
&& ! lpcbData
) || lpdwReserved
)
2513 return ERROR_INVALID_PARAMETER
;
2515 /* An empty name string is equivalent to NULL */
2516 if (lpValueName
&& !*lpValueName
)
2519 if (lpValueName
==NULL
)
2520 { /* Use key's unnamed or default value, if any */
2521 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2522 if (lpkey
->values
[i
].name
==NULL
)
2526 { /* Search for the key name */
2527 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2528 if ( lpkey
->values
[i
].name
&& !lstrcmpiW(lpValueName
,lpkey
->values
[i
].name
))
2532 if (i
==lpkey
->nrofvalues
)
2533 { TRACE(reg
," Key not found\n");
2534 if (lpValueName
==NULL
)
2535 { /* Empty keyname not found */
2537 { *(WCHAR
*)lpbData
= 0;
2542 TRACE(reg
, " Returning an empty string\n");
2543 return ERROR_SUCCESS
;
2545 return ERROR_FILE_NOT_FOUND
;
2548 ret
= ERROR_SUCCESS
;
2550 if (lpdwType
) /* type required ?*/
2551 *lpdwType
= lpkey
->values
[i
].type
;
2553 if (lpbData
) /* data required ?*/
2554 { if (*lpcbData
>= lpkey
->values
[i
].len
) /* buffer large enought ?*/
2555 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2557 ret
= ERROR_MORE_DATA
;
2560 if (lpcbData
) /* size required ?*/
2561 { *lpcbData
= lpkey
->values
[i
].len
;
2564 debug_print_value ( lpbData
, &lpkey
->values
[i
]);
2566 TRACE(reg
," (ret=%lx, type=%lx, len=%ld)\n", ret
, lpdwType
?*lpdwType
:0,lpcbData
?*lpcbData
:0);
2572 /******************************************************************************
2573 * RegQueryValue32W [ADVAPI32.159]
2575 DWORD WINAPI
RegQueryValueW( HKEY hkey
, LPCWSTR lpszSubKey
, LPWSTR lpszData
,
2581 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2582 lpcbData
?*lpcbData
:0);
2584 /* Only open subkey, if we really do descend */
2585 if (lpszSubKey
&& *lpszSubKey
) {
2586 ret
= RegOpenKeyW( hkey
, lpszSubKey
, &xhkey
);
2587 if (ret
!= ERROR_SUCCESS
) {
2588 WARN(reg
, "Could not open %s\n", debugstr_w(lpszSubKey
));
2595 ret
= RegQueryValueExW( xhkey
, NULL
, NULL
, &lpdwType
, (LPBYTE
)lpszData
,
2603 /******************************************************************************
2604 * RegQueryValueEx32A [ADVAPI32.157]
2607 * the documantation is wrong: if the buffer is to small it remains untouched
2609 * FIXME: check returnvalue (len) for an empty key
2611 DWORD WINAPI
RegQueryValueExA( HKEY hkey
, LPSTR lpszValueName
,
2612 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2613 LPBYTE lpbData
, LPDWORD lpcbData
)
2615 LPWSTR lpszValueNameW
;
2616 LPBYTE mybuf
= NULL
;
2617 DWORD ret
, mytype
, mylen
= 0;
2619 TRACE(reg
,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey
,debugstr_a(lpszValueName
),
2620 lpdwReserved
,lpdwType
,lpbData
,lpcbData
,lpcbData
?*lpcbData
:0);
2622 if (!lpcbData
&& lpbData
) /* buffer without size is illegal */
2623 { return ERROR_INVALID_PARAMETER
;
2626 lpszValueNameW
= lpszValueName
? strdupA2W(lpszValueName
) : NULL
;
2628 /* get just the type first */
2629 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, &mytype
, NULL
, NULL
);
2631 if ( ret
!= ERROR_SUCCESS
) /* failed ?? */
2632 { if(lpszValueNameW
) free(lpszValueNameW
);
2636 if (lpcbData
) /* at least length requested? */
2637 { if (UNICONVMASK
& (1<<(mytype
))) /* string requested? */
2638 { if (lpbData
) /* value requested? */
2639 { mylen
= 2*( *lpcbData
);
2640 mybuf
= (LPBYTE
)xmalloc( mylen
);
2643 ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, mybuf
, &mylen
);
2645 if (ret
== ERROR_SUCCESS
)
2647 { lmemcpynWtoA(lpbData
, (LPWSTR
)mybuf
, mylen
/2);
2651 *lpcbData
= mylen
/2; /* size is in byte! */
2653 else /* no strings, call it straight */
2654 { ret
= RegQueryValueExW( hkey
, lpszValueNameW
, lpdwReserved
, lpdwType
, lpbData
, lpcbData
);
2658 if (lpdwType
) /* type when requested */
2659 { *lpdwType
= mytype
;
2662 TRACE(reg
," (ret=%lx,type=%lx, len=%ld)\n", ret
,mytype
,lpcbData
?*lpcbData
:0);
2664 if(mybuf
) free(mybuf
);
2665 if(lpszValueNameW
) free(lpszValueNameW
);
2670 /******************************************************************************
2671 * RegQueryValueEx16 [KERNEL.225]
2673 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2674 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2675 LPBYTE lpbData
, LPDWORD lpcbData
)
2677 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2678 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2679 return RegQueryValueExA( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2680 lpbData
, lpcbData
);
2684 /******************************************************************************
2685 * RegQueryValue32A [ADVAPI32.156]
2687 DWORD WINAPI
RegQueryValueA( HKEY hkey
, LPCSTR lpszSubKey
, LPSTR lpszData
,
2693 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2694 lpcbData
?*lpcbData
:0);
2696 if (lpszSubKey
&& *lpszSubKey
) {
2697 ret
= RegOpenKey16( hkey
, lpszSubKey
, &xhkey
);
2698 if( ret
!= ERROR_SUCCESS
)
2704 ret
= RegQueryValueExA( xhkey
, NULL
,NULL
, &dwType
, (LPBYTE
)lpszData
,
2707 RegCloseKey( xhkey
);
2712 /******************************************************************************
2713 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2716 * Is this HACK still applicable?
2719 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2720 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2723 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2726 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2727 lpcbData
?*lpcbData
:0);
2730 *lpcbData
&= 0xFFFF;
2731 return RegQueryValueA(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2736 * Setting values of Registry keys
2739 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2740 * RegSetValue32W -> RegSetValueEx32W
2744 /******************************************************************************
2745 * RegSetValueEx32W [ADVAPI32.170]
2746 * Sets the data and type of a value under a register key
2749 * hkey [I] Handle of key to set value for
2750 * lpszValueName [I] Name of value to set
2751 * dwReserved [I] Reserved - must be zero
2752 * dwType [I] Flag for value type
2753 * lpbData [I] Address of value data
2754 * cbData [I] Size of value data
2757 * Success: ERROR_SUCCESS
2758 * Failure: Error code
2761 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2763 DWORD WINAPI
RegSetValueExW( HKEY hkey
, LPWSTR lpszValueName
,
2764 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2770 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2771 dwReserved
, dwType
, lpbData
, cbData
);
2773 lpkey
= lookup_hkey( hkey
);
2776 return ERROR_INVALID_HANDLE
;
2778 lpkey
->flags
|= REG_OPTION_TAINTED
;
2780 if (lpszValueName
==NULL
) {
2781 /* Sets type and name for key's unnamed or default value */
2782 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2783 if (lpkey
->values
[i
].name
==NULL
)
2786 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2787 if ( lpkey
->values
[i
].name
&&
2788 !lstrcmpiW(lpszValueName
,lpkey
->values
[i
].name
)
2792 if (i
==lpkey
->nrofvalues
) {
2793 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2795 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2797 lpkey
->nrofvalues
++;
2798 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2800 if (lpkey
->values
[i
].name
==NULL
) {
2802 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2804 lpkey
->values
[i
].name
= NULL
;
2807 if (dwType
== REG_SZ
)
2808 cbData
= 2 * (lstrlenW ((LPCWSTR
)lpbData
) + 1);
2810 lpkey
->values
[i
].len
= cbData
;
2811 lpkey
->values
[i
].type
= dwType
;
2812 if (lpkey
->values
[i
].data
!=NULL
)
2813 free(lpkey
->values
[i
].data
);
2814 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2815 lpkey
->values
[i
].lastmodified
= time(NULL
);
2816 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2817 return ERROR_SUCCESS
;
2821 /******************************************************************************
2822 * RegSetValueEx32A [ADVAPI32.169]
2825 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2827 DWORD WINAPI
RegSetValueExA( HKEY hkey
, LPSTR lpszValueName
,
2828 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2832 LPWSTR lpszValueNameW
;
2836 return (ERROR_INVALID_PARAMETER
);
2838 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2839 dwReserved
,dwType
,lpbData
,cbData
);
2841 if ((1<<dwType
) & UNICONVMASK
)
2842 { if (dwType
== REG_SZ
)
2843 cbData
= strlen ((LPCSTR
)lpbData
)+1;
2845 buf
= (LPBYTE
)xmalloc( cbData
*2 );
2846 lmemcpynAtoW ((LPVOID
)buf
, lpbData
, cbData
);
2853 lpszValueNameW
= strdupA2W(lpszValueName
);
2855 lpszValueNameW
= NULL
;
2857 ret
=RegSetValueExW(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2860 free(lpszValueNameW
);
2869 /******************************************************************************
2870 * RegSetValueEx16 [KERNEL.226]
2872 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2873 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2875 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2876 dwReserved
,dwType
,lpbData
,cbData
);
2877 return RegSetValueExA( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2882 /******************************************************************************
2883 * RegSetValue32W [ADVAPI32.171]
2885 DWORD WINAPI
RegSetValueW( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwType
,
2886 LPCWSTR lpszData
, DWORD cbData
)
2891 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2892 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2894 if (lpszSubKey
&& *lpszSubKey
) {
2895 ret
=RegCreateKeyW(hkey
,lpszSubKey
,&xhkey
);
2896 if (ret
!=ERROR_SUCCESS
)
2900 if (dwType
!=REG_SZ
) {
2901 TRACE(reg
,"dwType=%ld - Changing to REG_SZ\n",dwType
);
2904 if (cbData
!=2*lstrlenW(lpszData
)+2) {
2905 TRACE(reg
,"Len=%ld != strlen(%s)+1=%d!\n",
2906 cbData
,debugstr_w(lpszData
),2*lstrlenW(lpszData
)+2
2908 cbData
=2*lstrlenW(lpszData
)+2;
2910 ret
=RegSetValueExW(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2917 /******************************************************************************
2918 * RegSetValue32A [ADVAPI32.168]
2921 DWORD WINAPI
RegSetValueA( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2922 LPCSTR lpszData
, DWORD cbData
)
2927 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2928 if (lpszSubKey
&& *lpszSubKey
) {
2929 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2930 if (ret
!=ERROR_SUCCESS
)
2935 if (dwType
!=REG_SZ
) {
2936 TRACE(reg
,"dwType=%ld!\n",dwType
);
2939 if (cbData
!=strlen(lpszData
)+1)
2940 cbData
=strlen(lpszData
)+1;
2941 ret
=RegSetValueExA(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2948 /******************************************************************************
2949 * RegSetValue16 [KERNEL.221] [SHELL.5]
2951 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2952 LPCSTR lpszData
, DWORD cbData
)
2954 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2955 debugstr_a(lpszData
),cbData
);
2956 return RegSetValueA(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2964 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2965 * RegEnumKey32W -> RegEnumKeyEx32W
2969 /******************************************************************************
2970 * RegEnumKeyEx32W [ADVAPI32.139]
2973 * hkey [I] Handle to key to enumerate
2974 * iSubKey [I] Index of subkey to enumerate
2975 * lpszName [O] Buffer for subkey name
2976 * lpcchName [O] Size of subkey buffer
2977 * lpdwReserved [I] Reserved
2978 * lpszClass [O] Buffer for class string
2979 * lpcchClass [O] Size of class buffer
2980 * ft [O] Time key last written to
2982 DWORD WINAPI
RegEnumKeyExW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2983 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2984 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2987 LPKEYSTRUCT lpkey
,lpxkey
;
2989 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2990 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2992 lpkey
= lookup_hkey( hkey
);
2994 return ERROR_INVALID_HANDLE
;
2996 if (!lpkey
->nextsub
)
2997 return ERROR_NO_MORE_ITEMS
;
2998 lpxkey
=lpkey
->nextsub
;
3000 /* Traverse the subkeys */
3001 while (iSubkey
&& lpxkey
) {
3003 lpxkey
=lpxkey
->next
;
3006 if (iSubkey
|| !lpxkey
)
3007 return ERROR_NO_MORE_ITEMS
;
3008 if (lstrlenW(lpxkey
->keyname
)+1>*lpcchName
)
3009 return ERROR_MORE_DATA
;
3010 memcpy(lpszName
,lpxkey
->keyname
,lstrlenW(lpxkey
->keyname
)*2+2);
3013 *lpcchName
= lstrlenW(lpszName
);
3016 /* FIXME: what should we write into it? */
3020 return ERROR_SUCCESS
;
3024 /******************************************************************************
3025 * RegEnumKey32W [ADVAPI32.140]
3027 DWORD WINAPI
RegEnumKeyW( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
3032 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3033 return RegEnumKeyExW(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
3037 /******************************************************************************
3038 * RegEnumKeyEx32A [ADVAPI32.138]
3040 DWORD WINAPI
RegEnumKeyExA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3041 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
3042 LPSTR lpszClass
, LPDWORD lpcchClass
,
3045 DWORD ret
,lpcchNameW
,lpcchClassW
;
3046 LPWSTR lpszNameW
,lpszClassW
;
3049 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3050 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
3053 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
3054 lpcchNameW
= *lpcchName
;
3060 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
3061 lpcchClassW
= *lpcchClass
;
3076 if (ret
==ERROR_SUCCESS
) {
3077 lstrcpyWtoA(lpszName
,lpszNameW
);
3078 *lpcchName
=strlen(lpszName
);
3080 lstrcpyWtoA(lpszClass
,lpszClassW
);
3081 *lpcchClass
=strlen(lpszClass
);
3092 /******************************************************************************
3093 * RegEnumKey32A [ADVAPI32.137]
3095 DWORD WINAPI
RegEnumKeyA( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3100 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3101 return RegEnumKeyExA( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
3106 /******************************************************************************
3107 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3109 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
3112 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
3113 return RegEnumKeyA( hkey
, iSubkey
, lpszName
, lpcchName
);
3118 * Enumerate Registry Values
3121 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3125 /******************************************************************************
3126 * RegEnumValue32W [ADVAPI32.142]
3129 * hkey [I] Handle to key to query
3130 * iValue [I] Index of value to query
3131 * lpszValue [O] Value string
3132 * lpcchValue [I/O] Size of value buffer (in wchars)
3133 * lpdReserved [I] Reserved
3134 * lpdwType [O] Type code
3135 * lpbData [O] Value data
3136 * lpcbData [I/O] Size of data buffer (in bytes)
3138 * Note: wide character functions that take and/or return "character counts"
3139 * use TCHAR (that is unsigned short or char) not byte counts.
3141 DWORD WINAPI
RegEnumValueW( HKEY hkey
, DWORD iValue
, LPWSTR lpszValue
,
3142 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3143 LPDWORD lpdwType
, LPBYTE lpbData
,
3149 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,debugstr_w(lpszValue
),
3150 lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3152 lpkey
= lookup_hkey( hkey
);
3154 if (!lpcbData
&& lpbData
)
3155 return ERROR_INVALID_PARAMETER
;
3158 return ERROR_INVALID_HANDLE
;
3160 if (lpkey
->nrofvalues
<= iValue
)
3161 return ERROR_NO_MORE_ITEMS
;
3163 val
= &(lpkey
->values
[iValue
]);
3166 if (lstrlenW(val
->name
)+1>*lpcchValue
) {
3167 *lpcchValue
= lstrlenW(val
->name
)+1;
3168 return ERROR_MORE_DATA
;
3170 memcpy(lpszValue
,val
->name
,2 * (lstrlenW(val
->name
)+1) );
3171 *lpcchValue
=lstrlenW(val
->name
);
3177 /* Can be NULL if the type code is not required */
3179 *lpdwType
= val
->type
;
3182 if (val
->len
>*lpcbData
)
3183 return ERROR_MORE_DATA
;
3184 memcpy(lpbData
,val
->data
,val
->len
);
3185 *lpcbData
= val
->len
;
3188 debug_print_value ( val
->data
, val
);
3189 return ERROR_SUCCESS
;
3193 /******************************************************************************
3194 * RegEnumValue32A [ADVAPI32.141]
3196 DWORD WINAPI
RegEnumValueA( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3197 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3198 LPDWORD lpdwType
, LPBYTE lpbData
,
3203 DWORD ret
,lpcbDataW
;
3206 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3207 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3209 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
3211 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
3212 lpcbDataW
= *lpcbData
;
3216 ret
= RegEnumValueW( hkey
, iValue
, lpszValueW
, lpcchValue
,
3217 lpdReserved
, &dwType
, lpbDataW
, &lpcbDataW
);
3222 if (ret
==ERROR_SUCCESS
) {
3223 lstrcpyWtoA(lpszValue
,lpszValueW
);
3225 if ((1<<dwType
) & UNICONVMASK
) {
3226 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
3228 if (lpcbDataW
> *lpcbData
)
3229 ret
= ERROR_MORE_DATA
;
3231 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
3233 *lpcbData
= lpcbDataW
;
3236 if (lpbDataW
) free(lpbDataW
);
3237 if (lpszValueW
) free(lpszValueW
);
3242 /******************************************************************************
3243 * RegEnumValue16 [KERNEL.223]
3245 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
3246 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
3247 LPDWORD lpdwType
, LPBYTE lpbData
,
3250 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
3251 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
3252 return RegEnumValueA( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
3253 lpdwType
, lpbData
, lpcbData
);
3257 /******************************************************************************
3258 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3259 * Releases the handle of the specified key
3262 * hkey [I] Handle of key to close
3265 * Success: ERROR_SUCCESS
3266 * Failure: Error code
3268 DWORD WINAPI
RegCloseKey( HKEY hkey
)
3270 TRACE(reg
,"(%x)\n",hkey
);
3272 /* The standard handles are allowed to succeed, even though they are not
3274 if (is_standard_hkey(hkey
))
3275 return ERROR_SUCCESS
;
3277 return remove_handle(hkey
);
3282 * Delete registry key
3285 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3289 /******************************************************************************
3290 * RegDeleteKey32W [ADVAPI32.134]
3293 * hkey [I] Handle to open key
3294 * lpszSubKey [I] Name of subkey to delete
3297 * Success: ERROR_SUCCESS
3298 * Failure: Error code
3300 DWORD WINAPI
RegDeleteKeyW( HKEY hkey
, LPWSTR lpszSubKey
)
3302 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
3306 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
3308 lpNextKey
= lookup_hkey(hkey
);
3310 return ERROR_INVALID_HANDLE
;
3312 /* Subkey param cannot be NULL */
3313 if (!lpszSubKey
|| !*lpszSubKey
)
3314 return ERROR_BADKEY
;
3316 /* We need to know the previous key in the hier. */
3317 split_keypath(lpszSubKey
,&wps
,&wpc
);
3321 lpxkey
=lpNextKey
->nextsub
;
3323 TRACE(reg
, " Scanning [%s]\n",
3324 debugstr_w(lpxkey
->keyname
));
3325 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3327 lpxkey
=lpxkey
->next
;
3331 TRACE(reg
, " Not found.\n");
3332 /* not found is success */
3333 return ERROR_SUCCESS
;
3338 lpxkey
= lpNextKey
->nextsub
;
3339 lplpPrevKey
= &(lpNextKey
->nextsub
);
3341 TRACE(reg
, " Scanning [%s]\n",
3342 debugstr_w(lpxkey
->keyname
));
3343 if (!lstrcmpiW(wps
[i
],lpxkey
->keyname
))
3345 lplpPrevKey
= &(lpxkey
->next
);
3346 lpxkey
= lpxkey
->next
;
3351 WARN(reg
, " Not found.\n");
3352 return ERROR_FILE_NOT_FOUND
;
3355 if (lpxkey
->nextsub
) {
3357 WARN(reg
, " Not empty.\n");
3358 return ERROR_CANTWRITE
;
3360 *lplpPrevKey
= lpxkey
->next
;
3361 free(lpxkey
->keyname
);
3363 free(lpxkey
->class);
3365 free(lpxkey
->values
);
3368 TRACE(reg
, " Done.\n");
3369 return ERROR_SUCCESS
;
3373 /******************************************************************************
3374 * RegDeleteKey32A [ADVAPI32.133]
3376 DWORD WINAPI
RegDeleteKeyA( HKEY hkey
, LPCSTR lpszSubKey
)
3381 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3382 lpszSubKeyW
= lpszSubKey
?strdupA2W(lpszSubKey
):NULL
;
3383 ret
= RegDeleteKeyW( hkey
, lpszSubKeyW
);
3384 if(lpszSubKeyW
) free(lpszSubKeyW
);
3389 /******************************************************************************
3390 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3392 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
3394 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
3395 return RegDeleteKeyA( hkey
, lpszSubKey
);
3400 * Delete registry value
3403 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3407 /******************************************************************************
3408 * RegDeleteValue32W [ADVAPI32.136]
3416 DWORD WINAPI
RegDeleteValueW( HKEY hkey
, LPWSTR lpszValue
)
3422 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3424 lpkey
= lookup_hkey( hkey
);
3426 return ERROR_INVALID_HANDLE
;
3429 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3430 if ( lpkey
->values
[i
].name
&&
3431 !lstrcmpiW(lpkey
->values
[i
].name
,lpszValue
)
3435 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3436 if (lpkey
->values
[i
].name
==NULL
)
3440 if (i
== lpkey
->nrofvalues
)
3441 return ERROR_FILE_NOT_FOUND
;
3443 val
= lpkey
->values
+i
;
3444 if (val
->name
) free(val
->name
);
3445 if (val
->data
) free(val
->data
);
3449 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3451 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3453 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3455 lpkey
->nrofvalues
--;
3456 return ERROR_SUCCESS
;
3460 /******************************************************************************
3461 * RegDeleteValue32A [ADVAPI32.135]
3463 DWORD WINAPI
RegDeleteValueA( HKEY hkey
, LPSTR lpszValue
)
3468 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3469 lpszValueW
= lpszValue
?strdupA2W(lpszValue
):NULL
;
3470 ret
= RegDeleteValueW( hkey
, lpszValueW
);
3471 if(lpszValueW
) free(lpszValueW
);
3476 /******************************************************************************
3477 * RegDeleteValue16 [KERNEL.222]
3479 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3481 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3482 return RegDeleteValueA( hkey
, lpszValue
);
3486 /******************************************************************************
3487 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3488 * Writes key to registry
3491 * hkey [I] Handle of key to write
3494 * Success: ERROR_SUCCESS
3495 * Failure: Error code
3497 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3502 TRACE(reg
, "(%x)\n", hkey
);
3504 lpkey
= lookup_hkey( hkey
);
3506 return ERROR_BADKEY
;
3508 ERR(reg
, "What is the correct filename?\n");
3510 ret
= _savereg( lpkey
, "foo.bar", TRUE
);
3513 return ERROR_SUCCESS
;
3515 return ERROR_UNKNOWN
; /* FIXME */
3519 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3522 /******************************************************************************
3523 * RegQueryInfoKey32W [ADVAPI32.153]
3526 * hkey [I] Handle to key to query
3527 * lpszClass [O] Buffer for class string
3528 * lpcchClass [O] Size of class string buffer
3529 * lpdwReserved [I] Reserved
3530 * lpcSubKeys [I] Buffer for number of subkeys
3531 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3532 * lpcchMaxClass [O] Buffer for longest class string length
3533 * lpcValues [O] Buffer for number of value entries
3534 * lpcchMaxValueName [O] Buffer for longest value name length
3535 * lpccbMaxValueData [O] Buffer for longest value data length
3536 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3538 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3539 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3540 * lpcchClass is NULL
3541 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3542 * (it's hard to test validity, so test !NULL instead)
3544 DWORD WINAPI
RegQueryInfoKeyW( HKEY hkey
, LPWSTR lpszClass
,
3545 LPDWORD lpcchClass
, LPDWORD lpdwReserved
,
3546 LPDWORD lpcSubKeys
, LPDWORD lpcchMaxSubkey
,
3547 LPDWORD lpcchMaxClass
, LPDWORD lpcValues
,
3548 LPDWORD lpcchMaxValueName
,
3549 LPDWORD lpccbMaxValueData
,
3550 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3552 LPKEYSTRUCT lpkey
,lpxkey
;
3553 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3556 TRACE(reg
,"(%x,%p,...)\n",hkey
,lpszClass
);
3557 lpkey
= lookup_hkey(hkey
);
3559 return ERROR_INVALID_HANDLE
;
3561 if (VERSION_GetVersion() == NT40
&& lpcchClass
== NULL
) {
3562 return ERROR_INVALID_PARAMETER
;
3564 /* either lpcchClass is valid or this is win95 and lpcchClass
3567 DWORD classLen
= lstrlenW(lpkey
->class);
3569 if (lpcchClass
&& classLen
+1>*lpcchClass
) {
3570 *lpcchClass
=classLen
+1;
3571 return ERROR_MORE_DATA
;
3574 *lpcchClass
=classLen
;
3575 memcpy(lpszClass
,lpkey
->class, classLen
*2 + 2);
3583 *lpcchClass
= lstrlenW(lpkey
->class);
3585 lpxkey
=lpkey
->nextsub
;
3586 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3589 if (lstrlenW(lpxkey
->keyname
)>maxsubkey
)
3590 maxsubkey
=lstrlenW(lpxkey
->keyname
);
3591 if (lpxkey
->class && lstrlenW(lpxkey
->class)>maxclass
)
3592 maxclass
=lstrlenW(lpxkey
->class);
3593 lpxkey
=lpxkey
->next
;
3595 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3596 LPKEYVALUE val
=lpkey
->values
+i
;
3598 if (val
->name
&& lstrlenW(val
->name
)>maxvname
)
3599 maxvname
=lstrlenW(val
->name
);
3600 if (val
->len
>maxvdata
)
3603 if (!maxclass
) maxclass
= 1;
3604 if (!maxvname
) maxvname
= 1;
3606 *lpcValues
= lpkey
->nrofvalues
;
3608 *lpcSubKeys
= nrofkeys
;
3610 *lpcchMaxSubkey
= maxsubkey
;
3612 *lpcchMaxClass
= maxclass
;
3613 if (lpcchMaxValueName
)
3614 *lpcchMaxValueName
= maxvname
;
3615 if (lpccbMaxValueData
)
3616 *lpccbMaxValueData
= maxvdata
;
3617 return ERROR_SUCCESS
;
3621 /******************************************************************************
3622 * RegQueryInfoKey32A [ADVAPI32.152]
3624 DWORD WINAPI
RegQueryInfoKeyA( HKEY hkey
, LPSTR lpszClass
, LPDWORD lpcchClass
,
3625 LPDWORD lpdwReserved
, LPDWORD lpcSubKeys
,
3626 LPDWORD lpcchMaxSubkey
, LPDWORD lpcchMaxClass
,
3627 LPDWORD lpcValues
, LPDWORD lpcchMaxValueName
,
3628 LPDWORD lpccbMaxValueData
,
3629 LPDWORD lpcbSecurityDescriptor
, FILETIME
*ft
)
3631 LPWSTR lpszClassW
= NULL
;
3634 TRACE(reg
,"(%x,%p,%p......)\n",hkey
, lpszClass
, lpcchClass
);
3637 lpszClassW
= (LPWSTR
)xmalloc((*lpcchClass
) * 2);
3638 } else if (VERSION_GetVersion() == WIN95
) {
3639 /* win95 allows lpcchClass to be null */
3640 /* we don't know how big lpszClass is, would
3641 MAX_PATHNAME_LEN be the correct default? */
3642 lpszClassW
= (LPWSTR
)xmalloc(MAX_PATHNAME_LEN
*2);
3647 ret
=RegQueryInfoKeyW(
3658 lpcbSecurityDescriptor
,
3661 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3662 lstrcpyWtoA(lpszClass
,lpszClassW
);
3669 /******************************************************************************
3670 * RegConnectRegistry32W [ADVAPI32.128]
3673 * lpMachineName [I] Address of name of remote computer
3674 * hHey [I] Predefined registry handle
3675 * phkResult [I] Address of buffer for remote registry handle
3677 LONG WINAPI
RegConnectRegistryW( LPCWSTR lpMachineName
, HKEY hKey
,
3680 TRACE(reg
,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName
),hKey
,phkResult
);
3682 if (!lpMachineName
|| !*lpMachineName
) {
3683 /* Use the local machine name */
3684 return RegOpenKey16( hKey
, "", phkResult
);
3687 FIXME(reg
,"Cannot connect to %s\n",debugstr_w(lpMachineName
));
3688 return ERROR_BAD_NETPATH
;
3692 /******************************************************************************
3693 * RegConnectRegistry32A [ADVAPI32.127]
3695 LONG WINAPI
RegConnectRegistryA( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3698 LPWSTR machineW
= strdupA2W(machine
);
3699 ret
= RegConnectRegistryW( machineW
, hkey
, reskey
);
3705 /******************************************************************************
3706 * RegGetKeySecurity [ADVAPI32.144]
3707 * Retrieves a copy of security descriptor protecting the registry key
3710 * hkey [I] Open handle of key to set
3711 * SecurityInformation [I] Descriptor contents
3712 * pSecurityDescriptor [O] Address of descriptor for key
3713 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3716 * Success: ERROR_SUCCESS
3717 * Failure: Error code
3719 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3720 SECURITY_INFORMATION SecurityInformation
,
3721 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
3722 LPDWORD lpcbSecurityDescriptor
)
3726 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,SecurityInformation
,pSecurityDescriptor
,
3727 lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3729 lpkey
= lookup_hkey( hkey
);
3731 return ERROR_INVALID_HANDLE
;
3733 /* FIXME: Check for valid SecurityInformation values */
3735 if (*lpcbSecurityDescriptor
< sizeof(SECURITY_DESCRIPTOR
))
3736 return ERROR_INSUFFICIENT_BUFFER
;
3738 FIXME(reg
, "(%x,%ld,%p,%ld): stub\n",hkey
,SecurityInformation
,
3739 pSecurityDescriptor
,lpcbSecurityDescriptor
?*lpcbSecurityDescriptor
:0);
3741 return ERROR_SUCCESS
;
3745 /******************************************************************************
3746 * RegLoadKey32W [ADVAPI32.???]
3749 * hkey [I] Handle of open key
3750 * lpszSubKey [I] Address of name of subkey
3751 * lpszFile [I] Address of filename for registry information
3753 LONG WINAPI
RegLoadKeyW( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3756 TRACE(reg
,"(%x,%s,%s)\n",hkey
,debugstr_w(lpszSubKey
),debugstr_w(lpszFile
));
3758 /* Do this check before the hkey check */
3759 if (!lpszSubKey
|| !*lpszSubKey
|| !lpszFile
|| !*lpszFile
)
3760 return ERROR_INVALID_PARAMETER
;
3762 lpkey
= lookup_hkey( hkey
);
3764 return ERROR_INVALID_HANDLE
;
3766 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3767 debugstr_w(lpszFile
));
3769 return ERROR_SUCCESS
;
3773 /******************************************************************************
3774 * RegLoadKey32A [ADVAPI32.???]
3776 LONG WINAPI
RegLoadKeyA( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3779 LPWSTR lpszSubKeyW
= strdupA2W(lpszSubKey
);
3780 LPWSTR lpszFileW
= strdupA2W(lpszFile
);
3781 ret
= RegLoadKeyW( hkey
, lpszSubKeyW
, lpszFileW
);
3782 if(lpszFileW
) free(lpszFileW
);
3783 if(lpszSubKeyW
) free(lpszSubKeyW
);
3788 /******************************************************************************
3789 * RegNotifyChangeKeyValue [ADVAPI32.???]
3792 * hkey [I] Handle of key to watch
3793 * fWatchSubTree [I] Flag for subkey notification
3794 * fdwNotifyFilter [I] Changes to be reported
3795 * hEvent [I] Handle of signaled event
3796 * fAsync [I] Flag for asynchronous reporting
3798 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL fWatchSubTree
,
3799 DWORD fdwNotifyFilter
, HANDLE hEvent
,
3803 TRACE(reg
,"(%x,%i,%ld,%x,%i)\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3806 lpkey
= lookup_hkey( hkey
);
3808 return ERROR_INVALID_HANDLE
;
3810 FIXME(reg
,"(%x,%i,%ld,%x,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3813 return ERROR_SUCCESS
;
3817 /******************************************************************************
3818 * RegUnLoadKey32W [ADVAPI32.173]
3821 * hkey [I] Handle of open key
3822 * lpSubKey [I] Address of name of subkey to unload
3824 LONG WINAPI
RegUnLoadKeyW( HKEY hkey
, LPCWSTR lpSubKey
)
3826 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3827 return ERROR_SUCCESS
;
3831 /******************************************************************************
3832 * RegUnLoadKey32A [ADVAPI32.172]
3834 LONG WINAPI
RegUnLoadKeyA( HKEY hkey
, LPCSTR lpSubKey
)
3837 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
3838 ret
= RegUnLoadKeyW( hkey
, lpSubKeyW
);
3839 if(lpSubKeyW
) free(lpSubKeyW
);
3844 /******************************************************************************
3845 * RegSetKeySecurity [ADVAPI32.167]
3848 * hkey [I] Open handle of key to set
3849 * SecurityInfo [I] Descriptor contents
3850 * pSecurityDesc [I] Address of descriptor for key
3852 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3853 PSECURITY_DESCRIPTOR pSecurityDesc
)
3857 TRACE(reg
,"(%x,%ld,%p)\n",hkey
,SecurityInfo
,pSecurityDesc
);
3859 /* It seems to perform this check before the hkey check */
3860 if ((SecurityInfo
& OWNER_SECURITY_INFORMATION
) ||
3861 (SecurityInfo
& GROUP_SECURITY_INFORMATION
) ||
3862 (SecurityInfo
& DACL_SECURITY_INFORMATION
) ||
3863 (SecurityInfo
& SACL_SECURITY_INFORMATION
)) {
3866 return ERROR_INVALID_PARAMETER
;
3869 return ERROR_INVALID_PARAMETER
;
3871 lpkey
= lookup_hkey( hkey
);
3873 return ERROR_INVALID_HANDLE
;
3875 FIXME(reg
,":(%x,%ld,%p): stub\n",hkey
,SecurityInfo
,pSecurityDesc
);
3877 return ERROR_SUCCESS
;
3881 /******************************************************************************
3882 * RegSaveKey32W [ADVAPI32.166]
3885 * hkey [I] Handle of key where save begins
3886 * lpFile [I] Address of filename to save to
3887 * sa [I] Address of security structure
3889 LONG WINAPI
RegSaveKeyW( HKEY hkey
, LPCWSTR lpFile
,
3890 LPSECURITY_ATTRIBUTES sa
)
3894 TRACE(reg
, "(%x,%s,%p)\n", hkey
, debugstr_w(lpFile
), sa
);
3896 /* It appears to do this check before the hkey check */
3897 if (!lpFile
|| !*lpFile
)
3898 return ERROR_INVALID_PARAMETER
;
3900 lpkey
= lookup_hkey( hkey
);
3902 return ERROR_INVALID_HANDLE
;
3904 FIXME(reg
, "(%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3906 return ERROR_SUCCESS
;
3910 /******************************************************************************
3911 * RegSaveKey32A [ADVAPI32.165]
3913 LONG WINAPI
RegSaveKeyA( HKEY hkey
, LPCSTR lpFile
,
3914 LPSECURITY_ATTRIBUTES sa
)
3917 LPWSTR lpFileW
= strdupA2W(lpFile
);
3918 ret
= RegSaveKeyW( hkey
, lpFileW
, sa
);
3924 /******************************************************************************
3925 * RegRestoreKey32W [ADVAPI32.164]
3928 * hkey [I] Handle of key where restore begins
3929 * lpFile [I] Address of filename containing saved tree
3930 * dwFlags [I] Optional flags
3932 LONG WINAPI
RegRestoreKeyW( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3936 TRACE(reg
, "(%x,%s,%ld)\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3938 /* It seems to do this check before the hkey check */
3939 if (!lpFile
|| !*lpFile
)
3940 return ERROR_INVALID_PARAMETER
;
3942 lpkey
= lookup_hkey( hkey
);
3944 return ERROR_INVALID_HANDLE
;
3946 FIXME(reg
,"(%x,%s,%ld): stub\n",hkey
,debugstr_w(lpFile
),dwFlags
);
3948 /* Check for file existence */
3950 return ERROR_SUCCESS
;
3954 /******************************************************************************
3955 * RegRestoreKey32A [ADVAPI32.163]
3957 LONG WINAPI
RegRestoreKeyA( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3960 LPWSTR lpFileW
= strdupA2W(lpFile
);
3961 ret
= RegRestoreKeyW( hkey
, lpFileW
, dwFlags
);
3962 if(lpFileW
) free(lpFileW
);
3967 /******************************************************************************
3968 * RegReplaceKey32W [ADVAPI32.162]
3971 * hkey [I] Handle of open key
3972 * lpSubKey [I] Address of name of subkey
3973 * lpNewFile [I] Address of filename for file with new data
3974 * lpOldFile [I] Address of filename for backup file
3976 LONG WINAPI
RegReplaceKeyW( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3981 TRACE(reg
,"(%x,%s,%s,%s)\n",hkey
,debugstr_w(lpSubKey
),
3982 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3984 lpkey
= lookup_hkey( hkey
);
3986 return ERROR_INVALID_HANDLE
;
3988 FIXME(reg
, "(%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3989 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3991 return ERROR_SUCCESS
;
3995 /******************************************************************************
3996 * RegReplaceKey32A [ADVAPI32.161]
3998 LONG WINAPI
RegReplaceKeyA( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
4002 LPWSTR lpSubKeyW
= strdupA2W(lpSubKey
);
4003 LPWSTR lpNewFileW
= strdupA2W(lpNewFile
);
4004 LPWSTR lpOldFileW
= strdupA2W(lpOldFile
);
4005 ret
= RegReplaceKeyW( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);