4 * Copyright 1996 Marcus Meissner
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
29 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
31 /* FIXME: following defines should be configured global ... */
33 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
34 #define WINE_PREFIX "/.wine"
35 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
36 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
38 /* relative in ~user/.wine/ : */
39 #define SAVE_CURRENT_USER "user.reg"
40 #define SAVE_LOCAL_MACHINE "system.reg"
42 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
43 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
45 /* one value of a key */
46 typedef struct tagKEYVALUE
48 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
49 DWORD type
; /* type of value */
50 DWORD len
; /* length of data */
51 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
52 LPBYTE data
; /* content, may be strings, binaries, etc. */
53 } KEYVALUE
,*LPKEYVALUE
;
56 typedef struct tagKEYSTRUCT
58 LPWSTR keyname
; /* name of THIS key (UNICODE) */
59 DWORD flags
; /* flags. */
62 DWORD nrofvalues
; /* nr of values in THIS key */
63 LPKEYVALUE values
; /* values in THIS key */
64 /* key management pointers */
65 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
66 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
67 } KEYSTRUCT
, *LPKEYSTRUCT
;
70 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
71 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
72 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
73 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
75 /* dynamic, not saved */
76 static KEYSTRUCT
*key_performance_data
=NULL
;
77 static KEYSTRUCT
*key_current_config
=NULL
;
78 static KEYSTRUCT
*key_dyn_data
=NULL
;
80 /* what valuetypes do we need to convert? */
81 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
83 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
84 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
85 #define strdupW(x) STRING32_strdupW(x)
86 #define strcmpniW(a,b) STRING32_lstrcmpniW(a,b)
87 #define strchrW(a,c) STRING32_lstrchrW(a,c)
88 #define strcpyWA(a,b) STRING32_UniToAnsi(a,b)
90 static struct openhandle
{
95 static int nrofopenhandles
=0;
96 static int currenthandle
=1;
99 add_handle(HKEY hkey
,LPKEYSTRUCT lpkey
,REGSAM accessmask
) {
102 for (i
=0;i
<nrofopenhandles
;i
++) {
103 if (openhandles
[i
].lpkey
==lpkey
) {
104 dprintf_reg(stddeb
,"add_handle:Tried to add %p twice!\n",lpkey
);
106 if (openhandles
[i
].hkey
==hkey
) {
107 dprintf_reg(stddeb
,"add_handle:Tried to add %lx twice!\n",(LONG
)hkey
);
110 openhandles
=xrealloc( openhandles
,
111 sizeof(struct openhandle
)*(nrofopenhandles
+1)
113 openhandles
[i
].lpkey
= lpkey
;
114 openhandles
[i
].hkey
= hkey
;
115 openhandles
[i
].accessmask
= accessmask
;
120 get_handle(HKEY hkey
) {
123 for (i
=0;i
<nrofopenhandles
;i
++)
124 if (openhandles
[i
].hkey
==hkey
)
125 return openhandles
[i
].lpkey
;
126 dprintf_reg(stddeb
,"get_handle:Didn't find handle %lx?\n",(LONG
)hkey
);
131 remove_handle(HKEY hkey
) {
134 for (i
=0;i
<nrofopenhandles
;i
++)
135 if (openhandles
[i
].hkey
==hkey
)
137 if (i
==nrofopenhandles
) {
138 dprintf_reg(stddeb
,"remove_handle:Didn't find handle %08x?\n",hkey
);
141 memcpy( openhandles
+i
,
143 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
145 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
151 /* debug function, converts a unicode into a static memory area
152 * (sub for using two static strings, in case we need them in a single call)
155 W2C(LPCWSTR x
,int sub
) {
156 static LPSTR unicodedebug
[2]={NULL
,NULL
};
159 if (sub
!=0 && sub
!=1)
160 return "<W2C:bad sub>";
161 if (unicodedebug
[sub
]) free(unicodedebug
[sub
]);
162 unicodedebug
[sub
] = strdupW2A(x
);
163 return unicodedebug
[sub
];
167 lookup_hkey(HKEY hkey
) {
171 case HKEY_CLASSES_ROOT
:
172 return key_classes_root
;
173 case HKEY_CURRENT_USER
:
174 return key_current_user
;
175 case HKEY_LOCAL_MACHINE
:
176 return key_local_machine
;
179 case HKEY_PERFORMANCE_DATA
:
180 return key_performance_data
;
183 case HKEY_CURRENT_CONFIG
:
184 return key_current_config
;
186 dprintf_reg(stddeb
,"lookup_hkey(%lx), special key!\n",
189 return get_handle(hkey
);
195 * splits the unicode string 'wp' into an array of strings.
196 * the array is allocated by this function.
197 * the number of components will be stored in 'wpc'
198 * Free the array using FREE_KEY_PATH
201 split_keypath(LPCWSTR wp
,LPWSTR
**wpv
,int *wpc
) {
207 for (i
=0;ws
[i
];i
++) {
214 *wpv
= (LPWSTR
*)xmalloc(sizeof(LPWSTR
)*(*wpc
+2));
222 #define FREE_KEY_PATH free(wps[0]);free(wps);
225 * Shell initialisation, allocates keys.
227 void SHELL_StartupRegistry();
232 HKEY cl_r_hkey
,c_u_hkey
;
233 #define ADD_ROOT_KEY(xx) \
234 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
235 memset(xx,'\0',sizeof(KEYSTRUCT));\
236 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
238 ADD_ROOT_KEY(key_local_machine
);
239 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
240 fprintf(stderr
,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
243 key_classes_root
= lookup_hkey(cl_r_hkey
);
245 ADD_ROOT_KEY(key_users
);
248 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
249 * (later, when a win32 registry editing tool becomes avail.)
251 while (pwd
=getpwent()) {
252 if (pwd
->pw_name
== NULL
)
254 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
255 RegCloseKey(c_u_hkey
);
258 pwd
=getpwuid(getuid());
259 if (pwd
&& pwd
->pw_name
) {
260 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
261 key_current_user
= lookup_hkey(c_u_hkey
);
263 ADD_ROOT_KEY(key_current_user
);
265 ADD_ROOT_KEY(key_performance_data
);
266 ADD_ROOT_KEY(key_current_config
);
267 ADD_ROOT_KEY(key_dyn_data
);
269 SHELL_StartupRegistry();
274 SHELL_StartupRegistry() {
277 char buf
[200],cpubuf
[200];
279 RegCreateKey16(HKEY_DYN_DATA
,"\\PerfStats\\StatData",&xhkey
);
281 RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey
);
283 F
=fopen("/proc/cpuinfo","r");
286 while (NULL
!=fgets(buf
,200,F
)) {
287 if (sscanf(buf
,"processor\t: %d",&x
)) {
292 RegCreateKey16(hkey
,buf
,&xhkey
);
294 if (sscanf(buf
,"cpu\t\t: %s",cpubuf
)) {
295 sprintf(buf
,"CPU %s",cpubuf
);
297 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,buf
,strlen(buf
));
307 RegCreateKey16(hkey
,"0",&xhkey
);
308 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,"CPU 386",strlen("CPU 386"));
310 RegOpenKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System",&hkey
);
311 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
313 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
317 * string RegisteredOwner
318 * string RegisteredOrganization
321 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
326 if (-1!=gethostname(buf
,200)) {
327 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey
);
328 RegSetValueEx16(xhkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
332 /************************ SAVE Registry Function ****************************/
334 #define REGISTRY_SAVE_VERSION 0x00000001
336 /* Registry saveformat:
337 * If you change it, increase above number by 1, which will flush
338 * old registry database files.
341 * "WINE REGISTRY Version %d"
345 * valuename=lastmodified,type,data
349 * keyname,valuename,stringdata:
350 * the usual ascii characters from 0x00-0xff (well, not 0x00)
351 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
352 * ( "=\\\t" escaped in \uXXXX form.)
356 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
358 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
359 * SaveOnlyUpdatedKeys=yes
362 _save_check_tainted(LPKEYSTRUCT lpkey
) {
367 if (lpkey
->flags
& REG_OPTION_TAINTED
)
372 if (_save_check_tainted(lpkey
->nextsub
)) {
373 lpkey
->flags
|= REG_OPTION_TAINTED
;
382 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
395 if (escapeeq
&& *s
=='=')
398 fputc(*s
,F
); /* if \\ than put it twice. */
400 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
408 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
414 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
415 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
417 for (tabs
=level
;tabs
--;)
419 _save_USTRING(F
,lpxkey
->keyname
,1);
421 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
422 LPKEYVALUE val
=lpxkey
->values
+i
;
424 for (tabs
=level
+1;tabs
--;)
426 _save_USTRING(F
,val
->name
,0);
428 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
429 if ((1<<val
->type
) & UNICONVMASK
)
430 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
432 for (j
=0;j
<val
->len
;j
++)
433 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
436 /* descend recursively */
437 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
446 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
447 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
448 _save_check_tainted(lpkey
->nextsub
);
449 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
453 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
458 fprintf(stddeb
,__FILE__
":_savereg:Couldn't open %s for writing: %s\n",
463 if (!_savesubreg(F
,lpkey
,all
)) {
466 fprintf(stddeb
,__FILE__
":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
473 SHELL_SaveRegistry() {
481 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
487 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
499 if (lstrcmpi32A(buf
,"yes"))
501 pwd
=getpwuid(getuid());
502 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
503 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_USERS_DEFAULT
)+2);
504 strcpy(fn
,pwd
->pw_dir
);
505 strcat(fn
,WINE_PREFIX
);
506 /* create the directory. don't care about errorcodes. */
507 mkdir(fn
,0755); /* drwxr-xr-x */
508 strcat(fn
,"/"SAVE_CURRENT_USER
);
509 _savereg(key_current_user
,fn
,all
);
511 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
512 strcpy(fn
,pwd
->pw_dir
);
513 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
514 _savereg(key_local_machine
,fn
,all
);
517 fprintf(stderr
,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
520 /************************ LOAD Registry Function ****************************/
523 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
524 LPKEYSTRUCT lpxkey
,*lplpkey
;
526 lplpkey
= &(lpkey
->nextsub
);
529 if (!lstrcmp32W(lpxkey
->keyname
,keyname
))
531 lplpkey
= &(lpxkey
->next
);
535 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
537 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
538 lpxkey
->keyname
= keyname
;
546 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
552 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
558 if ( val
->name
!=NULL
&&
559 !lstrcmp32W(val
->name
,name
)
564 if (i
==lpkey
->nrofvalues
) {
565 lpkey
->values
= xrealloc(
567 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
570 memset(val
,'\0',sizeof(KEYVALUE
));
576 if (val
->lastmodified
<lastmodified
) {
577 val
->lastmodified
=lastmodified
;
588 /* reads a line including dynamically enlarging the readbuffer and throwing
592 _wine_read_line(FILE *F
,char **buf
,int *len
) {
601 s
=fgets(curread
,mylen
,F
);
604 if (NULL
==(s
=strchr(curread
,'\n'))) {
605 /* buffer wasn't large enough */
606 curoff
= strlen(*buf
);
607 *buf
= xrealloc(*buf
,*len
*2);
608 curread
= *buf
+ curoff
;
609 mylen
= *len
; /* we filled up the buffer and
610 * got new '*len' bytes to fill
618 /* throw away comments */
619 if (**buf
=='#' || **buf
==';') {
624 if (s
) /* got end of line */
630 /* converts a char* into a UNICODE string (up to a special char)
631 * and returns the position exactly after that string
634 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
638 /* read up to "=" or "\0" or "\n" */
641 /* empty string is the win3.1 default value(NULL)*/
645 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
647 while (*s
&& (*s
!='\n') && (*s
!='=')) {
649 *ws
++=*((unsigned char*)s
++);
658 fprintf(stderr
,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
666 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
667 if (!sscanf(xbuf
,"%x",&wc
))
668 fprintf(stderr
,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf
,buf
);
670 *ws
++ =(unsigned short)wc
;
676 *str
= strdupW(*str
);
683 FILE *F
,LPKEYSTRUCT lpkey
,int level
,char **buf
,int *buflen
,int optflag
690 lpkey
->flags
|= optflag
;
692 /* good. we already got a line here ... so parse it */
702 fprintf(stderr
,"_load_subkey:Got a subhierarchy without resp. key?\n");
705 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
708 /* let the caller handle this line */
709 if (i
<level
|| **buf
=='\0')
712 /* it can be: a value or a keyname. Parse the name first */
713 s
=_wine_read_USTRING(s
,&name
);
715 /* switch() default: hack to avoid gotos */
719 lpxkey
=_find_or_add_key(lpkey
,name
);
722 int len
,lastmodified
,type
;
725 fprintf(stderr
,"_wine_load_subkey:unexpected character: %c\n",*s
);
729 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
730 fprintf(stderr
,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf
);
736 if ((1<<type
) & UNICONVMASK
) {
737 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
739 len
= lstrlen32W((LPWSTR
)data
)*2+2;
744 data
= (LPBYTE
)xmalloc(len
+1);
745 for (i
=0;i
<len
;i
++) {
747 if (*s
>='0' && *s
<='9')
749 if (*s
>='a' && *s
<='f')
751 if (*s
>='A' && *s
<='F')
754 if (*s
>='0' && *s
<='9')
756 if (*s
>='a' && *s
<='f')
758 if (*s
>='A' && *s
<='F')
763 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
766 /* read the next line */
767 if (!_wine_read_line(F
,buf
,buflen
))
774 _wine_loadsubreg(FILE *F
,LPKEYSTRUCT lpkey
,int optflag
) {
779 buf
=xmalloc(10);buflen
=10;
780 if (!_wine_read_line(F
,&buf
,&buflen
)) {
784 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
788 if (ver
!=REGISTRY_SAVE_VERSION
) {
789 dprintf_reg(stddeb
,__FILE__
":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
793 if (!_wine_read_line(F
,&buf
,&buflen
)) {
797 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
806 _wine_loadreg(LPKEYSTRUCT lpkey
,char *fn
,int optflag
) {
811 dprintf_reg(stddeb
,__FILE__
":Couldn't open %s for reading: %s\n",
816 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
825 _copy_registry(LPKEYSTRUCT from
,LPKEYSTRUCT to
) {
832 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
834 for (j
=0;j
<from
->nrofvalues
;j
++) {
838 valfrom
= from
->values
+j
;
840 if (name
) name
=strdupW(name
);
841 data
=(LPBYTE
)malloc(valfrom
->len
);
842 memcpy(data
,valfrom
->data
,valfrom
->len
);
850 valfrom
->lastmodified
853 _copy_registry(from
,lpxkey
);
858 /* WINDOWS 95 REGISTRY LOADER */
860 * Structure of a win95 registry database.
864 * 8 : DWORD offset_of_RGDB_part
865 * 0C..1F: ? (someone fill in please)
870 * 4..0x1B: ? (fill in)
871 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
873 * Disk Key Entry Structure:
874 * 00: DWORD - unknown
875 * 04: DWORD - unknown
876 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
877 * 0C: DWORD - disk address of PreviousLevel Key.
878 * 10: DWORD - disk address of Next Sublevel Key.
879 * 14: DWORD - disk address of Next Key (on same level).
880 * DKEP>18: WORD - Nr, Low Significant part.
881 * 1A: WORD - Nr, High Significant part.
883 * The disk address always points to the nr part of the previous key entry
884 * of the referenced key. Don't ask me why, or even if I got this correct
885 * from staring at 1kg of hexdumps. (DKEP)
887 * The number of the entry is the low byte of the Low Significant Part ored
888 * with 0x100 * (low byte of the High Significant part)
889 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
891 * There are two minor corrections to the position of that structure.
892 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
893 * the DKE reread from there.
894 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
895 * (FIXME: slightly better explanation needed here)
899 * 04: DWORD offset to next RGDB section (perhaps WORD)
904 * 00: DWORD nextkeyoffset - offset to the next disk key structure
905 * 08: WORD nrLS - low significant part of NR
906 * 0A: WORD nrHS - high significant part of NR
907 * 0C: DWORD bytesused - bytes used in this structure.
908 * 10: WORD name_len - length of name in bytes. without \0
909 * 12: WORD nr_of_values - number of values.
910 * 14: char name[name_len] - name string. No \0.
911 * 14+name_len: disk values
912 * nextkeyoffset: ... next disk key
915 * 00: DWORD type - value type (hmm, could be WORD too)
916 * 04: DWORD - unknown, usually 0
917 * 08: WORD namelen - length of Name. 0 means name=NULL
918 * 0C: WORD datalen - length of Data.
919 * 10: char name[namelen] - name, no \0
920 * 10+namelen: BYTE data[datalen] - data, without \0 if string
921 * 10+namelen+datalen: next values or disk key
923 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
924 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
925 * structure) and reading another RGDB_section.
926 * repeat until end of file.
928 * FIXME: this description needs some serious help, yes.
931 struct _w95keyvalue
{
933 unsigned short datalen
;
943 struct _w95keyvalue
*values
;
944 unsigned long dkeaddr
;
949 struct _w95key
*prevlvl
;
950 struct _w95key
*nextsub
;
951 struct _w95key
*next
;
954 /* fast lookup table dkeaddr->nr */
956 unsigned long dkeaddr
;
962 _w95_walk_tree(LPKEYSTRUCT lpkey
,struct _w95key
*key
) {
968 if (key
->name
== NULL
) {
969 fprintf(stderr
,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
974 lpxkey
=_find_or_add_key(lpkey
,strdupA2W(key
->name
));
976 if (key
->nrofvals
<0) {
977 /* shouldn't happen */
978 fprintf(stderr
,"key %s already processed!\n",key
->name
);
982 for (i
=0;i
<key
->nrofvals
;i
++) {
986 name
= strdupA2W(key
->values
[i
].name
);
987 if (!*name
) name
= NULL
;
988 free(key
->values
[i
].name
);
990 len
= key
->values
[i
].datalen
;
991 data
= key
->values
[i
].data
;
992 if ((1<<key
->values
[i
].type
) & UNICONVMASK
) {
993 data
= (BYTE
*)strdupA2W(data
);
994 len
= lstrlen32W((LPWSTR
)data
)*2+2;
995 free(key
->values
[i
].data
);
1000 key
->values
[i
].type
,
1003 key
->values
[i
].lastmodified
1010 key
->nrofvals
=-key
->nrofvals
-1;
1011 _w95_walk_tree(lpxkey
,key
->nextsub
);
1016 /* small helper function to adjust address offset (dkeaddrs) */
1017 static unsigned long
1018 _w95_adj_da(unsigned long dkeaddr
) {
1019 if ((dkeaddr
&0xFFF)<0x018) {
1022 diff
=0x1C-(dkeaddr
&0xFFF);
1023 return dkeaddr
+diff
;
1025 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1026 /* readjust to 0x000,
1027 * but ONLY if we are >0x1000 already
1029 if (dkeaddr
& ~0xFFF)
1030 return dkeaddr
& ~0xFFF;
1036 _w95dkecomp(struct _w95nr2da
*a
,struct _w95nr2da
*b
){return a
->dkeaddr
-b
->dkeaddr
;}
1038 static struct _w95key
*
1039 _w95dkelookup(unsigned long dkeaddr
,int n
,struct _w95nr2da
*nr2da
,struct _w95key
*keys
) {
1042 if (dkeaddr
== 0xFFFFFFFF)
1046 dkeaddr
=_w95_adj_da(dkeaddr
+0x1c);
1047 off
= (dkeaddr
-0x3c)/0x1c;
1049 if (nr2da
[(i
+off
)%n
].dkeaddr
== dkeaddr
)
1050 return keys
+nr2da
[(i
+off
)%n
].nr
;
1051 /* 0x3C happens often, just report unusual values */
1053 dprintf_reg(stddeb
,"search hasn't found dkeaddr %lx?\n",dkeaddr
);
1057 extern time_t FileTimeToUnixTime(FILETIME
*);
1060 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1061 /* Disk Key Entry structure (RGKN part) */
1065 unsigned long x3
;/*usually 0xFFFFFFFF */
1066 unsigned long prevlvl
;
1067 unsigned long nextsub
;
1069 unsigned short nrLS
;
1070 unsigned short nrMS
;
1072 /* Disk Key Header structure (RGDB part) */
1074 unsigned long nextkeyoff
;
1075 unsigned short nrLS
;
1076 unsigned short nrMS
;
1077 unsigned long bytesused
;
1078 unsigned short keynamelen
;
1079 unsigned short values
;
1082 /* disk key values or nothing */
1084 /* Disk Key Value structure */
1088 unsigned short valnamelen
;
1089 unsigned short valdatalen
;
1090 /* valname, valdata */
1092 struct _w95nr2da
*nr2da
;
1097 unsigned long nr
,pos
,i
,where
,version
,rgdbsection
,end
,off_next_rgdb
;
1098 struct _w95key
*keys
;
1100 unsigned char *data
,*curdata
,*nextrgdb
;
1102 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1104 dprintf_reg(stddeb
,"Loading Win95 registry database '%s'\n",fn
);
1105 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1106 if (hfd
==HFILE_ERROR
)
1109 if (4!=_lread32(hfd
,magic
,4))
1111 if (strcmp(magic
,"CREG")) {
1112 fprintf(stddeb
,"%s is not a w95 registry.\n",fn
);
1115 if (4!=_lread32(hfd
,&version
,4))
1117 if (4!=_lread32(hfd
,&rgdbsection
,4))
1119 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1121 if (4!=_lread32(hfd
,magic
,4))
1123 if (strcmp(magic
,"RGKN")) {
1124 dprintf_reg(stddeb
,"second IFF header not RGKN, but %s\n",magic
);
1128 /* STEP 1: Keylink structures */
1129 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1134 nrofdkes
= (end
-where
)/sizeof(struct dke
)+100;
1135 data
= (char*)xmalloc(end
-where
);
1136 if ((end
-where
)!=_lread32(hfd
,data
,end
-where
))
1140 keys
= (struct _w95key
*)xmalloc(nrofdkes
* sizeof(struct _w95key
));
1141 memset(keys
,'\0',nrofdkes
*sizeof(struct _w95key
));
1142 nr2da
= (struct _w95nr2da
*)xmalloc(nrofdkes
* sizeof(struct _w95nr2da
));
1143 memset(nr2da
,'\0',nrofdkes
*sizeof(struct _w95nr2da
));
1145 for (i
=0;i
<nrofdkes
;i
++) {
1147 unsigned long dkeaddr
;
1149 pos
=curdata
-data
+0x40;
1150 memcpy(&dke
,curdata
,sizeof(dke
));
1151 curdata
+=sizeof(dke
);
1152 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1154 if ((dkeaddr
&0xFFF)<0x018) {
1157 diff
=0x1C-(dkeaddr
&0xFFF);
1159 curdata
+=diff
-sizeof(dke
);
1160 memcpy(&dke
,curdata
,sizeof(dke
));
1161 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1162 curdata
+=sizeof(dke
);
1164 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1165 /* readjust to 0x000,
1166 * but ONLY if we are >0x1000 already
1168 if (dkeaddr
& ~0xFFF)
1169 dkeaddr
= dkeaddr
& ~0xFFF;
1172 /* 0xFFFFFFFF happens often, just report unusual values */
1174 dprintf_reg(stddeb
,"nr %ld exceeds nrofdkes %d, skipping.\n",nr
,nrofdkes
);
1177 if (keys
[nr
].dkeaddr
) {
1180 for (x
=sizeof(dke
);x
--;)
1181 if (((char*)&dke
)[x
])
1184 break; /* finished reading if we got only 0 */
1186 if ( (dke
.next
!=(long)keys
[nr
].next
) ||
1187 (dke
.nextsub
!=(long)keys
[nr
].nextsub
) ||
1188 (dke
.prevlvl
!=(long)keys
[nr
].prevlvl
)
1190 dprintf_reg(stddeb
,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr
,keys
[nr
].dkeaddr
,dkeaddr
);
1195 nr2da
[i
].dkeaddr
= dkeaddr
;
1197 keys
[nr
].dkeaddr
= dkeaddr
;
1198 keys
[nr
].x1
= dke
.x1
;
1199 keys
[nr
].x2
= dke
.x2
;
1200 keys
[nr
].x3
= dke
.x3
;
1201 keys
[nr
].prevlvl
= (struct _w95key
*)dke
.prevlvl
;
1202 keys
[nr
].nextsub
= (struct _w95key
*)dke
.nextsub
;
1203 keys
[nr
].next
= (struct _w95key
*)dke
.next
;
1207 qsort(nr2da
,nrofdkes
,sizeof(nr2da
[0]),
1208 (int(*)(const void *,const void*))_w95dkecomp
);
1210 /* STEP 2: keydata & values */
1211 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1213 end
= hfdinfo
.nFileSizeLow
;
1214 lastmodified
= FileTimeToUnixTime(&(hfdinfo
.ftLastWriteTime
));
1216 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1218 data
= (char*)xmalloc(end
-rgdbsection
);
1219 if ((end
-rgdbsection
)!=_lread32(hfd
,data
,end
-rgdbsection
))
1223 memcpy(magic
,curdata
,4);
1224 memcpy(&off_next_rgdb
,curdata
+4,4);
1225 nextrgdb
= curdata
+off_next_rgdb
;
1226 if (strcmp(magic
,"RGDB")) {
1227 dprintf_reg(stddeb
,"third IFF header not RGDB, but %s\n",magic
);
1234 struct _w95key
*key
,xkey
;
1237 if (curdata
>=nextrgdb
) {
1239 if (!strncmp(curdata
,"RGDB",4)) {
1240 memcpy(&off_next_rgdb
,curdata
+4,4);
1241 nextrgdb
= curdata
+off_next_rgdb
;
1244 dprintf_reg(stddeb
,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata
-data
,end
-rgdbsection
);
1248 #define XREAD(whereto,len) \
1249 if ((curdata-data+len)<end) {\
1250 memcpy(whereto,curdata,len);\
1255 XREAD(&dkh
,sizeof(dkh
));
1256 nr
= dkh
.nrLS
+ (dkh
.nrMS
<<8);
1257 if ((nr
>nrofdkes
) || (dkh
.nrLS
== 0xFFFF)) {
1258 if (dkh
.nrLS
== 0xFFFF) {
1259 /* skip over key using nextkeyoff */
1260 curdata
+=dkh
.nextkeyoff
-sizeof(struct dkh
);
1263 dprintf_reg(stddeb
,"haven't found nr %ld.\n",nr
);
1265 memset(key
,'\0',sizeof(xkey
));
1269 dprintf_reg(stddeb
,"key with nr=%ld has no dkeaddr?\n",nr
);
1271 key
->nrofvals
= dkh
.values
;
1272 key
->name
= (char*)xmalloc(dkh
.keynamelen
+1);
1274 XREAD(key
->name
,dkh
.keynamelen
);
1275 key
->name
[dkh
.keynamelen
]=0;
1276 if (key
->nrofvals
) {
1277 key
->values
= (struct _w95keyvalue
*)xmalloc(
1278 sizeof(struct _w95keyvalue
)*key
->nrofvals
1280 for (i
=0;i
<key
->nrofvals
;i
++) {
1283 XREAD(&dkv
,sizeof(dkv
));
1284 key
->values
[i
].type
= dkv
.type
;
1285 key
->values
[i
].name
= (char*)xmalloc(
1288 key
->values
[i
].datalen
= dkv
.valdatalen
;
1289 key
->values
[i
].data
= (unsigned char*)xmalloc(
1292 key
->values
[i
].x1
= dkv
.x1
;
1293 XREAD(key
->values
[i
].name
,dkv
.valnamelen
);
1294 XREAD(key
->values
[i
].data
,dkv
.valdatalen
);
1295 key
->values
[i
].data
[dkv
.valdatalen
]=0;
1296 key
->values
[i
].name
[dkv
.valnamelen
]=0;
1297 key
->values
[i
].lastmodified
=lastmodified
;
1300 if (bytesread
!= dkh
.nextkeyoff
) {
1301 if (dkh
.bytesused
!= bytesread
)
1303 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread
,dkh
.nextkeyoff
,
1306 curdata
+= dkh
.nextkeyoff
-bytesread
;
1308 key
->prevlvl
= _w95dkelookup((long)key
->prevlvl
,nrofdkes
,nr2da
,keys
);
1309 key
->nextsub
= _w95dkelookup((long)key
->nextsub
,nrofdkes
,nr2da
,keys
);
1310 key
->next
= _w95dkelookup((long)key
->next
,nrofdkes
,nr2da
,keys
);
1315 _w95_walk_tree(lpkey
,keys
);
1320 SHELL_LoadRegistry() {
1327 if (key_classes_root
==NULL
)
1330 /* Load windows 95 entries */
1331 _w95_loadreg("C:\\system.1st", key_local_machine
);
1332 _w95_loadreg("system.dat", key_local_machine
);
1333 _w95_loadreg("user.dat", key_users
);
1335 /* FIXME: win3.1 reg.dat loader still missing */
1337 /* the global user default is loaded under HKEY_USERS\\.Default */
1338 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1339 lpkey
= lookup_hkey(hkey
);
1340 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1342 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1343 _copy_registry(lpkey
,key_current_user
);
1346 /* the global machine defaults */
1347 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1349 /* load the user saved registries */
1351 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1353 pwd
=getpwuid(getuid());
1354 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1355 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1356 strcpy(fn
,pwd
->pw_dir
);
1357 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1358 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1360 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1361 strcpy(fn
,pwd
->pw_dir
);
1362 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1363 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1366 fprintf(stderr
,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1367 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1368 DWORD junk
,type
,len
;
1372 if (( RegQueryValueEx32A(
1379 )!=ERROR_SUCCESS
) ||
1382 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1388 /********************* API FUNCTIONS ***************************************/
1392 * All functions are stubs to RegOpenKeyEx32W where all the
1395 * FIXME: security,options,desiredaccess,...
1398 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1399 * RegOpenKey32W -> RegOpenKeyEx32W
1402 /* RegOpenKeyExW [ADVAPI32.150] */
1403 DWORD
RegOpenKeyEx32W(
1410 LPKEYSTRUCT lpNextKey
,lpxkey
;
1413 dprintf_reg(stddeb
,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1414 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1417 lpNextKey
= lookup_hkey(hkey
);
1419 return SHELL_ERROR_BADKEY
;
1420 if (!lpszSubKey
|| !*lpszSubKey
) {
1421 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1422 *retkey
=currenthandle
;
1423 return SHELL_ERROR_SUCCESS
;
1425 split_keypath(lpszSubKey
,&wps
,&wpc
);
1427 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1430 lpxkey
=lpNextKey
->nextsub
;
1432 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1434 lpxkey
=lpxkey
->next
;
1438 return SHELL_ERROR_BADKEY
;
1443 add_handle(++currenthandle
,lpxkey
,samDesired
);
1444 *retkey
= currenthandle
;
1446 return SHELL_ERROR_SUCCESS
;
1449 /* RegOpenKeyW [ADVAPI32.151] */
1450 DWORD
RegOpenKey32W(
1455 dprintf_reg(stddeb
,"RegOpenKey32W(%lx,%s,%p)\n",
1456 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1458 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1462 /* RegOpenKeyExA [ADVAPI32.149] */
1463 DWORD
RegOpenKeyEx32A(
1473 dprintf_reg(stddeb
,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1474 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1477 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1480 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1486 /* RegOpenKeyA [ADVAPI32.148] */
1487 DWORD
RegOpenKey32A(
1492 dprintf_reg(stddeb
,"RegOpenKey32A(%lx,%s,%p)\n",
1493 (LONG
)hkey
,lpszSubKey
,retkey
1495 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1498 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1504 dprintf_reg(stddeb
,"RegOpenKey16(%lx,%s,%p)\n",
1505 (LONG
)hkey
,lpszSubKey
,retkey
1507 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1513 * All those functions convert their respective
1514 * arguments and call RegCreateKeyExW at the end.
1516 * FIXME: no security,no access attrib,no optionhandling yet.
1519 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1520 * RegCreateKey32W -> RegCreateKeyEx32W
1523 /* RegCreateKeyExW [ADVAPI32.131] */
1524 DWORD
RegCreateKeyEx32W(
1531 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1535 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1539 /*FIXME: handle security/access/whatever */
1540 dprintf_reg(stddeb
,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1552 lpNextKey
= lookup_hkey(hkey
);
1554 return SHELL_ERROR_BADKEY
;
1555 if (!lpszSubKey
|| !*lpszSubKey
) {
1556 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1557 *retkey
=currenthandle
;
1558 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1559 return SHELL_ERROR_SUCCESS
;
1561 split_keypath(lpszSubKey
,&wps
,&wpc
);
1563 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1566 lpxkey
=lpNextKey
->nextsub
;
1568 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1570 lpxkey
=lpxkey
->next
;
1578 add_handle(++currenthandle
,lpxkey
,samDesired
);
1579 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1580 *retkey
= currenthandle
;
1582 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1584 return SHELL_ERROR_SUCCESS
;
1586 /* good. now the hard part */
1588 lplpPrevKey
= &(lpNextKey
->nextsub
);
1589 lpxkey
= *lplpPrevKey
;
1591 lplpPrevKey
= &(lpxkey
->next
);
1592 lpxkey
= *lplpPrevKey
;
1594 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1595 if (!*lplpPrevKey
) {
1597 return SHELL_ERROR_OUTOFMEMORY
;
1599 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1600 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1601 (*lplpPrevKey
)->next
= NULL
;
1602 (*lplpPrevKey
)->nextsub
= NULL
;
1603 (*lplpPrevKey
)->values
= NULL
;
1604 (*lplpPrevKey
)->nrofvalues
= 0;
1605 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1607 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1609 (*lplpPrevKey
)->class = NULL
;
1610 lpNextKey
= *lplpPrevKey
;
1613 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1615 /*FIXME: flag handling correct? */
1616 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1618 lpNextKey
->class = strdupW(lpszClass
);
1620 lpNextKey
->class = NULL
;
1621 *retkey
= currenthandle
;
1623 *lpDispos
= REG_CREATED_NEW_KEY
;
1625 return SHELL_ERROR_SUCCESS
;
1628 /* RegCreateKeyW [ADVAPI32.132] */
1629 DWORD
RegCreateKey32W(
1636 dprintf_reg(stddeb
,"RegCreateKey32W(%lx,%s,%p)\n",
1637 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1639 ret
=RegCreateKeyEx32W(
1640 hkey
, /* key handle */
1641 lpszSubKey
, /* subkey name */
1642 0, /* reserved = 0 */
1643 NULL
, /* lpszClass? FIXME: ? */
1644 REG_OPTION_NON_VOLATILE
, /* options */
1645 KEY_ALL_ACCESS
, /* desired access attribs */
1646 NULL
, /* lpsecurity attributes */
1647 retkey
, /* lpretkey */
1648 &junk
/* disposition value */
1653 /* RegCreateKeyExA [ADVAPI32.130] */
1654 DWORD
RegCreateKeyEx32A(
1661 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1665 LPWSTR lpszSubKeyW
,lpszClassW
;
1668 dprintf_reg(stddeb
,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1680 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1684 lpszClassW
=strdupA2W(lpszClass
);
1687 ret
=RegCreateKeyEx32W(
1705 /* RegCreateKeyA [ADVAPI32.129] */
1706 DWORD
RegCreateKey32A(
1713 dprintf_reg(stddeb
,"RegCreateKey32A(%lx,%s,%p)\n",
1714 (LONG
)hkey
,lpszSubKey
,retkey
1716 return RegCreateKeyEx32A(
1717 hkey
, /* key handle */
1718 lpszSubKey
, /* subkey name */
1719 0, /* reserved = 0 */
1720 NULL
, /* lpszClass? FIXME: ? */
1721 REG_OPTION_NON_VOLATILE
,/* options */
1722 KEY_ALL_ACCESS
, /* desired access attribs */
1723 NULL
, /* lpsecurity attributes */
1724 retkey
, /* lpretkey */
1725 &junk
/* disposition value */
1729 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1730 DWORD
RegCreateKey16(
1735 dprintf_reg(stddeb
,"RegCreateKey16(%lx,%s,%p)\n",
1736 (LONG
)hkey
,lpszSubKey
,retkey
1738 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1742 * Query Value Functions
1743 * Win32 differs between keynames and valuenames.
1744 * multiple values may belong to one key, the special value
1745 * with name NULL is the default value used by the win31
1749 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1750 * RegQueryValue32W -> RegQueryValueEx32W
1753 /* RegQueryValueExW [ADVAPI32.158] */
1754 DWORD
RegQueryValueEx32W(
1756 LPWSTR lpszValueName
,
1757 LPDWORD lpdwReserved
,
1765 dprintf_reg(stddeb
,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1766 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1767 lpcbData
?*lpcbData
:0
1770 lpkey
= lookup_hkey(hkey
);
1772 return SHELL_ERROR_BADKEY
;
1773 if (lpszValueName
==NULL
) {
1774 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1775 if (lpkey
->values
[i
].name
==NULL
)
1778 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1779 if ( lpkey
->values
[i
].name
&&
1780 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
1784 if (i
==lpkey
->nrofvalues
) {
1785 if (lpszValueName
==NULL
) {
1787 *(WCHAR
*)lpbData
= 0;
1792 return SHELL_ERROR_SUCCESS
;
1794 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
1797 *lpdwType
= lpkey
->values
[i
].type
;
1798 if (lpbData
==NULL
) {
1800 return SHELL_ERROR_SUCCESS
;
1801 *lpcbData
= lpkey
->values
[i
].len
;
1802 return SHELL_ERROR_SUCCESS
;
1804 if (*lpcbData
<lpkey
->values
[i
].len
) {
1807 *lpcbData
= lpkey
->values
[i
].len
;
1808 return ERROR_MORE_DATA
;
1810 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
1811 *lpcbData
= lpkey
->values
[i
].len
;
1812 return SHELL_ERROR_SUCCESS
;
1815 /* RegQueryValueW [ADVAPI32.159] */
1816 DWORD
RegQueryValue32W(
1825 dprintf_reg(stddeb
,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1826 hkey
,W2C(lpszSubKey
,0),lpszData
,
1827 lpcbData
?*lpcbData
:0
1830 /* only open subkey, if we really do descend */
1831 if (lpszSubKey
&& *lpszSubKey
) {
1832 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
1833 if (ret
!=ERROR_SUCCESS
)
1839 ret
= RegQueryValueEx32W(
1841 NULL
, /* varname NULL -> compat */
1842 NULL
, /* lpdwReserved, must be NULL */
1852 /* RegQueryValueExA [ADVAPI32.157] */
1853 DWORD
RegQueryValueEx32A(
1855 LPSTR lpszValueName
,
1856 LPDWORD lpdwReserved
,
1861 LPWSTR lpszValueNameW
;
1867 dprintf_reg(stddeb
,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
1868 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1869 lpcbData
?*lpcbData
:0
1873 buf
= (LPBYTE
)xmalloc((*lpcbData
)*2);
1874 myxlen
= *lpcbData
*2;
1879 myxlen
= *lpcbData
*2;
1885 lpszValueNameW
=strdupA2W(lpszValueName
);
1887 lpszValueNameW
=NULL
;
1891 ret
=RegQueryValueEx32W(
1901 if (ret
==ERROR_SUCCESS
) {
1903 if (UNICONVMASK
& (1<<(type
))) {
1904 /* convert UNICODE to ASCII */
1905 strcpyWA(lpbData
,(LPWSTR
)buf
);
1906 *lpcbData
= myxlen
/2;
1908 if (myxlen
>*lpcbData
)
1909 ret
= ERROR_MORE_DATA
;
1911 memcpy(lpbData
,buf
,myxlen
);
1916 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
1917 *lpcbData
= myxlen
/2;
1920 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
1921 *lpcbData
= myxlen
/2;
1928 /* RegQueryValueEx [KERNEL.225] */
1929 DWORD
RegQueryValueEx16(
1931 LPSTR lpszValueName
,
1932 LPDWORD lpdwReserved
,
1937 dprintf_reg(stddeb
,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
1938 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1939 lpcbData
?*lpcbData
:0
1941 return RegQueryValueEx32A(
1951 /* RegQueryValueA [ADVAPI32.156] */
1952 DWORD
RegQueryValue32A(
1961 dprintf_reg(stddeb
,"RegQueryValue32A(%x,%s,%p,%ld)\n",
1962 hkey
,lpszSubKey
,lpszData
,
1963 lpcbData
?*lpcbData
:0
1966 /* only open subkey, if we really do descend */
1967 if (lpszSubKey
&& *lpszSubKey
) {
1968 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
1969 if (ret
!=ERROR_SUCCESS
)
1975 ret
= RegQueryValueEx32A(
1977 NULL
, /* lpszValueName NULL -> compat */
1978 NULL
, /* lpdwReserved, must be NULL */
1988 /* RegQueryValue [SHELL.6] [KERNEL.224] */
1989 DWORD
RegQueryValue16(
1995 dprintf_reg(stddeb
,"RegQueryValue16(%x,%s,%p,%ld)\n",
1996 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0
1998 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
1999 * anyway, so we just mask out the high 16 bit.
2000 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2003 *lpcbData
&= 0xFFFF;
2004 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2008 * Setting values of Registry keys
2011 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2012 * RegSetValue32W -> RegSetValueEx32W
2015 /* RegSetValueExW [ADVAPI32.170] */
2016 DWORD
RegSetValueEx32W(
2018 LPWSTR lpszValueName
,
2027 dprintf_reg(stddeb
,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2028 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
2030 /* we no longer care about the lpbData type here... */
2031 lpkey
= lookup_hkey(hkey
);
2033 return SHELL_ERROR_BADKEY
;
2035 lpkey
->flags
|= REG_OPTION_TAINTED
;
2037 if (lpszValueName
==NULL
) {
2038 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2039 if (lpkey
->values
[i
].name
==NULL
)
2042 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2043 if ( lpkey
->values
[i
].name
&&
2044 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
2048 if (i
==lpkey
->nrofvalues
) {
2049 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2051 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2053 lpkey
->nrofvalues
++;
2054 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2056 if (lpkey
->values
[i
].name
==NULL
)
2058 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2060 lpkey
->values
[i
].name
= NULL
;
2061 lpkey
->values
[i
].len
= cbData
;
2062 lpkey
->values
[i
].type
= dwType
;
2063 if (lpkey
->values
[i
].data
!=NULL
)
2064 free(lpkey
->values
[i
].data
);
2065 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2066 lpkey
->values
[i
].lastmodified
= time(NULL
);
2067 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2068 return SHELL_ERROR_SUCCESS
;
2071 /* RegSetValueExA [ADVAPI32.169] */
2072 DWORD
RegSetValueEx32A(
2074 LPSTR lpszValueName
,
2081 LPWSTR lpszValueNameW
;
2084 dprintf_reg(stddeb
,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2085 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2087 if ((1<<dwType
) & UNICONVMASK
) {
2088 buf
=(LPBYTE
)strdupA2W(lpbData
);
2089 cbData
=2*strlen(lpbData
)+2;
2093 lpszValueNameW
= strdupA2W(lpszValueName
);
2095 lpszValueNameW
= NULL
;
2096 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2098 free(lpszValueNameW
);
2104 /* RegSetValueEx [KERNEL.226] */
2105 DWORD
RegSetValueEx16(
2107 LPSTR lpszValueName
,
2113 dprintf_reg(stddeb
,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2114 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2116 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2119 /* RegSetValueW [ADVAPI32.171] */
2120 DWORD
RegSetValue32W(
2130 dprintf_reg(stddeb
,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2131 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2133 if (lpszSubKey
&& *lpszSubKey
) {
2134 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2135 if (ret
!=ERROR_SUCCESS
)
2139 if (dwType
!=REG_SZ
) {
2140 fprintf(stddeb
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2143 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2144 dprintf_reg(stddeb
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2145 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2147 cbData
=2*lstrlen32W(lpszData
)+2;
2149 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2155 /* RegSetValueA [ADVAPI32.168] */
2156 DWORD
RegSetValue32A(
2166 dprintf_reg(stddeb
,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2167 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2169 if (lpszSubKey
&& *lpszSubKey
) {
2170 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2171 if (ret
!=ERROR_SUCCESS
)
2176 if (dwType
!=REG_SZ
) {
2177 dprintf_reg(stddeb
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2180 if (cbData
!=strlen(lpszData
)+1)
2181 cbData
=strlen(lpszData
)+1;
2182 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2188 /* RegSetValue [KERNEL.221] [SHELL.5] */
2189 DWORD
RegSetValue16(
2197 dprintf_reg(stddeb
,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2198 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2200 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2208 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2209 * RegEnumKey32W -> RegEnumKeyEx32W
2212 /* RegEnumKeyExW [ADVAPI32.139] */
2213 DWORD
RegEnumKeyEx32W(
2218 LPDWORD lpdwReserved
,
2223 LPKEYSTRUCT lpkey
,lpxkey
;
2225 dprintf_reg(stddeb
,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2226 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2228 lpkey
=lookup_hkey(hkey
);
2230 return SHELL_ERROR_BADKEY
;
2231 if (!lpkey
->nextsub
)
2232 return ERROR_NO_MORE_ITEMS
;
2233 lpxkey
=lpkey
->nextsub
;
2234 while (iSubkey
&& lpxkey
) {
2236 lpxkey
=lpxkey
->next
;
2238 if (iSubkey
|| !lpxkey
)
2239 return ERROR_NO_MORE_ITEMS
;
2240 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2241 return ERROR_MORE_DATA
;
2242 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2244 /* what should we write into it? */
2248 return ERROR_SUCCESS
;
2252 /* RegEnumKeyW [ADVAPI32.140] */
2253 DWORD
RegEnumKey32W(
2261 dprintf_reg(stddeb
,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2262 hkey
,iSubkey
,lpszName
,lpcchName
2264 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2266 /* RegEnumKeyExA [ADVAPI32.138] */
2267 DWORD
RegEnumKeyEx32A(
2272 LPDWORD lpdwReserved
,
2277 DWORD ret
,lpcchNameW
,lpcchClassW
;
2278 LPWSTR lpszNameW
,lpszClassW
;
2281 dprintf_reg(stddeb
,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2282 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2285 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2286 lpcchNameW
= *lpcchName
*2;
2292 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2293 lpcchClassW
= *lpcchClass
*2;
2298 ret
=RegEnumKeyEx32W(
2308 if (ret
==ERROR_SUCCESS
) {
2309 strcpyWA(lpszName
,lpszNameW
);
2310 *lpcchName
=strlen(lpszName
);
2312 strcpyWA(lpszClass
,lpszClassW
);
2313 *lpcchClass
=strlen(lpszClass
);
2323 /* RegEnumKeyA [ADVAPI32.137] */
2324 DWORD
RegEnumKey32A(
2332 dprintf_reg(stddeb
,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2333 hkey
,iSubkey
,lpszName
,lpcchName
2335 return RegEnumKeyEx32A(
2347 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2354 dprintf_reg(stddeb
,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2355 hkey
,iSubkey
,lpszName
,lpcchName
2357 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2361 * Enumerate Registry Values
2364 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2367 /* RegEnumValueW [ADVAPI32.142] */
2368 DWORD
RegEnumValue32W(
2373 LPDWORD lpdReserved
,
2381 dprintf_reg(stddeb
,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2382 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2384 lpkey
= lookup_hkey(hkey
);
2386 return SHELL_ERROR_BADKEY
;
2387 if (lpkey
->nrofvalues
<=iValue
)
2388 return ERROR_NO_MORE_ITEMS
;
2389 val
= lpkey
->values
+iValue
;
2392 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2393 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2394 return ERROR_MORE_DATA
;
2396 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2397 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2399 /* how to handle NULL value? */
2403 *lpdwType
=val
->type
;
2405 if (val
->len
>*lpcbData
)
2406 return ERROR_MORE_DATA
;
2407 memcpy(lpbData
,val
->data
,val
->len
);
2408 *lpcbData
= val
->len
;
2410 return SHELL_ERROR_SUCCESS
;
2413 /* RegEnumValueA [ADVAPI32.141] */
2414 DWORD
RegEnumValue32A(
2419 LPDWORD lpdReserved
,
2426 DWORD ret
,lpcbDataW
;
2428 dprintf_reg(stddeb
,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2429 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2432 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2434 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2435 lpcbDataW
= *lpcbData
*2;
2438 ret
=RegEnumValue32W(
2449 if (ret
==ERROR_SUCCESS
) {
2450 strcpyWA(lpszValue
,lpszValueW
);
2452 if ((1<<*lpdwType
) & UNICONVMASK
) {
2453 strcpyWA(lpbData
,(LPWSTR
)lpbDataW
);
2455 if (lpcbDataW
> *lpcbData
)
2456 ret
= ERROR_MORE_DATA
;
2458 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2460 *lpcbData
= lpcbDataW
;
2470 /* RegEnumValue [KERNEL.223] */
2471 DWORD
RegEnumValue16(
2476 LPDWORD lpdReserved
,
2481 dprintf_reg(stddeb
,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2482 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2484 return RegEnumValue32A(
2497 * Close registry key
2499 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2500 DWORD
RegCloseKey(HKEY hkey
) {
2501 dprintf_reg(stddeb
,"RegCloseKey(%x)\n",hkey
);
2502 remove_handle(hkey
);
2503 return ERROR_SUCCESS
;
2506 * Delete registry key
2509 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2511 /* RegDeleteKeyW [ADVAPI32.134] */
2512 DWORD
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2513 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2517 dprintf_reg(stddeb
,"RegDeleteKey32W(%x,%s)\n",
2518 hkey
,W2C(lpszSubKey
,0)
2520 lpNextKey
= lookup_hkey(hkey
);
2522 return SHELL_ERROR_BADKEY
;
2523 /* we need to know the previous key in the hier. */
2524 if (!lpszSubKey
|| !*lpszSubKey
)
2525 return SHELL_ERROR_BADKEY
;
2526 split_keypath(lpszSubKey
,&wps
,&wpc
);
2530 lpxkey
=lpNextKey
->nextsub
;
2532 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2534 lpxkey
=lpxkey
->next
;
2538 /* not found is success */
2539 return SHELL_ERROR_SUCCESS
;
2544 lpxkey
= lpNextKey
->nextsub
;
2545 lplpPrevKey
= &(lpNextKey
->nextsub
);
2547 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2549 lplpPrevKey
= &(lpxkey
->next
);
2550 lpxkey
= lpxkey
->next
;
2553 return SHELL_ERROR_SUCCESS
;
2554 if (lpxkey
->nextsub
)
2555 return SHELL_ERROR_CANTWRITE
;
2556 *lplpPrevKey
= lpxkey
->next
;
2557 free(lpxkey
->keyname
);
2559 free(lpxkey
->class);
2561 free(lpxkey
->values
);
2564 return SHELL_ERROR_SUCCESS
;
2567 /* RegDeleteKeyA [ADVAPI32.133] */
2568 DWORD
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2572 dprintf_reg(stddeb
,"RegDeleteKey32A(%x,%s)\n",
2575 lpszSubKeyW
=strdupA2W(lpszSubKey
);
2576 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2581 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2582 DWORD
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2583 dprintf_reg(stddeb
,"RegDeleteKey16(%x,%s)\n",
2586 return RegDeleteKey32A(hkey
,lpszSubKey
);
2590 * Delete registry value
2593 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2595 /* RegDeleteValueW [ADVAPI32.136] */
2596 DWORD
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
) {
2601 dprintf_reg(stddeb
,"RegDeleteValue32W(%x,%s)\n",
2602 hkey
,W2C(lpszValue
,0)
2604 lpkey
=lookup_hkey(hkey
);
2606 return SHELL_ERROR_BADKEY
;
2608 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2609 if ( lpkey
->values
[i
].name
&&
2610 !lstrcmp32W(lpkey
->values
[i
].name
,lpszValue
)
2614 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2615 if (lpkey
->values
[i
].name
==NULL
)
2618 if (i
==lpkey
->nrofvalues
)
2619 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2620 val
= lpkey
->values
+i
;
2621 if (val
->name
) free(val
->name
);
2622 if (val
->data
) free(val
->data
);
2626 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2628 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2630 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2632 lpkey
->nrofvalues
--;
2633 return SHELL_ERROR_SUCCESS
;
2636 /* RegDeleteValueA [ADVAPI32.135] */
2637 DWORD
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
) {
2641 dprintf_reg( stddeb
, "RegDeleteValue32A(%x,%s)\n", hkey
,lpszValue
);
2643 lpszValueW
=strdupA2W(lpszValue
);
2646 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2652 /* RegDeleteValue [KERNEL.222] */
2653 DWORD
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
) {
2654 dprintf_reg( stddeb
,"RegDeleteValue16(%x,%s)\n", hkey
,lpszValue
);
2655 return RegDeleteValue32A(hkey
,lpszValue
);
2658 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2659 DWORD
RegFlushKey(HKEY hkey
) {
2660 dprintf_reg(stddeb
,"RegFlushKey(%x), STUB.\n",hkey
);
2661 return SHELL_ERROR_SUCCESS
;
2664 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2666 /* RegQueryInfoKeyW [ADVAPI32.153] */
2667 DWORD
RegQueryInfoKey32W(
2671 LPDWORD lpdwReserved
,
2673 LPDWORD lpcchMaxSubkey
,
2674 LPDWORD lpcchMaxClass
,
2676 LPDWORD lpcchMaxValueName
,
2677 LPDWORD lpccbMaxValueData
,
2678 LPDWORD lpcbSecurityDescriptor
,
2681 LPKEYSTRUCT lpkey
,lpxkey
;
2682 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2685 dprintf_reg(stddeb
,"RegQueryInfoKey32W(%x,......)\n",hkey
);
2686 lpkey
=lookup_hkey(hkey
);
2688 return SHELL_ERROR_BADKEY
;
2691 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2692 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2693 return ERROR_MORE_DATA
;
2695 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2696 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2703 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2705 lpxkey
=lpkey
->nextsub
;
2706 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2709 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2710 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2711 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2712 maxclass
=lstrlen32W(lpxkey
->class);
2713 if (lpxkey
->nrofvalues
>maxvalues
)
2714 maxvalues
=lpxkey
->nrofvalues
;
2715 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2716 LPKEYVALUE val
=lpxkey
->values
+i
;
2718 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2719 maxvname
=lstrlen32W(val
->name
);
2720 if (val
->len
>maxvdata
)
2723 lpxkey
=lpxkey
->next
;
2725 if (!maxclass
) maxclass
= 1;
2726 if (!maxvname
) maxvname
= 1;
2728 *lpcSubKeys
= nrofkeys
;
2730 *lpcchMaxSubkey
= maxsubkey
*2;
2732 *lpcchMaxClass
= maxclass
*2;
2734 *lpcValues
= maxvalues
;
2735 if (lpcchMaxValueName
)
2736 *lpcchMaxValueName
= maxvname
;
2737 if (lpccbMaxValueData
)
2738 *lpccbMaxValueData
= maxvdata
;
2739 return SHELL_ERROR_SUCCESS
;
2742 /* RegQueryInfoKeyA [ADVAPI32.152] */
2743 DWORD
RegQueryInfoKey32A(
2747 LPDWORD lpdwReserved
,
2749 LPDWORD lpcchMaxSubkey
,
2750 LPDWORD lpcchMaxClass
,
2752 LPDWORD lpcchMaxValueName
,
2753 LPDWORD lpccbMaxValueData
,
2754 LPDWORD lpcbSecurityDescriptor
,
2760 dprintf_reg(stddeb
,"RegQueryInfoKey32A(%x,......)\n",hkey
);
2763 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2767 ret
=RegQueryInfoKey32W(
2778 lpcbSecurityDescriptor
,
2781 if (ret
==ERROR_SUCCESS
)
2782 strcpyWA(lpszClass
,lpszClassW
);
2789 if (lpcchMaxValueName
)
2790 *lpcchMaxValueName
/=2;