4 * Copyright 1996 Marcus Meissner
6 * December 21, 1997 - Kevin Cozens
7 * Fixed bugs in the _w95_loadreg() function. Added extra information
8 * regarding the format of the Windows '95 registry files.
10 * May 5, 1998 - Matthew Becker
11 * Changed optionflags to DWORD instead of int because it could be 0x8000000
12 * All error return values must come from winerror.h
15 * When changing this file, please re-run the regtest program to ensure
16 * the conditions are handled properly.
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
42 static void REGISTRY_Init();
43 /* FIXME: following defines should be configured global ... */
45 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
46 #define WINE_PREFIX "/.wine"
47 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
48 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
50 /* relative in ~user/.wine/ : */
51 #define SAVE_CURRENT_USER "user.reg"
52 #define SAVE_LOCAL_MACHINE "system.reg"
54 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
55 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
57 /* one value of a key */
58 typedef struct tagKEYVALUE
60 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
61 DWORD type
; /* type of value */
62 DWORD len
; /* length of data in BYTEs */
63 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
64 LPBYTE data
; /* content, may be strings, binaries, etc. */
65 } KEYVALUE
,*LPKEYVALUE
;
68 typedef struct tagKEYSTRUCT
70 LPWSTR keyname
; /* name of THIS key (UNICODE) */
71 DWORD flags
; /* flags. */
74 DWORD nrofvalues
; /* nr of values in THIS key */
75 LPKEYVALUE values
; /* values in THIS key */
76 /* key management pointers */
77 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
78 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
79 } KEYSTRUCT
, *LPKEYSTRUCT
;
82 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
83 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
84 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
85 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
87 /* dynamic, not saved */
88 static KEYSTRUCT
*key_performance_data
=NULL
;
89 static KEYSTRUCT
*key_current_config
=NULL
;
90 static KEYSTRUCT
*key_dyn_data
=NULL
;
92 /* what valuetypes do we need to convert? */
93 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
98 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
99 * If so, can we remove them?
101 * No, the memory handling functions are called very often in here,
102 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
103 * loading 100 times slower. -MM
105 static LPWSTR
strdupA2W(LPCSTR src
)
107 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
108 lstrcpyAtoW(dest
,src
);
112 static LPWSTR
strdupW(LPCWSTR a
) {
116 len
=sizeof(WCHAR
)*(lstrlen32W(a
)+1);
117 b
=(LPWSTR
)xmalloc(len
);
123 static struct openhandle
{
128 static int nrofopenhandles
=0;
129 static int currenthandle
=1;
132 /******************************************************************************
133 * add_handle [Internal]
135 static void add_handle( HKEY hkey
, LPKEYSTRUCT lpkey
, REGSAM accessmask
)
139 TRACE(reg
,"(%x,%p,%lx)\n",hkey
,lpkey
,accessmask
);
141 TRACE(reg
," (%s)\n",debugstr_w(lpkey
->keyname
));
143 /* Check for duplicates */
144 for (i
=0;i
<nrofopenhandles
;i
++) {
145 if (openhandles
[i
].lpkey
==lpkey
) {
146 /* This is not really an error - the user is allowed to create
147 two (or more) handles to the same key */
148 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
150 if (openhandles
[i
].hkey
==hkey
) {
151 WARN(reg
, "Adding handle %x twice\n",hkey
);
154 openhandles
=xrealloc( openhandles
,
155 sizeof(struct openhandle
)*(nrofopenhandles
+1));
157 openhandles
[i
].lpkey
= lpkey
;
158 openhandles
[i
].hkey
= hkey
;
159 openhandles
[i
].accessmask
= accessmask
;
164 /******************************************************************************
165 * get_handle [Internal]
168 * Success: Pointer to key
171 static LPKEYSTRUCT
get_handle( HKEY hkey
)
175 for (i
=0; i
<nrofopenhandles
; i
++)
176 if (openhandles
[i
].hkey
== hkey
)
177 return openhandles
[i
].lpkey
;
178 WARN(reg
, "Could not find handle %x\n",hkey
);
183 /******************************************************************************
184 * remove_handle [Internal]
187 * hkey [I] Handle of key to remove
190 * Success: ERROR_SUCCESS
191 * Failure: ERROR_INVALID_HANDLE
193 static DWORD
remove_handle( HKEY hkey
)
197 for (i
=0;i
<nrofopenhandles
;i
++)
198 if (openhandles
[i
].hkey
==hkey
)
201 if (i
== nrofopenhandles
) {
202 WARN(reg
, "Could not find handle %x\n",hkey
);
203 return ERROR_INVALID_HANDLE
;
206 memcpy( openhandles
+i
,
208 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
210 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
212 return ERROR_SUCCESS
;
216 /******************************************************************************
217 * lookup_hkey [Internal]
219 * Just as the name says. Creates the root keys on demand, so we can call the
220 * Reg* functions at any time.
223 * Success: Pointer to key structure
226 #define ADD_ROOT_KEY(xx) \
227 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
228 memset(xx,'\0',sizeof(KEYSTRUCT));\
229 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
231 static LPKEYSTRUCT
lookup_hkey( HKEY hkey
)
234 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
235 * some programs. Do not remove those cases. -MM
239 case HKEY_CLASSES_ROOT
: {
240 if (!key_classes_root
) {
243 /* calls lookup_hkey recursively, TWICE */
244 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
245 ERR(reg
,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
248 key_classes_root
= lookup_hkey(cl_r_hkey
);
250 return key_classes_root
;
252 case HKEY_CURRENT_USER
:
253 if (!key_current_user
) {
257 pwd
=getpwuid(getuid());
258 /* calls lookup_hkey recursively, TWICE */
259 if (pwd
&& pwd
->pw_name
) {
260 if (RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
)!=ERROR_SUCCESS
) {
261 ERR(reg
,"Could not create HU\\%s. This is impossible.\n",pwd
->pw_name
);
264 key_current_user
= lookup_hkey(c_u_hkey
);
266 /* nothing found, use standalone */
267 ADD_ROOT_KEY(key_current_user
);
270 return key_current_user
;
271 case HKEY_LOCAL_MACHINE
:
272 if (!key_local_machine
) {
273 ADD_ROOT_KEY(key_local_machine
);
276 return key_local_machine
;
279 ADD_ROOT_KEY(key_users
);
282 case HKEY_PERFORMANCE_DATA
:
283 if (!key_performance_data
) {
284 ADD_ROOT_KEY(key_performance_data
);
286 return key_performance_data
;
289 ADD_ROOT_KEY(key_dyn_data
);
292 case HKEY_CURRENT_CONFIG
:
293 if (!key_current_config
) {
294 ADD_ROOT_KEY(key_current_config
);
296 return key_current_config
;
298 return get_handle(hkey
);
303 /* so we don't accidently access them ... */
304 #define key_current_config NULL NULL
305 #define key_current_user NULL NULL
306 #define key_users NULL NULL
307 #define key_local_machine NULL NULL
308 #define key_classes_root NULL NULL
309 #define key_dyn_data NULL NULL
310 #define key_performance_data NULL NULL
312 /******************************************************************************
313 * split_keypath [Internal]
314 * splits the unicode string 'wp' into an array of strings.
315 * the array is allocated by this function.
316 * Free the array using FREE_KEY_PATH
319 * wp [I] String to split up
320 * wpv [O] Array of pointers to strings
321 * wpc [O] Number of components
323 static void split_keypath( LPCWSTR wp
, LPWSTR
**wpv
, int *wpc
)
328 TRACE(reg
,"(%s,%p,%p)\n",debugstr_w(wp
),wpv
,wpc
);
330 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
332 /* We know we have at least one substring */
335 /* Replace each backslash with NULL, and increment the count */
336 for (i
=0;ws
[i
];i
++) {
345 /* Allocate the space for the array of pointers, leaving room for the
347 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
350 /* Assign each pointer to the appropriate character in the string */
355 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
360 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
365 /******************************************************************************
366 * REGISTRY_Init [Internal]
367 * Registry initialisation, allocates some default keys.
369 static void REGISTRY_Init() {
373 TRACE(reg
,"(void)\n");
375 RegCreateKey16(HKEY_DYN_DATA
,"PerfStats\\StatData",&hkey
);
378 /* This was an Open, but since it is called before the real registries
379 are loaded, it was changed to a Create - MTB 980507*/
380 RegCreateKey16(HKEY_LOCAL_MACHINE
,"HARDWARE\\DESCRIPTION\\System",&hkey
);
381 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
384 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
388 * string RegisteredOwner
389 * string RegisteredOrganization
392 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
397 if (-1!=gethostname(buf
,200)) {
398 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
399 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
405 /************************ SAVE Registry Function ****************************/
407 #define REGISTRY_SAVE_VERSION 0x00000001
409 /* Registry saveformat:
410 * If you change it, increase above number by 1, which will flush
411 * old registry database files.
414 * "WINE REGISTRY Version %d"
418 * valuename=lastmodified,type,data
422 * keyname,valuename,stringdata:
423 * the usual ascii characters from 0x00-0xff (well, not 0x00)
424 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
425 * ( "=\\\t" escaped in \uXXXX form.)
429 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
431 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
432 * SaveOnlyUpdatedKeys=yes
435 _save_check_tainted(LPKEYSTRUCT lpkey
) {
440 if (lpkey
->flags
& REG_OPTION_TAINTED
)
445 if (_save_check_tainted(lpkey
->nextsub
)) {
446 lpkey
->flags
|= REG_OPTION_TAINTED
;
455 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
468 if (escapeeq
&& *s
=='=')
471 fputc(*s
,F
); /* if \\ then put it twice. */
473 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
481 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
487 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
488 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
490 for (tabs
=level
;tabs
--;)
492 _save_USTRING(F
,lpxkey
->keyname
,1);
494 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
495 LPKEYVALUE val
=lpxkey
->values
+i
;
497 for (tabs
=level
+1;tabs
--;)
499 _save_USTRING(F
,val
->name
,0);
501 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
502 if ((1<<val
->type
) & UNICONVMASK
)
503 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
505 for (j
=0;j
<val
->len
;j
++)
506 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
509 /* descend recursively */
510 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
519 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
520 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
521 _save_check_tainted(lpkey
->nextsub
);
522 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
526 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
531 WARN(reg
,"Couldn't open %s for writing: %s\n",
536 if (!_savesubreg(F
,lpkey
,all
)) {
539 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
547 /******************************************************************************
548 * SHELL_SaveRegistry [Internal]
550 void SHELL_SaveRegistry( void )
558 TRACE(reg
,"(void)\n");
561 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
567 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
579 if (lstrcmpi32A(buf
,"yes"))
581 pwd
=getpwuid(getuid());
582 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
586 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
587 strlen(SAVE_CURRENT_USER
) + 2 );
588 strcpy(fn
,pwd
->pw_dir
);
589 strcat(fn
,WINE_PREFIX
);
590 /* create the directory. don't care about errorcodes. */
591 mkdir(fn
,0755); /* drwxr-xr-x */
592 strcat(fn
,"/"SAVE_CURRENT_USER
);
593 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
594 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
595 if (_savereg(lookup_hkey(HKEY_CURRENT_USER
),tmp
,all
)) {
596 if (-1==rename(tmp
,fn
)) {
597 perror("rename tmp registry");
603 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
604 strcpy(fn
,pwd
->pw_dir
);
605 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
606 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
607 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
608 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE
),tmp
,all
)) {
609 if (-1==rename(tmp
,fn
)) {
610 perror("rename tmp registry");
617 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
620 /************************ LOAD Registry Function ****************************/
623 /******************************************************************************
624 * _find_or_add_key [Internal]
626 static LPKEYSTRUCT
_find_or_add_key( LPKEYSTRUCT lpkey
, LPWSTR keyname
)
628 LPKEYSTRUCT lpxkey
,*lplpkey
;
630 if ((!keyname
) || (keyname
[0]==0)) {
634 lplpkey
= &(lpkey
->nextsub
);
637 if (!lstrcmpi32W(lpxkey
->keyname
,keyname
))
639 lplpkey
= &(lpxkey
->next
);
643 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
645 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
646 lpxkey
->keyname
= keyname
;
654 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
660 if (name
&& !*name
) {/* empty string equals default (NULL) value */
665 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
671 if ( val
->name
!=NULL
&&
672 !lstrcmpi32W(val
->name
,name
)
677 if (i
==lpkey
->nrofvalues
) {
678 lpkey
->values
= xrealloc(
680 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
683 memset(val
,'\0',sizeof(KEYVALUE
));
689 if (val
->lastmodified
<lastmodified
) {
690 val
->lastmodified
=lastmodified
;
701 /* reads a line including dynamically enlarging the readbuffer and throwing
705 _wine_read_line(FILE *F
,char **buf
,int *len
) {
714 s
=fgets(curread
,mylen
,F
);
717 if (NULL
==(s
=strchr(curread
,'\n'))) {
718 /* buffer wasn't large enough */
719 curoff
= strlen(*buf
);
720 *buf
= xrealloc(*buf
,*len
*2);
721 curread
= *buf
+ curoff
;
722 mylen
= *len
; /* we filled up the buffer and
723 * got new '*len' bytes to fill
731 /* throw away comments */
732 if (**buf
=='#' || **buf
==';') {
737 if (s
) /* got end of line */
743 /* converts a char* into a UNICODE string (up to a special char)
744 * and returns the position exactly after that string
747 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
751 /* read up to "=" or "\0" or "\n" */
754 /* empty string is the win3.1 default value(NULL)*/
758 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
760 while (*s
&& (*s
!='\n') && (*s
!='=')) {
762 *ws
++=*((unsigned char*)s
++);
771 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
779 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
780 if (!sscanf(xbuf
,"%x",&wc
))
781 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
783 *ws
++ =(unsigned short)wc
;
790 *str
= strdupW(*str
);
798 /******************************************************************************
799 * _wine_loadsubkey [Internal]
802 * It seems like this is returning a boolean. Should it?
808 static int _wine_loadsubkey( FILE *F
, LPKEYSTRUCT lpkey
, int level
, char **buf
,
809 int *buflen
, DWORD optflag
)
816 TRACE(reg
,"(%p,%p,%d,%s,%d,%lx)\n", F
, lpkey
, level
, debugstr_a(*buf
),
819 lpkey
->flags
|= optflag
;
821 /* Good. We already got a line here ... so parse it */
831 WARN(reg
,"Got a subhierarchy without resp. key?\n");
834 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
838 /* let the caller handle this line */
839 if (i
<level
|| **buf
=='\0')
842 /* it can be: a value or a keyname. Parse the name first */
843 s
=_wine_read_USTRING(s
,&name
);
845 /* switch() default: hack to avoid gotos */
849 lpxkey
=_find_or_add_key(lpkey
,name
);
852 int len
,lastmodified
,type
;
855 WARN(reg
,"Unexpected character: %c\n",*s
);
859 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
860 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
866 if ((1<<type
) & UNICONVMASK
) {
867 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
869 len
= lstrlen32W((LPWSTR
)data
)*2+2;
874 data
= (LPBYTE
)xmalloc(len
+1);
875 for (i
=0;i
<len
;i
++) {
877 if (*s
>='0' && *s
<='9')
879 if (*s
>='a' && *s
<='f')
880 data
[i
]=(*s
-'a'+'\xa')<<4;
881 if (*s
>='A' && *s
<='F')
882 data
[i
]=(*s
-'A'+'\xa')<<4;
884 if (*s
>='0' && *s
<='9')
886 if (*s
>='a' && *s
<='f')
887 data
[i
]|=*s
-'a'+'\xa';
888 if (*s
>='A' && *s
<='F')
889 data
[i
]|=*s
-'A'+'\xa';
893 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
896 /* read the next line */
897 if (!_wine_read_line(F
,buf
,buflen
))
904 /******************************************************************************
905 * _wine_loadsubreg [Internal]
907 static int _wine_loadsubreg( FILE *F
, LPKEYSTRUCT lpkey
, DWORD optflag
)
913 buf
=xmalloc(10);buflen
=10;
914 if (!_wine_read_line(F
,&buf
,&buflen
)) {
918 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
922 if (ver
!=REGISTRY_SAVE_VERSION
) {
923 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
927 if (!_wine_read_line(F
,&buf
,&buflen
)) {
931 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
940 /******************************************************************************
941 * _wine_loadreg [Internal]
943 static void _wine_loadreg( LPKEYSTRUCT lpkey
, char *fn
, DWORD optflag
)
947 TRACE(reg
,"(%p,%s,%lx)\n",lpkey
,debugstr_a(fn
),optflag
);
951 WARN(reg
,"Couldn't open %s for reading: %s\n",fn
,strerror(errno
) );
954 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
963 /******************************************************************************
964 * _copy_registry [Internal]
966 static void _copy_registry( LPKEYSTRUCT from
, LPKEYSTRUCT to
)
974 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
976 for (j
=0;j
<from
->nrofvalues
;j
++) {
980 valfrom
= from
->values
+j
;
982 if (name
) name
=strdupW(name
);
983 data
=(LPBYTE
)xmalloc(valfrom
->len
);
984 memcpy(data
,valfrom
->data
,valfrom
->len
);
992 valfrom
->lastmodified
995 _copy_registry(from
,lpxkey
);
1001 /* WINDOWS 95 REGISTRY LOADER */
1003 * Structure of a win95 registry database.
1005 * 0 : "CREG" - magic
1007 * 8 : DWORD offset_of_RGDB_part
1008 * 0C..0F: ? (someone fill in please)
1009 * 10: WORD number of RGDB blocks
1011 * 14: WORD always 0000?
1012 * 16: WORD always 0001?
1013 * 18..1F: ? (someone fill in please)
1017 * 0 : "RGKN" - magic
1018 * 4 : DWORD offset to first RGDB section
1019 * 8 : DWORD offset to ?
1020 * C..0x1B: ? (fill in)
1021 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1023 * Disk Key Entry Structure:
1024 * 00: DWORD - Free entry indicator(?)
1025 * 04: DWORD - Hash = sum of bytes of keyname
1026 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1027 * 0C: DWORD - disk address of PreviousLevel Key.
1028 * 10: DWORD - disk address of Next Sublevel Key.
1029 * 14: DWORD - disk address of Next Key (on same level).
1030 * DKEP>18: WORD - Nr, Low Significant part.
1031 * 1A: WORD - Nr, High Significant part.
1033 * The disk address always points to the nr part of the previous key entry
1034 * of the referenced key. Don't ask me why, or even if I got this correct
1035 * from staring at 1kg of hexdumps. (DKEP)
1037 * The High significant part of the structure seems to equal the number
1038 * of the RGDB section. The low significant part is a unique ID within
1041 * There are two minor corrections to the position of that structure.
1042 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1043 * the DKE reread from there.
1044 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1045 * CPS - I have not experienced the above phenomenon in my registry files
1048 * 00: "RGDB" - magic
1049 * 04: DWORD offset to next RGDB section
1051 * 0C: WORD always 000d?
1052 * 0E: WORD RGDB block number
1053 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1055 * 20.....: disk keys
1058 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1059 * 08: WORD nrLS - low significant part of NR
1060 * 0A: WORD nrHS - high significant part of NR
1061 * 0C: DWORD bytesused - bytes used in this structure.
1062 * 10: WORD name_len - length of name in bytes. without \0
1063 * 12: WORD nr_of_values - number of values.
1064 * 14: char name[name_len] - name string. No \0.
1065 * 14+name_len: disk values
1066 * nextkeyoffset: ... next disk key
1069 * 00: DWORD type - value type (hmm, could be WORD too)
1070 * 04: DWORD - unknown, usually 0
1071 * 08: WORD namelen - length of Name. 0 means name=NULL
1072 * 0C: WORD datalen - length of Data.
1073 * 10: char name[namelen] - name, no \0
1074 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1075 * 10+namelen+datalen: next values or disk key
1077 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1078 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1079 * structure) and reading another RGDB_section.
1080 * repeat until end of file.
1082 * An interesting relationship exists in RGDB_section. The value at offset
1083 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1084 * idea at the moment what this means. (Kevin Cozens)
1086 * FIXME: this description needs some serious help, yes.
1089 struct _w95keyvalue
{
1091 unsigned short datalen
;
1093 unsigned char *data
;
1101 struct _w95keyvalue
*values
;
1102 struct _w95key
*prevlvl
;
1103 struct _w95key
*nextsub
;
1104 struct _w95key
*next
;
1117 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
1120 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
1122 lstrcpynAtoW(dest
,src
,nchars
+1);
1128 /******************************************************************************
1129 * _w95_processKey [Internal]
1131 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1132 int nrLS
, int nrMS
, struct _w95_info
*info
)
1135 /* Disk Key Header structure (RGDB part) */
1137 unsigned long nextkeyoff
;
1138 unsigned short nrLS
;
1139 unsigned short nrMS
;
1140 unsigned long bytesused
;
1141 unsigned short keynamelen
;
1142 unsigned short values
;
1145 /* disk key values or nothing */
1147 /* Disk Key Value structure */
1151 unsigned short valnamelen
;
1152 unsigned short valdatalen
;
1153 /* valname, valdata */
1159 char *rgdbdata
= info
->rgdbbuffer
;
1160 int nbytes
= info
->rgdbsize
;
1161 char *curdata
= rgdbdata
;
1162 char *end
= rgdbdata
+ nbytes
;
1164 char *next
= rgdbdata
;
1170 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1172 memcpy(&off_next_rgdb
,curdata
+4,4);
1173 next
= curdata
+ off_next_rgdb
;
1174 nrgdb
= (int) *((short *)curdata
+ 7);
1176 } while (nrgdb
!= nrMS
&& (next
< end
));
1178 /* curdata now points to the start of the right RGDB section */
1181 #define XREAD(whereto,len) \
1182 if ((curdata + len) <end) {\
1183 memcpy(whereto,curdata,len);\
1189 XREAD(&dkh
, sizeof (dkh
));
1190 if (dkh
.nrLS
== nrLS
) break;
1192 curdata
+= dkh
.nextkeyoff
- sizeof(dkh
);
1193 } while (curdata
< next
);
1195 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1197 if (nrgdb
!= dkh
.nrMS
) {
1201 assert((dkh
.keynamelen
<2) || curdata
[0]);
1202 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1203 curdata
+= dkh
.keynamelen
;
1205 for (i
=0;i
< dkh
.values
; i
++) {
1211 XREAD(&dkv
,sizeof(dkv
));
1213 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1214 curdata
+= dkv
.valnamelen
;
1216 if ((1 << dkv
.type
) & UNICONVMASK
) {
1217 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1218 len
= 2*(dkv
.valdatalen
+ 1);
1220 /* I don't think we want to NULL terminate all data */
1221 data
= xmalloc(dkv
.valdatalen
);
1222 memcpy (data
, curdata
, dkv
.valdatalen
);
1223 len
= dkv
.valdatalen
;
1226 curdata
+= dkv
.valdatalen
;
1243 _w95_walkrgkn(LPKEYSTRUCT prevkey
, char *off
, struct _w95_info
*info
)
1246 /* Disk Key Entry structure (RGKN part) */
1250 unsigned long x3
;/*usually 0xFFFFFFFF */
1251 unsigned long prevlvl
;
1252 unsigned long nextsub
;
1254 unsigned short nrLS
;
1255 unsigned short nrMS
;
1256 } *dke
= (struct dke
*)off
;
1260 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1263 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1264 /* XXX <-- This is a hack*/
1269 if (dke
->nextsub
!= -1 &&
1270 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1271 && (dke
->nextsub
> 0x20)) {
1273 _w95_walkrgkn(lpxkey
,
1274 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1278 if (dke
->next
!= -1 &&
1279 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1280 (dke
->next
> 0x20)) {
1281 _w95_walkrgkn(prevkey
,
1282 info
->rgknbuffer
+ dke
->next
- 0x20,
1290 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1293 unsigned long where
,version
,rgdbsection
,end
;
1294 struct _w95_info info
;
1296 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1298 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1299 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1300 if (hfd
==HFILE_ERROR32
)
1303 if (4!=_lread32(hfd
,magic
,4))
1305 if (strcmp(magic
,"CREG")) {
1306 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1309 if (4!=_lread32(hfd
,&version
,4))
1311 if (4!=_lread32(hfd
,&rgdbsection
,4))
1313 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1315 if (4!=_lread32(hfd
,magic
,4))
1317 if (strcmp(magic
,"RGKN")) {
1318 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1322 /* STEP 1: Keylink structures */
1323 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1328 info
.rgknsize
= end
- where
;
1329 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1330 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1333 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1336 end
= hfdinfo
.nFileSizeLow
;
1337 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1339 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1342 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1343 info
.rgdbsize
= end
- rgdbsection
;
1345 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1349 _w95_walkrgkn(lpkey
, NULL
, &info
);
1351 free (info
.rgdbbuffer
);
1352 free (info
.rgknbuffer
);
1356 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1359 reghack - windows 3.11 registry data format demo program.
1361 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1362 a combined hash table and tree description, and finally a text table.
1364 The header is obvious from the struct header. The taboff1 and taboff2
1365 fields are always 0x20, and their usage is unknown.
1367 The 8-byte entry table has various entry types.
1369 tabent[0] is a root index. The second word has the index of the root of
1371 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1372 the index of the key/value that has that hash. Data with the same
1373 hash value are on a circular list. The other three words in the
1374 hash entry are always zero.
1375 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1376 entry: dirent and keyent/valent. They are identified by context.
1377 tabent[freeidx] is the first free entry. The first word in a free entry
1378 is the index of the next free entry. The last has 0 as a link.
1379 The other three words in the free list are probably irrelevant.
1381 Entries in text table are preceeded by a word at offset-2. This word
1382 has the value (2*index)+1, where index is the referring keyent/valent
1383 entry in the table. I have no suggestion for the 2* and the +1.
1384 Following the word, there are N bytes of data, as per the keyent/valent
1385 entry length. The offset of the keyent/valent entry is from the start
1386 of the text table to the first data byte.
1388 This information is not available from Microsoft. The data format is
1389 deduced from the reg.dat file by me. Mistakes may
1390 have been made. I claim no rights and give no guarantees for this program.
1392 Tor Sjøwall, tor@sn.no
1395 /* reg.dat header format */
1396 struct _w31_header
{
1397 char cookie
[8]; /* 'SHCC3.10' */
1398 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1399 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1400 unsigned long tabcnt
; /* number of entries in index table */
1401 unsigned long textoff
; /* offset of text part */
1402 unsigned long textsize
; /* byte size of text part */
1403 unsigned short hashsize
; /* hash size */
1404 unsigned short freeidx
; /* free index */
1407 /* generic format of table entries */
1408 struct _w31_tabent
{
1409 unsigned short w0
, w1
, w2
, w3
;
1412 /* directory tabent: */
1413 struct _w31_dirent
{
1414 unsigned short sibling_idx
; /* table index of sibling dirent */
1415 unsigned short child_idx
; /* table index of child dirent */
1416 unsigned short key_idx
; /* table index of key keyent */
1417 unsigned short value_idx
; /* table index of value valent */
1421 struct _w31_keyent
{
1422 unsigned short hash_idx
; /* hash chain index for string */
1423 unsigned short refcnt
; /* reference count */
1424 unsigned short length
; /* length of string */
1425 unsigned short string_off
; /* offset of string in text table */
1429 struct _w31_valent
{
1430 unsigned short hash_idx
; /* hash chain index for string */
1431 unsigned short refcnt
; /* reference count */
1432 unsigned short length
; /* length of string */
1433 unsigned short string_off
; /* offset of string in text table */
1436 /* recursive helper function to display a directory tree */
1438 __w31_dumptree( unsigned short idx
,
1440 struct _w31_tabent
*tab
,
1441 struct _w31_header
*head
,
1443 time_t lastmodified
,
1446 struct _w31_dirent
*dir
;
1447 struct _w31_keyent
*key
;
1448 struct _w31_valent
*val
;
1449 LPKEYSTRUCT xlpkey
= NULL
;
1451 static char tail
[400];
1454 dir
=(struct _w31_dirent
*)&tab
[idx
];
1457 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1459 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1460 tail
[key
->length
]='\0';
1461 /* all toplevel entries AND the entries in the
1462 * toplevel subdirectory belong to \SOFTWARE\Classes
1464 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1465 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1466 idx
=dir
->sibling_idx
;
1469 name
=strdupA2W(tail
);
1471 xlpkey
=_find_or_add_key(lpkey
,name
);
1473 /* only add if leaf node or valued node */
1474 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1475 if (dir
->value_idx
) {
1476 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1477 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1478 tail
[val
->length
]='\0';
1479 value
=strdupA2W(tail
);
1480 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1484 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1486 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1487 idx
=dir
->sibling_idx
;
1492 /******************************************************************************
1493 * _w31_loadreg [Internal]
1495 void _w31_loadreg() {
1497 struct _w31_header head
;
1498 struct _w31_tabent
*tab
;
1502 BY_HANDLE_FILE_INFORMATION hfinfo
;
1503 time_t lastmodified
;
1506 TRACE(reg
,"(void)\n");
1508 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1509 if (hf
==HFILE_ERROR32
)
1512 /* read & dump header */
1513 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1514 ERR(reg
, "reg.dat is too short.\n");
1518 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1519 ERR(reg
, "reg.dat has bad signature.\n");
1524 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1525 /* read and dump index table */
1527 if (len
!=_lread32(hf
,tab
,len
)) {
1528 ERR(reg
,"couldn't read %d bytes.\n",len
);
1535 txt
= xmalloc(head
.textsize
);
1536 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1537 ERR(reg
,"couldn't seek to textblock.\n");
1543 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1544 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1551 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1552 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1558 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1559 lpkey
= lookup_hkey(HKEY_CLASSES_ROOT
);
1560 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1568 /**********************************************************************************
1569 * SHELL_LoadRegistry [Internal]
1571 void SHELL_LoadRegistry( void )
1578 TRACE(reg
,"(void)\n");
1580 /* Load windows 3.1 entries */
1582 /* Load windows 95 entries */
1583 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE
));
1584 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE
));
1585 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS
));
1587 /* the global user default is loaded under HKEY_USERS\\.Default */
1588 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1589 lpkey
= lookup_hkey(hkey
);
1591 WARN(reg
,"Could not create global user default key\n");
1592 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1594 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1595 _copy_registry(lpkey
,lookup_hkey(HKEY_CURRENT_USER
));
1598 /* the global machine defaults */
1599 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),SAVE_LOCAL_MACHINE_DEFAULT
,0);
1601 /* load the user saved registries */
1603 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1605 pwd
=getpwuid(getuid());
1606 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1607 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1608 strcpy(fn
,pwd
->pw_dir
);
1609 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1610 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER
),fn
,REG_OPTION_TAINTED
);
1612 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1613 strcpy(fn
,pwd
->pw_dir
);
1614 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1615 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE
),fn
,REG_OPTION_TAINTED
);
1618 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1619 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1620 DWORD junk
,type
,len
;
1624 if (( RegQueryValueEx32A(
1631 )!=ERROR_SUCCESS
) ||
1634 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1640 /********************* API FUNCTIONS ***************************************/
1644 * All functions are stubs to RegOpenKeyEx32W where all the
1647 * FIXME: security,options,desiredaccess,...
1650 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1651 * RegOpenKey32W -> RegOpenKeyEx32W
1655 /******************************************************************************
1656 * RegOpenKeyEx32W [ADVAPI32.150]
1657 * Opens the specified key
1659 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1662 * hkey [I] Handle of open key
1663 * lpszSubKey [I] Name of subkey to open
1664 * dwReserved [I] Reserved - must be zero
1665 * samDesired [I] Security access mask
1666 * retkey [O] Address of handle of open key
1669 * Success: ERROR_SUCCESS
1670 * Failure: Error code
1672 DWORD WINAPI
RegOpenKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
, DWORD dwReserved
,
1673 REGSAM samDesired
, LPHKEY retkey
)
1675 LPKEYSTRUCT lpNextKey
,lpxkey
;
1679 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n", hkey
,debugstr_w(lpszSubKey
),dwReserved
,
1682 lpNextKey
= lookup_hkey(hkey
);
1684 WARN(reg
,"Invalid handle: %x\n",hkey
);
1685 return ERROR_INVALID_HANDLE
;
1688 if (!lpszSubKey
|| !*lpszSubKey
) {
1689 /* Either NULL or pointer to empty string, so return a new handle
1690 to the original hkey */
1691 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1692 *retkey
=currenthandle
;
1693 return ERROR_SUCCESS
;
1696 split_keypath(lpszSubKey
,&wps
,&wpc
);
1698 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1702 lpxkey
=lpNextKey
->nextsub
;
1704 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
)) {
1707 lpxkey
=lpxkey
->next
;
1711 TRACE(reg
,"Could not find subkey %s\n",debugstr_w(wps
[i
]));
1713 return ERROR_BADKEY
;
1719 add_handle(++currenthandle
,lpxkey
,samDesired
);
1720 *retkey
= currenthandle
;
1721 TRACE(reg
," Returning %x\n", currenthandle
);
1723 return ERROR_SUCCESS
;
1727 /******************************************************************************
1728 * RegOpenKey32W [ADVAPI32.151]
1730 DWORD WINAPI
RegOpenKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1732 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_w(lpszSubKey
),retkey
);
1733 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1737 /******************************************************************************
1738 * RegOpenKeyEx32A [ADVAPI32.149]
1740 DWORD WINAPI
RegOpenKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1741 REGSAM samDesired
, LPHKEY retkey
)
1743 LPWSTR lpszSubKeyW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey
);
1746 TRACE(reg
,"(%x,%s,%ld,%lx,%p)\n",hkey
,debugstr_a(lpszSubKey
),dwReserved
,
1749 ret
= RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1750 HeapFree(GetProcessHeap(),0,lpszSubKeyW
);
1755 /******************************************************************************
1756 * RegOpenKey32A [ADVAPI32.148]
1758 DWORD WINAPI
RegOpenKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1760 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1761 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1765 /******************************************************************************
1766 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1768 DWORD WINAPI
RegOpenKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1770 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1771 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1778 * All those functions convert their respective
1779 * arguments and call RegCreateKeyExW at the end.
1781 * FIXME: no security,no access attrib,no optionhandling yet.
1784 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1785 * RegCreateKey32W -> RegCreateKeyEx32W
1789 /******************************************************************************
1790 * RegCreateKeyEx32W [ADVAPI32.131]
1794 * retkey [O] Address of buffer for opened handle
1795 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1797 DWORD WINAPI
RegCreateKeyEx32W( HKEY hkey
, LPCWSTR lpszSubKey
,
1798 DWORD dwReserved
, LPWSTR lpszClass
,
1799 DWORD fdwOptions
, REGSAM samDesired
,
1800 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1801 LPHKEY retkey
, LPDWORD lpDispos
)
1803 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1807 /*FIXME: handle security/access/whatever */
1809 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey
,
1810 debugstr_w(lpszSubKey
), dwReserved
, debugstr_w(lpszClass
),
1811 fdwOptions
, samDesired
, lpSecAttribs
, retkey
, lpDispos
);
1813 lpNextKey
= lookup_hkey(hkey
);
1815 return ERROR_BADKEY
;
1817 if (!lpszSubKey
|| !*lpszSubKey
) {
1818 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1819 *retkey
=currenthandle
;
1820 TRACE(reg
, "Returning %x\n", currenthandle
);
1821 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1822 return ERROR_SUCCESS
;
1825 if (lpszSubKey
[0] == '\\') {
1826 WARN(reg
,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey
));
1827 return ERROR_BAD_PATHNAME
;
1830 split_keypath(lpszSubKey
,&wps
,&wpc
);
1832 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1835 lpxkey
=lpNextKey
->nextsub
;
1837 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1839 lpxkey
=lpxkey
->next
;
1847 add_handle(++currenthandle
,lpxkey
,samDesired
);
1848 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1849 *retkey
= currenthandle
;
1850 TRACE(reg
, "Returning %x\n", currenthandle
);
1852 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1854 return ERROR_SUCCESS
;
1857 /* Good. Now the hard part */
1859 lplpPrevKey
= &(lpNextKey
->nextsub
);
1860 lpxkey
= *lplpPrevKey
;
1862 lplpPrevKey
= &(lpxkey
->next
);
1863 lpxkey
= *lplpPrevKey
;
1865 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1866 if (!*lplpPrevKey
) {
1868 TRACE(reg
, "Returning OUTOFMEMORY\n");
1869 return ERROR_OUTOFMEMORY
;
1871 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1872 TRACE(reg
,"Adding %s\n", debugstr_w(wps
[i
]));
1873 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1874 (*lplpPrevKey
)->next
= NULL
;
1875 (*lplpPrevKey
)->nextsub
= NULL
;
1876 (*lplpPrevKey
)->values
= NULL
;
1877 (*lplpPrevKey
)->nrofvalues
= 0;
1878 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1880 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1882 (*lplpPrevKey
)->class = NULL
;
1883 lpNextKey
= *lplpPrevKey
;
1886 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1888 /*FIXME: flag handling correct? */
1889 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1891 lpNextKey
->class = strdupW(lpszClass
);
1893 lpNextKey
->class = NULL
;
1894 *retkey
= currenthandle
;
1895 TRACE(reg
, "Returning %x\n", currenthandle
);
1897 *lpDispos
= REG_CREATED_NEW_KEY
;
1899 return ERROR_SUCCESS
;
1903 /******************************************************************************
1904 * RegCreateKey32W [ADVAPI32.132]
1906 DWORD WINAPI
RegCreateKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPHKEY retkey
)
1910 TRACE(reg
,"(%x,%s,%p)\n", hkey
,debugstr_w(lpszSubKey
),retkey
);
1911 return RegCreateKeyEx32W( hkey
, lpszSubKey
, 0, NULL
,
1912 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
,NULL
,
1917 /******************************************************************************
1918 * RegCreateKeyEx32A [ADVAPI32.130]
1920 DWORD WINAPI
RegCreateKeyEx32A( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwReserved
,
1921 LPSTR lpszClass
, DWORD fdwOptions
,
1923 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1924 LPHKEY retkey
, LPDWORD lpDispos
)
1926 LPWSTR lpszSubKeyW
, lpszClassW
;
1929 TRACE(reg
,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey
,debugstr_a(lpszSubKey
),
1930 dwReserved
,debugstr_a(lpszClass
),fdwOptions
,samDesired
,lpSecAttribs
,
1933 lpszSubKeyW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey
);
1936 lpszSubKeyW=strdupA2W(lpszSubKey);
1941 lpszClassW
=strdupA2W(lpszClass
);
1944 ret
= RegCreateKeyEx32W( hkey
, lpszSubKeyW
, dwReserved
, lpszClassW
,
1945 fdwOptions
, samDesired
, lpSecAttribs
, retkey
,
1947 HeapFree(GetProcessHeap(),0,lpszSubKeyW
);
1958 /******************************************************************************
1959 * RegCreateKey32A [ADVAPI32.129]
1961 DWORD WINAPI
RegCreateKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1965 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1967 return RegCreateKeyEx32A(
1968 hkey
, /* key handle */
1969 lpszSubKey
, /* subkey name */
1970 0, /* reserved = 0 */
1971 NULL
, /* lpszClass? FIXME: ? */
1972 REG_OPTION_NON_VOLATILE
,/* options */
1973 KEY_ALL_ACCESS
, /* desired access attribs */
1974 NULL
, /* lpsecurity attributes */
1975 retkey
, /* lpretkey */
1976 &junk
/* disposition value */
1981 /******************************************************************************
1982 * RegCreateKey16 [SHELL.2] [KERNEL.218]
1984 DWORD WINAPI
RegCreateKey16( HKEY hkey
, LPCSTR lpszSubKey
, LPHKEY retkey
)
1986 TRACE(reg
,"(%x,%s,%p)\n",hkey
,debugstr_a(lpszSubKey
),retkey
);
1987 return RegCreateKey32A( hkey
, lpszSubKey
, retkey
);
1992 * Query Value Functions
1993 * Win32 differs between keynames and valuenames.
1994 * multiple values may belong to one key, the special value
1995 * with name NULL is the default value used by the win31
1999 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2000 * RegQueryValue32W -> RegQueryValueEx32W
2004 /******************************************************************************
2005 * RegQueryValueEx32W [ADVAPI32.158]
2006 * Retrieves type and data for a specified name associated with an open key
2009 * hkey [I] Handle of key to query
2010 * lpValueName [I] Name of value to query
2011 * lpdwReserved [I] Reserved - must be NULL
2012 * lpdwType [O] Address of buffer for value type. If NULL, the type
2014 * lpbData [O] Address of data buffer. If NULL, the actual data is
2016 * lpcbData [I/O] Address of data buffer size
2019 * ERROR_SUCCESS: Success
2020 * ERROR_MORE_DATA: The specified buffer is not big enough to hold the data
2022 DWORD WINAPI
RegQueryValueEx32W( HKEY hkey
, LPWSTR lpValueName
,
2023 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2024 LPBYTE lpbData
, LPDWORD lpcbData
)
2029 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
, debugstr_w(lpValueName
),
2030 lpdwReserved
, lpdwType
, lpbData
, lpcbData
?*lpcbData
:0);
2032 lpkey
= lookup_hkey(hkey
);
2034 TRACE(reg
, "Invalid handle(%x)\n",hkey
);
2035 return ERROR_INVALID_HANDLE
;
2038 /* An empty name string is equivalent to NULL */
2039 if (lpValueName
&& !*lpValueName
)
2042 if (lpValueName
==NULL
) {
2043 /* Use key's unnamed or default value, if any */
2044 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2045 if (lpkey
->values
[i
].name
==NULL
)
2048 /* Search for the key name */
2049 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2050 if ( lpkey
->values
[i
].name
&&
2051 !lstrcmpi32W(lpValueName
,lpkey
->values
[i
].name
)
2056 if (i
==lpkey
->nrofvalues
) {
2057 TRACE(reg
,"Key not found\n");
2058 if (lpValueName
==NULL
) {
2059 /* Empty keyname not found */
2061 *(WCHAR
*)lpbData
= 0;
2066 TRACE(reg
, "Returning an empty string\n");
2067 return ERROR_SUCCESS
;
2069 return ERROR_BADKEY
; /* FIXME */
2073 *lpdwType
= lpkey
->values
[i
].type
;
2075 if (lpbData
==NULL
) {
2076 /* Data is not required */
2077 if (lpcbData
==NULL
) {
2078 /* And data size is not required */
2079 /* So all that is returned is the type (set above) */
2080 return ERROR_SUCCESS
;
2082 /* Set the size required and return success */
2083 *lpcbData
= lpkey
->values
[i
].len
;
2084 return ERROR_SUCCESS
;
2087 if (*lpcbData
<lpkey
->values
[i
].len
) {
2088 /* The size was specified, but the data is too big for it */
2089 /* Instead of setting it to NULL, fill in with as much as possible */
2090 /* But the docs do not specify how to handle the lpbData here */
2091 /* *(WCHAR*)lpbData= 0; */
2092 memcpy(lpbData
,lpkey
->values
[i
].data
,*lpcbData
);
2093 *lpcbData
= lpkey
->values
[i
].len
;
2094 return ERROR_MORE_DATA
;
2097 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2099 /* Extra debugging output */
2103 TRACE(reg
," Data(sz)=%s\n",debugstr_w((LPCWSTR
)lpbData
));
2106 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)*lpbData
);
2109 TRACE(reg
," Data(binary)\n");
2110 /* Is there a way of printing this in readable form? */
2113 TRACE(reg
, "Unknown data type %ld\n", *lpdwType
);
2117 /* Set the actual size */
2118 *lpcbData
= lpkey
->values
[i
].len
;
2119 return ERROR_SUCCESS
;
2123 /******************************************************************************
2124 * RegQueryValue32W [ADVAPI32.159]
2127 * Why is this calling RegOpenKey32W?
2129 DWORD WINAPI
RegQueryValue32W( HKEY hkey
, LPWSTR lpszSubKey
, LPWSTR lpszData
,
2135 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_w(lpszSubKey
),lpszData
,
2136 lpcbData
?*lpcbData
:0);
2138 /* only open subkey, if we really do descend */
2139 if (lpszSubKey
&& *lpszSubKey
) {
2140 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
2141 if (ret
!=ERROR_SUCCESS
)
2147 ret
= RegQueryValueEx32W(
2149 NULL
, /* varname NULL -> compat */
2150 NULL
, /* lpdwReserved, must be NULL */
2161 /******************************************************************************
2162 * RegQueryValueEx32A [ADVAPI32.157]
2164 * Can this use HEAP_strdupAtoW?
2166 DWORD WINAPI
RegQueryValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2167 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2168 LPBYTE lpbData
, LPDWORD lpcbData
)
2170 LPWSTR lpszValueNameW
;
2176 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n", hkey
,debugstr_a(lpszValueName
),
2177 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2180 lpszValueNameW
=strdupA2W(lpszValueName
);
2182 lpszValueNameW
=NULL
;
2191 /* Only get the size for now */
2192 ret
=RegQueryValueEx32W(
2201 if (ret
==ERROR_MORE_DATA
) {
2202 buf
= (LPBYTE
)xmalloc(*mylen
);
2204 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2205 myxlen
= 2*(*lpcbData
);
2210 myxlen
= *lpcbData
*2;
2215 /* Now get the data */
2216 ret
=RegQueryValueEx32W(
2227 if (ret
==ERROR_SUCCESS
) {
2229 if (UNICONVMASK
& (1<<(type
))) {
2230 /* convert UNICODE to ASCII */
2231 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2232 *lpcbData
= myxlen
/2;
2234 if (myxlen
>*lpcbData
)
2235 ret
= ERROR_MORE_DATA
;
2237 memcpy(lpbData
,buf
,myxlen
);
2242 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2243 *lpcbData
= myxlen
/2;
2246 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2247 *lpcbData
= myxlen
/2;
2256 /******************************************************************************
2257 * RegQueryValueEx16 [KERNEL.225]
2259 DWORD WINAPI
RegQueryValueEx16( HKEY hkey
, LPSTR lpszValueName
,
2260 LPDWORD lpdwReserved
, LPDWORD lpdwType
,
2261 LPBYTE lpbData
, LPDWORD lpcbData
)
2263 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2264 lpdwReserved
,lpdwType
,lpbData
,lpcbData
?*lpcbData
:0);
2265 return RegQueryValueEx32A( hkey
, lpszValueName
, lpdwReserved
, lpdwType
,
2266 lpbData
, lpcbData
);
2270 /******************************************************************************
2271 * RegQueryValue32A [ADVAPI32.156]
2274 * Why is this calling RegOpenKey16?
2276 DWORD WINAPI
RegQueryValue32A(
2285 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2286 lpcbData
?*lpcbData
:0);
2288 /* only open subkey, if we really do descend */
2289 if (lpszSubKey
&& *lpszSubKey
) {
2290 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
2291 if (ret
!=ERROR_SUCCESS
)
2297 ret
= RegQueryValueEx32A(
2299 NULL
, /* lpszValueName NULL -> compat */
2300 NULL
, /* lpdwReserved, must be NULL */
2311 /******************************************************************************
2312 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2315 * Is this HACK still applicable?
2318 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2319 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2322 DWORD WINAPI
RegQueryValue16( HKEY hkey
, LPSTR lpszSubKey
, LPSTR lpszData
,
2325 TRACE(reg
,"(%x,%s,%p,%ld)\n",hkey
,debugstr_a(lpszSubKey
),lpszData
,
2326 lpcbData
?*lpcbData
:0);
2329 *lpcbData
&= 0xFFFF;
2330 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2335 * Setting values of Registry keys
2338 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2339 * RegSetValue32W -> RegSetValueEx32W
2343 /******************************************************************************
2344 * RegSetValueEx32W [ADVAPI32.170]
2345 * Sets the data and type of a value under a register key
2348 * hkey [I] Handle of key to set value for
2349 * lpszValueName [I] Name of value to set
2350 * dwReserved [I] Reserved - must be zero
2351 * dwType [I] Flag for value type
2352 * lpbData [I] Address of value data
2353 * cbData [I] Size of value data
2356 * Success: ERROR_SUCCESS
2357 * Failure: Error code
2359 DWORD WINAPI
RegSetValueEx32W( HKEY hkey
, LPWSTR lpszValueName
,
2360 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2366 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey
, debugstr_w(lpszValueName
),
2367 dwReserved
, dwType
, lpbData
, cbData
);
2371 TRACE(reg
," Data(sz)=%s\n", debugstr_w((LPCWSTR
)lpbData
));
2374 TRACE(reg
," Data(binary)\n");
2377 TRACE(reg
," Data(dword)=%lx\n", (DWORD
)lpbData
);
2380 TRACE(reg
,"Unknown type: %ld\n", dwType
);
2383 lpkey
= lookup_hkey(hkey
);
2385 WARN(reg
,"Returning badkey\n");
2386 return ERROR_INVALID_HANDLE
;
2389 lpkey
->flags
|= REG_OPTION_TAINTED
;
2391 if (lpszValueName
==NULL
) {
2392 /* Sets type and name for key's unnamed or default value */
2393 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2394 if (lpkey
->values
[i
].name
==NULL
)
2397 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2398 if ( lpkey
->values
[i
].name
&&
2399 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2403 if (i
==lpkey
->nrofvalues
) {
2404 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2406 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2408 lpkey
->nrofvalues
++;
2409 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2411 if (lpkey
->values
[i
].name
==NULL
)
2413 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2415 lpkey
->values
[i
].name
= NULL
;
2416 lpkey
->values
[i
].len
= cbData
;
2417 lpkey
->values
[i
].type
= dwType
;
2418 if (lpkey
->values
[i
].data
!=NULL
)
2419 free(lpkey
->values
[i
].data
);
2420 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2421 lpkey
->values
[i
].lastmodified
= time(NULL
);
2422 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2423 return ERROR_SUCCESS
;
2427 /******************************************************************************
2428 * RegSetValueEx32A [ADVAPI32.169]
2431 * Can this use the standard HEAP_strdupAtoW instead?
2433 DWORD WINAPI
RegSetValueEx32A( HKEY hkey
, LPSTR lpszValueName
,
2434 DWORD dwReserved
, DWORD dwType
, LPBYTE lpbData
,
2438 LPWSTR lpszValueNameW
;
2441 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2442 dwReserved
,dwType
,lpbData
,cbData
);
2444 if ((1<<dwType
) & UNICONVMASK
) {
2445 buf
=(LPBYTE
)strdupA2W(lpbData
);
2446 cbData
=2*strlen(lpbData
)+2;
2450 lpszValueNameW
= strdupA2W(lpszValueName
);
2452 lpszValueNameW
= NULL
;
2453 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2455 free(lpszValueNameW
);
2462 /******************************************************************************
2463 * RegSetValueEx16 [KERNEL.226]
2465 DWORD WINAPI
RegSetValueEx16( HKEY hkey
, LPSTR lpszValueName
, DWORD dwReserved
,
2466 DWORD dwType
, LPBYTE lpbData
, DWORD cbData
)
2468 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey
,debugstr_a(lpszValueName
),
2469 dwReserved
,dwType
,lpbData
,cbData
);
2470 return RegSetValueEx32A( hkey
, lpszValueName
, dwReserved
, dwType
, lpbData
,
2475 /******************************************************************************
2476 * RegSetValue32W [ADVAPI32.171]
2478 DWORD WINAPI
RegSetValue32W(
2488 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2489 hkey
,debugstr_w(lpszSubKey
),dwType
,debugstr_w(lpszData
),cbData
2491 if (lpszSubKey
&& *lpszSubKey
) {
2492 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2493 if (ret
!=ERROR_SUCCESS
)
2497 if (dwType
!=REG_SZ
) {
2498 TRACE(reg
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2501 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2502 TRACE(reg
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2503 cbData
,debugstr_w(lpszData
),2*lstrlen32W(lpszData
)+2
2505 cbData
=2*lstrlen32W(lpszData
)+2;
2507 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2514 /******************************************************************************
2515 * RegSetValue32A [ADVAPI32.168]
2518 * Why is this calling RegCreateKey16?
2520 DWORD WINAPI
RegSetValue32A(
2530 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2531 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2533 if (lpszSubKey
&& *lpszSubKey
) {
2534 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2535 if (ret
!=ERROR_SUCCESS
)
2540 if (dwType
!=REG_SZ
) {
2541 TRACE(reg
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2544 if (cbData
!=strlen(lpszData
)+1)
2545 cbData
=strlen(lpszData
)+1;
2546 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2553 /******************************************************************************
2554 * RegSetValue16 [KERNEL.221] [SHELL.5]
2556 DWORD WINAPI
RegSetValue16( HKEY hkey
, LPCSTR lpszSubKey
, DWORD dwType
,
2557 LPCSTR lpszData
, DWORD cbData
)
2559 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",hkey
,debugstr_a(lpszSubKey
),dwType
,
2560 debugstr_a(lpszData
),cbData
);
2561 return RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2569 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2570 * RegEnumKey32W -> RegEnumKeyEx32W
2574 /******************************************************************************
2575 * RegEnumKeyEx32W [ADVAPI32.139]
2577 DWORD WINAPI
RegEnumKeyEx32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2578 LPDWORD lpcchName
, LPDWORD lpdwReserved
,
2579 LPWSTR lpszClass
, LPDWORD lpcchClass
,
2582 LPKEYSTRUCT lpkey
,lpxkey
;
2584 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey
,iSubkey
,lpszName
,
2585 *lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
);
2587 lpkey
= lookup_hkey(hkey
);
2589 return ERROR_INVALID_HANDLE
;
2591 if (!lpkey
->nextsub
)
2592 return ERROR_NO_MORE_ITEMS
;
2593 lpxkey
=lpkey
->nextsub
;
2594 while (iSubkey
&& lpxkey
) {
2596 lpxkey
=lpxkey
->next
;
2598 if (iSubkey
|| !lpxkey
)
2599 return ERROR_NO_MORE_ITEMS
;
2600 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2601 return ERROR_MORE_DATA
;
2602 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2604 /* what should we write into it? */
2608 return ERROR_SUCCESS
;
2612 /******************************************************************************
2613 * RegEnumKey32W [ADVAPI32.140]
2615 DWORD WINAPI
RegEnumKey32W( HKEY hkey
, DWORD iSubkey
, LPWSTR lpszName
,
2620 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2621 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2625 /* RegEnumKeyExA [ADVAPI32.138] */
2626 DWORD WINAPI
RegEnumKeyEx32A(
2631 LPDWORD lpdwReserved
,
2636 DWORD ret
,lpcchNameW
,lpcchClassW
;
2637 LPWSTR lpszNameW
,lpszClassW
;
2640 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2641 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2644 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2645 lpcchNameW
= *lpcchName
*2;
2651 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2652 lpcchClassW
= *lpcchClass
*2;
2657 ret
=RegEnumKeyEx32W(
2667 if (ret
==ERROR_SUCCESS
) {
2668 lstrcpyWtoA(lpszName
,lpszNameW
);
2669 *lpcchName
=strlen(lpszName
);
2671 lstrcpyWtoA(lpszClass
,lpszClassW
);
2672 *lpcchClass
=strlen(lpszClass
);
2683 /******************************************************************************
2684 * RegEnumKey32A [ADVAPI32.137]
2686 DWORD WINAPI
RegEnumKey32A( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2691 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2692 return RegEnumKeyEx32A( hkey
, iSubkey
, lpszName
, &lpcchName
, NULL
, NULL
,
2697 /******************************************************************************
2698 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2700 DWORD WINAPI
RegEnumKey16( HKEY hkey
, DWORD iSubkey
, LPSTR lpszName
,
2703 TRACE(reg
,"(%x,%ld,%p,%ld)\n",hkey
,iSubkey
,lpszName
,lpcchName
);
2704 return RegEnumKey32A( hkey
, iSubkey
, lpszName
, lpcchName
);
2709 * Enumerate Registry Values
2712 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2716 /******************************************************************************
2717 * RegEnumValue32W [ADVAPI32.142]
2719 DWORD WINAPI
RegEnumValue32W(
2724 LPDWORD lpdReserved
,
2732 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2733 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2735 lpkey
= lookup_hkey(hkey
);
2737 return ERROR_INVALID_HANDLE
;
2739 if (lpkey
->nrofvalues
<=iValue
)
2740 return ERROR_NO_MORE_ITEMS
;
2741 val
= lpkey
->values
+iValue
;
2744 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2745 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2746 return ERROR_MORE_DATA
;
2748 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2749 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2755 *lpdwType
=val
->type
;
2757 if (val
->len
>*lpcbData
)
2758 return ERROR_MORE_DATA
;
2759 memcpy(lpbData
,val
->data
,val
->len
);
2760 *lpcbData
= val
->len
;
2762 return ERROR_SUCCESS
;
2766 /* RegEnumValueA [ADVAPI32.141] */
2767 DWORD WINAPI
RegEnumValue32A(
2772 LPDWORD lpdReserved
,
2779 DWORD ret
,lpcbDataW
;
2781 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2782 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2785 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2787 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2788 lpcbDataW
= *lpcbData
*2;
2791 ret
=RegEnumValue32W(
2802 if (ret
==ERROR_SUCCESS
) {
2803 lstrcpyWtoA(lpszValue
,lpszValueW
);
2805 if ((1<<*lpdwType
) & UNICONVMASK
) {
2806 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2808 if (lpcbDataW
> *lpcbData
)
2809 ret
= ERROR_MORE_DATA
;
2811 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2813 *lpcbData
= lpcbDataW
;
2824 /******************************************************************************
2825 * RegEnumValue16 [KERNEL.223]
2827 DWORD WINAPI
RegEnumValue16( HKEY hkey
, DWORD iValue
, LPSTR lpszValue
,
2828 LPDWORD lpcchValue
, LPDWORD lpdReserved
,
2829 LPDWORD lpdwType
, LPBYTE lpbData
,
2832 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey
,iValue
,lpszValue
,lpcchValue
,
2833 lpdReserved
,lpdwType
,lpbData
,lpcbData
);
2834 return RegEnumValue32A( hkey
, iValue
, lpszValue
, lpcchValue
, lpdReserved
,
2835 lpdwType
, lpbData
, lpcbData
);
2839 /******************************************************************************
2840 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2841 * Releases the handle of the specified key
2844 * hkey [I] Handle of key to close
2847 * Success: ERROR_SUCCESS
2848 * Failure: Error code
2850 DWORD WINAPI
RegCloseKey( HKEY hkey
)
2852 TRACE(reg
,"(%x)\n",hkey
);
2853 return remove_handle(hkey
);
2858 * Delete registry key
2861 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2865 /******************************************************************************
2866 * RegDeleteKey32W [ADVAPI32.134]
2873 * Success: ERROR_SUCCESS
2874 * Failure: Error code
2876 DWORD WINAPI
RegDeleteKey32W( HKEY hkey
, LPWSTR lpszSubKey
)
2878 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2882 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszSubKey
));
2884 lpNextKey
= lookup_hkey(hkey
);
2886 TRACE(reg
, " Invalid handle.\n");
2887 return ERROR_INVALID_HANDLE
;
2890 /* we need to know the previous key in the hier. */
2891 if (!lpszSubKey
|| !*lpszSubKey
) {
2892 TRACE(reg
, " Badkey[2].\n");
2893 return ERROR_BADKEY
;
2895 split_keypath(lpszSubKey
,&wps
,&wpc
);
2899 lpxkey
=lpNextKey
->nextsub
;
2901 TRACE(reg
, " Scanning [%s]\n",
2902 debugstr_w(lpxkey
->keyname
));
2903 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2905 lpxkey
=lpxkey
->next
;
2909 TRACE(reg
, " Not found.\n");
2910 /* not found is success */
2911 return ERROR_SUCCESS
;
2916 lpxkey
= lpNextKey
->nextsub
;
2917 lplpPrevKey
= &(lpNextKey
->nextsub
);
2919 TRACE(reg
, " Scanning [%s]\n",
2920 debugstr_w(lpxkey
->keyname
));
2921 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2923 lplpPrevKey
= &(lpxkey
->next
);
2924 lpxkey
= lpxkey
->next
;
2929 WARN(reg
, " Not found.\n");
2930 return ERROR_FILE_NOT_FOUND
;
2933 if (lpxkey
->nextsub
) {
2935 WARN(reg
, " Not empty.\n");
2936 return ERROR_CANTWRITE
;
2938 *lplpPrevKey
= lpxkey
->next
;
2939 free(lpxkey
->keyname
);
2941 free(lpxkey
->class);
2943 free(lpxkey
->values
);
2946 TRACE(reg
, " Done.\n");
2947 return ERROR_SUCCESS
;
2951 /******************************************************************************
2952 * RegDeleteKey32A [ADVAPI32.133]
2954 DWORD WINAPI
RegDeleteKey32A( HKEY hkey
, LPCSTR lpszSubKey
)
2959 TRACE(reg
,"(%x,%s)\n",hkey
,lpszSubKey
);
2960 lpszSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpszSubKey
);
2961 ret
= RegDeleteKey32W( hkey
, lpszSubKeyW
);
2962 HeapFree( GetProcessHeap(), 0, lpszSubKeyW
);
2967 /******************************************************************************
2968 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
2970 DWORD WINAPI
RegDeleteKey16( HKEY hkey
, LPCSTR lpszSubKey
)
2972 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_a(lpszSubKey
));
2973 return RegDeleteKey32A( hkey
, lpszSubKey
);
2978 * Delete registry value
2981 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2985 /******************************************************************************
2986 * RegDeleteValue32W [ADVAPI32.136]
2994 DWORD WINAPI
RegDeleteValue32W( HKEY hkey
, LPWSTR lpszValue
)
3000 TRACE(reg
,"(%x,%s)\n",hkey
,debugstr_w(lpszValue
));
3002 lpkey
= lookup_hkey(hkey
);
3004 return ERROR_INVALID_HANDLE
;
3007 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3008 if ( lpkey
->values
[i
].name
&&
3009 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
3013 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
3014 if (lpkey
->values
[i
].name
==NULL
)
3018 if (i
== lpkey
->nrofvalues
)
3019 return ERROR_FILE_NOT_FOUND
;
3021 val
= lpkey
->values
+i
;
3022 if (val
->name
) free(val
->name
);
3023 if (val
->data
) free(val
->data
);
3027 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
3029 lpkey
->values
= (LPKEYVALUE
)xrealloc(
3031 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
3033 lpkey
->nrofvalues
--;
3034 return ERROR_SUCCESS
;
3038 /******************************************************************************
3039 * RegDeleteValue32A [ADVAPI32.135]
3041 DWORD WINAPI
RegDeleteValue32A( HKEY hkey
, LPSTR lpszValue
)
3046 TRACE(reg
, "(%x,%s)\n",hkey
,debugstr_a(lpszValue
));
3047 lpszValueW
=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue
);
3048 ret
= RegDeleteValue32W( hkey
, lpszValueW
);
3049 HeapFree(GetProcessHeap(),0,lpszValueW
);
3054 /******************************************************************************
3055 * RegDeleteValue16 [KERNEL.222]
3057 DWORD WINAPI
RegDeleteValue16( HKEY hkey
, LPSTR lpszValue
)
3059 TRACE(reg
,"(%x,%s)\n", hkey
,debugstr_a(lpszValue
));
3060 return RegDeleteValue32A(hkey
,lpszValue
);
3064 /******************************************************************************
3065 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3066 * Writes key to registry
3069 * hkey [I] Handle of key to write
3072 * Success: ERROR_SUCCESS
3073 * Failure: Error code
3075 DWORD WINAPI
RegFlushKey( HKEY hkey
)
3077 FIXME(reg
, "(%x): stub\n", hkey
);
3078 return ERROR_SUCCESS
;
3082 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3084 /******************************************************************************
3085 * RegQueryInfoKey32W [ADVAPI32.153]
3087 DWORD WINAPI
RegQueryInfoKey32W(
3091 LPDWORD lpdwReserved
,
3093 LPDWORD lpcchMaxSubkey
,
3094 LPDWORD lpcchMaxClass
,
3096 LPDWORD lpcchMaxValueName
,
3097 LPDWORD lpccbMaxValueData
,
3098 LPDWORD lpcbSecurityDescriptor
,
3101 LPKEYSTRUCT lpkey
,lpxkey
;
3102 int nrofkeys
,maxsubkey
,maxclass
,maxvname
,maxvdata
;
3105 TRACE(reg
,"(%x,......)\n",hkey
);
3106 lpkey
= lookup_hkey(hkey
);
3108 return ERROR_INVALID_HANDLE
;
3111 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
3112 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3113 return ERROR_MORE_DATA
;
3115 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
3116 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
3123 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
3125 lpxkey
=lpkey
->nextsub
;
3126 nrofkeys
=maxsubkey
=maxclass
=maxvname
=maxvdata
=0;
3129 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
3130 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
3131 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
3132 maxclass
=lstrlen32W(lpxkey
->class);
3133 lpxkey
=lpxkey
->next
;
3135 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
3136 LPKEYVALUE val
=lpkey
->values
+i
;
3138 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
3139 maxvname
=lstrlen32W(val
->name
);
3140 if (val
->len
>maxvdata
)
3143 if (!maxclass
) maxclass
= 1;
3144 if (!maxvname
) maxvname
= 1;
3146 *lpcValues
= lpkey
->nrofvalues
;
3148 *lpcSubKeys
= nrofkeys
;
3150 *lpcchMaxSubkey
= maxsubkey
*2;
3152 *lpcchMaxClass
= maxclass
*2;
3153 if (lpcchMaxValueName
)
3154 *lpcchMaxValueName
= maxvname
;
3155 if (lpccbMaxValueData
)
3156 *lpccbMaxValueData
= maxvdata
;
3157 return ERROR_SUCCESS
;
3161 /* RegQueryInfoKeyA [ADVAPI32.152] */
3162 DWORD WINAPI
RegQueryInfoKey32A(
3166 LPDWORD lpdwReserved
,
3168 LPDWORD lpcchMaxSubkey
,
3169 LPDWORD lpcchMaxClass
,
3171 LPDWORD lpcchMaxValueName
,
3172 LPDWORD lpccbMaxValueData
,
3173 LPDWORD lpcbSecurityDescriptor
,
3179 TRACE(reg
,"(%x,......)\n",hkey
);
3182 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
3186 ret
=RegQueryInfoKey32W(
3197 lpcbSecurityDescriptor
,
3200 if (ret
==ERROR_SUCCESS
&& lpszClass
)
3201 lstrcpyWtoA(lpszClass
,lpszClassW
);
3208 if (lpcchMaxValueName
)
3209 *lpcchMaxValueName
/=2;
3216 /******************************************************************************
3217 * RegConnectRegistry32W [ADVAPI32.128]
3219 LONG WINAPI
RegConnectRegistry32W( LPCWSTR machine
, HKEY hkey
, LPHKEY reskey
)
3221 FIXME(reg
,"(%s,%x,%p): stub\n",debugstr_w(machine
),hkey
,reskey
);
3222 return ERROR_BAD_NETPATH
; /* FIXME */
3226 /******************************************************************************
3227 * RegConnectRegistry32A [ADVAPI32.127]
3229 LONG WINAPI
RegConnectRegistry32A( LPCSTR machine
, HKEY hkey
, LPHKEY reskey
)
3232 LPWSTR machineW
= HEAP_strdupAtoW(GetProcessHeap(),0,machine
);
3233 ret
= RegConnectRegistry32W( machineW
, hkey
, reskey
);
3234 HeapFree(GetProcessHeap(),0,machineW
);
3239 /******************************************************************************
3240 * RegGetKeySecurity [ADVAPI32.144]
3241 * Retrieves a copy of security descriptor protecting the registry key
3244 * Success: ERROR_SUCCESS
3245 * Failure: Error code
3247 LONG WINAPI
RegGetKeySecurity( HKEY hkey
,
3248 SECURITY_INFORMATION SecurityInformation
,
3249 LPSECURITY_DESCRIPTOR pSecurityDescriptor
,
3250 LPDWORD lpcbSecurityDescriptor
)
3253 lpkey
= lookup_hkey(hkey
);
3255 return ERROR_INVALID_HANDLE
;
3257 FIXME(reg
, "(%d,%ld,%p,%p): stub\n", hkey
, SecurityInformation
,
3258 pSecurityDescriptor
, lpcbSecurityDescriptor
);
3259 return ERROR_SUCCESS
;
3263 /******************************************************************************
3264 * RegLoadKey32W [ADVAPI32.???]
3266 LONG WINAPI
RegLoadKey32W( HKEY hkey
, LPCWSTR lpszSubKey
, LPCWSTR lpszFile
)
3268 FIXME(reg
,"(%x,%s,%s): stub\n",hkey
,debugstr_w(lpszSubKey
),
3269 debugstr_w(lpszFile
));
3270 return ERROR_SUCCESS
;
3274 /******************************************************************************
3275 * RegLoadKey32A [ADVAPI32.???]
3277 LONG WINAPI
RegLoadKey32A( HKEY hkey
, LPCSTR lpszSubKey
, LPCSTR lpszFile
)
3280 LPWSTR lpszSubKeyW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey
);
3281 LPWSTR lpszFileW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpszFile
);
3282 ret
= RegLoadKey32W( hkey
, lpszSubKeyW
, lpszFileW
);
3283 HeapFree(GetProcessHeap(),0,lpszFileW
);
3284 HeapFree(GetProcessHeap(),0,lpszSubKeyW
);
3289 /******************************************************************************
3290 * RegNotifyChangeKeyValue [ADVAPI32.???]
3292 LONG WINAPI
RegNotifyChangeKeyValue( HKEY hkey
, BOOL32 fWatchSubTree
,
3293 DWORD fdwNotifyFilter
, HANDLE32 hEvent
,
3296 FIXME(reg
,"(%x,%i,%ld,%d,%i): stub\n",hkey
,fWatchSubTree
,fdwNotifyFilter
,
3298 return ERROR_SUCCESS
;
3302 /******************************************************************************
3303 * RegUnLoadKey32W [ADVAPI32.173]
3305 LONG WINAPI
RegUnLoadKey32W( HKEY hkey
, LPCWSTR lpSubKey
)
3307 FIXME(reg
,"(%x,%s): stub\n",hkey
, debugstr_w(lpSubKey
));
3308 return ERROR_SUCCESS
;
3312 /******************************************************************************
3313 * RegUnLoadKey32A [ADVAPI32.172]
3315 LONG WINAPI
RegUnLoadKey32A( HKEY hkey
, LPCSTR lpSubKey
)
3318 LPWSTR lpSubKeyW
= HEAP_strdupAtoW( GetProcessHeap(), 0, lpSubKey
);
3319 ret
= RegUnLoadKey32W( hkey
, lpSubKeyW
);
3320 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);
3325 /******************************************************************************
3326 * RegSetKeySecurity [ADVAPI32.167]
3328 LONG WINAPI
RegSetKeySecurity( HKEY hkey
, SECURITY_INFORMATION SecurityInfo
,
3329 LPSECURITY_DESCRIPTOR pSecurityDesc
)
3331 FIXME(reg
, "%x,%ld,%p): stub\n", hkey
, SecurityInfo
, pSecurityDesc
);
3332 return ERROR_SUCCESS
;
3336 /******************************************************************************
3337 * RegSaveKey32W [ADVAPI32.166]
3339 LONG WINAPI
RegSaveKey32W( HKEY hkey
, LPCWSTR lpFile
,
3340 LPSECURITY_ATTRIBUTES sa
)
3342 FIXME(reg
, "%x,%s,%p): stub\n", hkey
, debugstr_w(lpFile
), sa
);
3343 return ERROR_SUCCESS
;
3347 /******************************************************************************
3348 * RegSaveKey32A [ADVAPI32.165]
3350 LONG WINAPI
RegSaveKey32A( HKEY hkey
, LPCSTR lpFile
,
3351 LPSECURITY_ATTRIBUTES sa
)
3354 LPWSTR lpFileW
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpFile
);
3355 ret
= RegSaveKey32W( hkey
, lpFileW
, sa
);
3356 HeapFree( GetProcessHeap(), 0, lpFileW
);
3361 /******************************************************************************
3362 * RegRestoreKey32W [ADVAPI32.164]
3364 LONG WINAPI
RegRestoreKey32W( HKEY hkey
, LPCWSTR lpFile
, DWORD dwFlags
)
3366 FIXME(reg
, "%x,%s,%ld): stub\n", hkey
, debugstr_w(lpFile
), dwFlags
);
3367 return ERROR_SUCCESS
;
3371 /******************************************************************************
3372 * RegRestoreKey32A [ADVAPI32.163]
3374 LONG WINAPI
RegRestoreKey32A( HKEY hkey
, LPCSTR lpFile
, DWORD dwFlags
)
3377 LPWSTR lpFileW
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpFile
);
3378 ret
= RegRestoreKey32W( hkey
, lpFileW
, dwFlags
);
3379 HeapFree( GetProcessHeap(), 0, lpFileW
);
3384 /******************************************************************************
3385 * RegReplaceKey32W [ADVAPI32.162]
3387 LONG WINAPI
RegReplaceKey32W( HKEY hkey
, LPCWSTR lpSubKey
, LPCWSTR lpNewFile
,
3390 FIXME(reg
, "%x,%s,%s,%s): stub\n", hkey
, debugstr_w(lpSubKey
),
3391 debugstr_w(lpNewFile
),debugstr_w(lpOldFile
));
3392 return ERROR_SUCCESS
;
3396 /******************************************************************************
3397 * RegReplaceKey32A [ADVAPI32.161]
3399 LONG WINAPI
RegReplaceKey32A( HKEY hkey
, LPCSTR lpSubKey
, LPCSTR lpNewFile
,
3403 LPWSTR lpSubKeyW
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpSubKey
);
3404 LPWSTR lpNewFileW
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpNewFile
);
3405 LPWSTR lpOldFileW
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpOldFile
);
3406 ret
= RegReplaceKey32W( hkey
, lpSubKeyW
, lpNewFileW
, lpOldFileW
);
3407 HeapFree( GetProcessHeap(), 0, lpOldFileW
);
3408 HeapFree( GetProcessHeap(), 0, lpNewFileW
);
3409 HeapFree( GetProcessHeap(), 0, lpSubKeyW
);