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.
231 HKEY cl_r_hkey
,c_u_hkey
;
232 #define ADD_ROOT_KEY(xx) \
233 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
234 memset(xx,'\0',sizeof(KEYSTRUCT));\
235 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
237 ADD_ROOT_KEY(key_local_machine
);
238 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
239 fprintf(stderr
,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
242 key_classes_root
= lookup_hkey(cl_r_hkey
);
244 ADD_ROOT_KEY(key_users
);
247 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
248 * (later, when a win32 registry editing tool becomes avail.)
250 while (pwd
=getpwent()) {
251 if (pwd
->pw_name
== NULL
)
253 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
254 RegCloseKey(c_u_hkey
);
257 pwd
=getpwuid(getuid());
258 if (pwd
&& pwd
->pw_name
) {
259 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
260 key_current_user
= lookup_hkey(c_u_hkey
);
262 ADD_ROOT_KEY(key_current_user
);
264 ADD_ROOT_KEY(key_performance_data
);
265 ADD_ROOT_KEY(key_current_config
);
266 ADD_ROOT_KEY(key_dyn_data
);
270 /************************ SAVE Registry Function ****************************/
272 #define REGISTRY_SAVE_VERSION 0x00000001
274 /* Registry saveformat:
275 * If you change it, increase above number by 1, which will flush
276 * old registry database files.
279 * "WINE REGISTRY Version %d"
283 * valuename=lastmodified,type,data
287 * keyname,valuename,stringdata:
288 * the usual ascii characters from 0x00-0xff (well, not 0x00)
289 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
290 * ( "=\\\t" escaped in \uXXXX form.)
294 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
296 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
297 * SaveOnlyUpdatedKeys=yes
300 _save_check_tainted(LPKEYSTRUCT lpkey
) {
305 if (lpkey
->flags
& REG_OPTION_TAINTED
)
310 if (_save_check_tainted(lpkey
->nextsub
)) {
311 lpkey
->flags
|= REG_OPTION_TAINTED
;
320 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
333 if (escapeeq
&& *s
=='=')
336 fputc(*s
,F
); /* if \\ than put it twice. */
338 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
346 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
352 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
353 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
355 for (tabs
=level
;tabs
--;)
357 _save_USTRING(F
,lpxkey
->keyname
,1);
359 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
360 LPKEYVALUE val
=lpxkey
->values
+i
;
362 for (tabs
=level
+1;tabs
--;)
364 _save_USTRING(F
,val
->name
,0);
366 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
367 if ((1<<val
->type
) & UNICONVMASK
)
368 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
370 for (j
=0;j
<val
->len
;j
++)
371 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
374 /* descend recursively */
375 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
384 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
385 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
386 _save_check_tainted(lpkey
->nextsub
);
387 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
391 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
396 fprintf(stddeb
,__FILE__
":_savereg:Couldn't open %s for writing: %s\n",
401 if (!_savesubreg(F
,lpkey
,all
)) {
404 fprintf(stddeb
,__FILE__
":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
411 SHELL_SaveRegistry() {
419 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
425 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
437 if (lstrcmpi32A(buf
,"yes"))
439 pwd
=getpwuid(getuid());
440 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
441 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_USERS_DEFAULT
)+2);
442 strcpy(fn
,pwd
->pw_dir
);
443 strcat(fn
,WINE_PREFIX
);
444 /* create the directory. don't care about errorcodes. */
445 mkdir(fn
,0755); /* drwxr-xr-x */
446 strcat(fn
,"/"SAVE_CURRENT_USER
);
447 _savereg(key_current_user
,fn
,all
);
449 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
450 strcpy(fn
,pwd
->pw_dir
);
451 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
452 _savereg(key_local_machine
,fn
,all
);
455 fprintf(stderr
,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
458 /************************ LOAD Registry Function ****************************/
461 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
462 LPKEYSTRUCT lpxkey
,*lplpkey
;
464 lplpkey
= &(lpkey
->nextsub
);
467 if (!lstrcmp32W(lpxkey
->keyname
,keyname
))
469 lplpkey
= &(lpxkey
->next
);
473 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
475 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
476 lpxkey
->keyname
= keyname
;
484 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
490 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
496 if ( val
->name
!=NULL
&&
497 !lstrcmp32W(val
->name
,name
)
502 if (i
==lpkey
->nrofvalues
) {
503 lpkey
->values
= xrealloc(
505 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
508 memset(val
,'\0',sizeof(KEYVALUE
));
514 if (val
->lastmodified
<lastmodified
) {
515 val
->lastmodified
=lastmodified
;
526 /* reads a line including dynamically enlarging the readbuffer and throwing
530 _wine_read_line(FILE *F
,char **buf
,int *len
) {
539 s
=fgets(curread
,mylen
,F
);
542 if (NULL
==(s
=strchr(curread
,'\n'))) {
543 /* buffer wasn't large enough */
544 curoff
= strlen(*buf
);
545 *buf
= xrealloc(*buf
,*len
*2);
546 curread
= *buf
+ curoff
;
547 mylen
= *len
; /* we filled up the buffer and
548 * got new '*len' bytes to fill
556 /* throw away comments */
557 if (**buf
=='#' || **buf
==';') {
562 if (s
) /* got end of line */
568 /* converts a char* into a UNICODE string (up to a special char)
569 * and returns the position exactly after that string
572 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
576 /* read up to "=" or "\0" or "\n" */
579 /* empty string is the win3.1 default value(NULL)*/
583 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
585 while (*s
&& (*s
!='\n') && (*s
!='=')) {
587 *ws
++=*((unsigned char*)s
++);
596 fprintf(stderr
,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
604 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
605 if (!sscanf(xbuf
,"%x",&wc
))
606 fprintf(stderr
,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf
,buf
);
608 *ws
++ =(unsigned short)wc
;
614 *str
= strdupW(*str
);
621 FILE *F
,LPKEYSTRUCT lpkey
,int level
,char **buf
,int *buflen
,int optflag
628 lpkey
->flags
|= optflag
;
630 /* good. we already got a line here ... so parse it */
640 fprintf(stderr
,"_load_subkey:Got a subhierarchy without resp. key?\n");
643 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
646 /* let the caller handle this line */
647 if (i
<level
|| **buf
=='\0')
650 /* it can be: a value or a keyname. Parse the name first */
651 s
=_wine_read_USTRING(s
,&name
);
653 /* switch() default: hack to avoid gotos */
657 lpxkey
=_find_or_add_key(lpkey
,name
);
660 int len
,lastmodified
,type
;
663 fprintf(stderr
,"_wine_load_subkey:unexpected character: %c\n",*s
);
667 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
668 fprintf(stderr
,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf
);
674 if ((1<<type
) & UNICONVMASK
) {
675 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
677 len
= lstrlen32W((LPWSTR
)data
)*2+2;
682 data
= (LPBYTE
)xmalloc(len
+1);
683 for (i
=0;i
<len
;i
++) {
685 if (*s
>='0' && *s
<='9')
687 if (*s
>='a' && *s
<='f')
689 if (*s
>='A' && *s
<='F')
692 if (*s
>='0' && *s
<='9')
694 if (*s
>='a' && *s
<='f')
696 if (*s
>='A' && *s
<='F')
701 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
704 /* read the next line */
705 if (!_wine_read_line(F
,buf
,buflen
))
712 _wine_loadsubreg(FILE *F
,LPKEYSTRUCT lpkey
,int optflag
) {
717 buf
=xmalloc(10);buflen
=10;
718 if (!_wine_read_line(F
,&buf
,&buflen
)) {
722 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
726 if (ver
!=REGISTRY_SAVE_VERSION
) {
727 dprintf_reg(stddeb
,__FILE__
":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
731 if (!_wine_read_line(F
,&buf
,&buflen
)) {
735 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
744 _wine_loadreg(LPKEYSTRUCT lpkey
,char *fn
,int optflag
) {
749 dprintf_reg(stddeb
,__FILE__
":Couldn't open %s for reading: %s\n",
754 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
763 _copy_registry(LPKEYSTRUCT from
,LPKEYSTRUCT to
) {
770 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
772 for (j
=0;j
<from
->nrofvalues
;j
++) {
776 valfrom
= from
->values
+j
;
778 if (name
) name
=strdupW(name
);
779 data
=(LPBYTE
)malloc(valfrom
->len
);
780 memcpy(data
,valfrom
->data
,valfrom
->len
);
788 valfrom
->lastmodified
791 _copy_registry(from
,lpxkey
);
796 /* WINDOWS 95 REGISTRY LOADER */
798 * Structure of a win95 registry database.
802 * 8 : DWORD offset_of_RGDB_part
803 * 0C..1F: ? (someone fill in please)
808 * 4..0x1B: ? (fill in)
809 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
811 * Disk Key Entry Structure:
812 * 00: DWORD - unknown
813 * 04: DWORD - unknown
814 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
815 * 0C: DWORD - disk address of PreviousLevel Key.
816 * 10: DWORD - disk address of Next Sublevel Key.
817 * 14: DWORD - disk address of Next Key (on same level).
818 * DKEP>18: WORD - Nr, Low Significant part.
819 * 1A: WORD - Nr, High Significant part.
821 * The disk address always points to the nr part of the previous key entry
822 * of the referenced key. Don't ask me why, or even if I got this correct
823 * from staring at 1kg of hexdumps. (DKEP)
825 * The number of the entry is the low byte of the Low Significant Part ored
826 * with 0x100 * (low byte of the High Significant part)
827 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
829 * There are two minor corrections to the position of that structure.
830 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
831 * the DKE reread from there.
832 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
833 * (FIXME: slightly better explanation needed here)
837 * 04: DWORD offset to next RGDB section (perhaps WORD)
842 * 00: DWORD nextkeyoffset - offset to the next disk key structure
843 * 08: WORD nrLS - low significant part of NR
844 * 0A: WORD nrHS - high significant part of NR
845 * 0C: DWORD bytesused - bytes used in this structure.
846 * 10: WORD name_len - length of name in bytes. without \0
847 * 12: WORD nr_of_values - number of values.
848 * 14: char name[name_len] - name string. No \0.
849 * 14+name_len: disk values
850 * nextkeyoffset: ... next disk key
853 * 00: DWORD type - value type (hmm, could be WORD too)
854 * 04: DWORD - unknown, usually 0
855 * 08: WORD namelen - length of Name. 0 means name=NULL
856 * 0C: WORD datalen - length of Data.
857 * 10: char name[namelen] - name, no \0
858 * 10+namelen: BYTE data[datalen] - data, without \0 if string
859 * 10+namelen+datalen: next values or disk key
861 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
862 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
863 * structure) and reading another RGDB_section.
864 * repeat until end of file.
866 * FIXME: this description needs some serious help, yes.
869 struct _w95keyvalue
{
871 unsigned short datalen
;
881 struct _w95keyvalue
*values
;
882 unsigned long dkeaddr
;
887 struct _w95key
*prevlvl
;
888 struct _w95key
*nextsub
;
889 struct _w95key
*next
;
892 /* fast lookup table dkeaddr->nr */
894 unsigned long dkeaddr
;
900 _w95_walk_tree(LPKEYSTRUCT lpkey
,struct _w95key
*key
) {
906 if (key
->name
== NULL
) {
907 fprintf(stderr
,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
912 lpxkey
=_find_or_add_key(lpkey
,strdupA2W(key
->name
));
914 if (key
->nrofvals
<0) {
915 /* shouldn't happen */
916 fprintf(stderr
,"key %s already processed!\n",key
->name
);
920 for (i
=0;i
<key
->nrofvals
;i
++) {
924 name
= strdupA2W(key
->values
[i
].name
);
925 if (!*name
) name
= NULL
;
926 free(key
->values
[i
].name
);
928 len
= key
->values
[i
].datalen
;
929 data
= key
->values
[i
].data
;
930 if ((1<<key
->values
[i
].type
) & UNICONVMASK
) {
931 data
= (BYTE
*)strdupA2W(data
);
932 len
= lstrlen32W((LPWSTR
)data
)*2+2;
933 free(key
->values
[i
].data
);
941 key
->values
[i
].lastmodified
948 key
->nrofvals
=-key
->nrofvals
-1;
949 _w95_walk_tree(lpxkey
,key
->nextsub
);
954 /* small helper function to adjust address offset (dkeaddrs) */
956 _w95_adj_da(unsigned long dkeaddr
) {
957 if ((dkeaddr
&0xFFF)<0x018) {
960 diff
=0x1C-(dkeaddr
&0xFFF);
963 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
964 /* readjust to 0x000,
965 * but ONLY if we are >0x1000 already
967 if (dkeaddr
& ~0xFFF)
968 return dkeaddr
& ~0xFFF;
974 _w95dkecomp(struct _w95nr2da
*a
,struct _w95nr2da
*b
){return a
->dkeaddr
-b
->dkeaddr
;}
976 static struct _w95key
*
977 _w95dkelookup(unsigned long dkeaddr
,int n
,struct _w95nr2da
*nr2da
,struct _w95key
*keys
) {
980 if (dkeaddr
== 0xFFFFFFFF)
984 dkeaddr
=_w95_adj_da(dkeaddr
+0x1c);
985 off
= (dkeaddr
-0x3c)/0x1c;
987 if (nr2da
[(i
+off
)%n
].dkeaddr
== dkeaddr
)
988 return keys
+nr2da
[(i
+off
)%n
].nr
;
989 /* 0x3C happens often, just report unusual values */
991 dprintf_reg(stddeb
,"search hasn't found dkeaddr %lx?\n",dkeaddr
);
996 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
997 /* Disk Key Entry structure (RGKN part) */
1001 unsigned long x3
;/*usually 0xFFFFFFFF */
1002 unsigned long prevlvl
;
1003 unsigned long nextsub
;
1005 unsigned short nrLS
;
1006 unsigned short nrMS
;
1008 /* Disk Key Header structure (RGDB part) */
1010 unsigned long nextkeyoff
;
1011 unsigned short nrLS
;
1012 unsigned short nrMS
;
1013 unsigned long bytesused
;
1014 unsigned short keynamelen
;
1015 unsigned short values
;
1018 /* disk key values or nothing */
1020 /* Disk Key Value structure */
1024 unsigned short valnamelen
;
1025 unsigned short valdatalen
;
1026 /* valname, valdata */
1028 struct _w95nr2da
*nr2da
;
1031 int fd
,lastmodified
;
1033 unsigned long nr
,pos
,i
,where
,version
,rgdbsection
,end
,off_next_rgdb
;
1034 struct _w95key
*keys
;
1036 unsigned char *data
,*curdata
,*nextrgdb
;
1040 dprintf_reg(stddeb
,"Loading Win95 registry database '%s'\n",fn
);
1041 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1042 if (hfd
==HFILE_ERROR
)
1044 fd
= FILE_GetUnixHandle(hfd
);
1046 if (4!=read(fd
,magic
,4))
1048 if (strcmp(magic
,"CREG")) {
1049 fprintf(stddeb
,"%s is not a w95 registry.\n",fn
);
1052 if (4!=read(fd
,&version
,4))
1054 if (4!=read(fd
,&rgdbsection
,4))
1056 if (-1==lseek(fd
,0x20,SEEK_SET
))
1058 if (4!=read(fd
,magic
,4))
1060 if (strcmp(magic
,"RGKN")) {
1061 dprintf_reg(stddeb
,"second IFF header not RGKN, but %s\n",magic
);
1065 /* STEP 1: Keylink structures */
1066 if (-1==lseek(fd
,0x40,SEEK_SET
))
1071 nrofdkes
= (end
-where
)/sizeof(struct dke
)+100;
1072 data
= (char*)xmalloc(end
-where
);
1073 if ((end
-where
)!=read(fd
,data
,end
-where
))
1077 keys
= (struct _w95key
*)xmalloc(nrofdkes
* sizeof(struct _w95key
));
1078 memset(keys
,'\0',nrofdkes
*sizeof(struct _w95key
));
1079 nr2da
= (struct _w95nr2da
*)xmalloc(nrofdkes
* sizeof(struct _w95nr2da
));
1080 memset(nr2da
,'\0',nrofdkes
*sizeof(struct _w95nr2da
));
1082 for (i
=0;i
<nrofdkes
;i
++) {
1084 unsigned long dkeaddr
;
1086 pos
=curdata
-data
+0x40;
1087 memcpy(&dke
,curdata
,sizeof(dke
));
1088 curdata
+=sizeof(dke
);
1089 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1091 if ((dkeaddr
&0xFFF)<0x018) {
1094 diff
=0x1C-(dkeaddr
&0xFFF);
1096 curdata
+=diff
-sizeof(dke
);
1097 memcpy(&dke
,curdata
,sizeof(dke
));
1098 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1099 curdata
+=sizeof(dke
);
1101 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1102 /* readjust to 0x000,
1103 * but ONLY if we are >0x1000 already
1105 if (dkeaddr
& ~0xFFF)
1106 dkeaddr
= dkeaddr
& ~0xFFF;
1109 /* 0xFFFFFFFF happens often, just report unusual values */
1111 dprintf_reg(stddeb
,"nr %ld exceeds nrofdkes %d, skipping.\n",nr
,nrofdkes
);
1114 if (keys
[nr
].dkeaddr
) {
1117 for (x
=sizeof(dke
);x
--;)
1118 if (((char*)&dke
)[x
])
1121 break; /* finished reading if we got only 0 */
1123 if ( (dke
.next
!=(long)keys
[nr
].next
) ||
1124 (dke
.nextsub
!=(long)keys
[nr
].nextsub
) ||
1125 (dke
.prevlvl
!=(long)keys
[nr
].prevlvl
)
1127 dprintf_reg(stddeb
,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr
,keys
[nr
].dkeaddr
,dkeaddr
);
1132 nr2da
[i
].dkeaddr
= dkeaddr
;
1134 keys
[nr
].dkeaddr
= dkeaddr
;
1135 keys
[nr
].x1
= dke
.x1
;
1136 keys
[nr
].x2
= dke
.x2
;
1137 keys
[nr
].x3
= dke
.x3
;
1138 keys
[nr
].prevlvl
= (struct _w95key
*)dke
.prevlvl
;
1139 keys
[nr
].nextsub
= (struct _w95key
*)dke
.nextsub
;
1140 keys
[nr
].next
= (struct _w95key
*)dke
.next
;
1144 qsort(nr2da
,nrofdkes
,sizeof(nr2da
[0]),_w95dkecomp
);
1146 /* STEP 2: keydata & values */
1147 if (-1==fstat(fd
,&stbuf
))
1149 end
= stbuf
.st_size
;
1150 lastmodified
= stbuf
.st_mtime
;
1152 if (-1==lseek(fd
,rgdbsection
,SEEK_SET
))
1154 data
= (char*)xmalloc(end
-rgdbsection
);
1155 if ((end
-rgdbsection
)!=read(fd
,data
,end
-rgdbsection
))
1159 memcpy(magic
,curdata
,4);
1160 memcpy(&off_next_rgdb
,curdata
+4,4);
1161 nextrgdb
= curdata
+off_next_rgdb
;
1162 if (strcmp(magic
,"RGDB")) {
1163 dprintf_reg(stddeb
,"third IFF header not RGDB, but %s\n",magic
);
1170 struct _w95key
*key
,xkey
;
1173 if (curdata
>=nextrgdb
) {
1175 if (!strncmp(curdata
,"RGDB",4)) {
1176 memcpy(&off_next_rgdb
,curdata
+4,4);
1177 nextrgdb
= curdata
+off_next_rgdb
;
1180 dprintf_reg(stddeb
,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata
-data
,end
-rgdbsection
);
1184 #define XREAD(whereto,len) \
1185 if ((curdata-data+len)<end) {\
1186 memcpy(whereto,curdata,len);\
1191 XREAD(&dkh
,sizeof(dkh
));
1192 nr
= dkh
.nrLS
+ (dkh
.nrMS
<<8);
1193 if ((nr
>nrofdkes
) || (dkh
.nrLS
== 0xFFFF)) {
1194 if (dkh
.nrLS
== 0xFFFF) {
1195 /* skip over key using nextkeyoff */
1196 curdata
+=dkh
.nextkeyoff
-sizeof(struct dkh
);
1199 dprintf_reg(stddeb
,"haven't found nr %ld.\n",nr
);
1201 memset(key
,'\0',sizeof(xkey
));
1205 dprintf_reg(stddeb
,"key with nr=%ld has no dkeaddr?\n",nr
);
1207 key
->nrofvals
= dkh
.values
;
1208 key
->name
= (char*)xmalloc(dkh
.keynamelen
+1);
1210 XREAD(key
->name
,dkh
.keynamelen
);
1211 key
->name
[dkh
.keynamelen
]=0;
1212 if (key
->nrofvals
) {
1213 key
->values
= (struct _w95keyvalue
*)xmalloc(
1214 sizeof(struct _w95keyvalue
)*key
->nrofvals
1216 for (i
=0;i
<key
->nrofvals
;i
++) {
1219 XREAD(&dkv
,sizeof(dkv
));
1220 key
->values
[i
].type
= dkv
.type
;
1221 key
->values
[i
].name
= (char*)xmalloc(
1224 key
->values
[i
].datalen
= dkv
.valdatalen
;
1225 key
->values
[i
].data
= (unsigned char*)xmalloc(
1228 key
->values
[i
].x1
= dkv
.x1
;
1229 XREAD(key
->values
[i
].name
,dkv
.valnamelen
);
1230 XREAD(key
->values
[i
].data
,dkv
.valdatalen
);
1231 key
->values
[i
].data
[dkv
.valdatalen
]=0;
1232 key
->values
[i
].name
[dkv
.valnamelen
]=0;
1233 key
->values
[i
].lastmodified
=lastmodified
;
1236 if (bytesread
!= dkh
.nextkeyoff
) {
1237 if (dkh
.bytesused
!= bytesread
)
1239 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread
,dkh
.nextkeyoff
,
1242 curdata
+= dkh
.nextkeyoff
-bytesread
;
1244 key
->prevlvl
= _w95dkelookup((long)key
->prevlvl
,nrofdkes
,nr2da
,keys
);
1245 key
->nextsub
= _w95dkelookup((long)key
->nextsub
,nrofdkes
,nr2da
,keys
);
1246 key
->next
= _w95dkelookup((long)key
->next
,nrofdkes
,nr2da
,keys
);
1251 _w95_walk_tree(lpkey
,keys
);
1256 SHELL_LoadRegistry() {
1263 if (key_classes_root
==NULL
)
1266 /* Load windows 95 entries */
1267 _w95_loadreg("C:\\system.1st", key_local_machine
);
1268 _w95_loadreg("system.dat", key_local_machine
);
1269 _w95_loadreg("user.dat", key_users
);
1271 /* FIXME: win3.1 reg.dat loader still missing */
1273 /* the global user default is loaded under HKEY_USERS\\.Default */
1274 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1275 lpkey
= lookup_hkey(hkey
);
1276 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1278 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1279 _copy_registry(lpkey
,key_current_user
);
1282 /* the global machine defaults */
1283 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1285 /* load the user saved registries */
1287 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1289 pwd
=getpwuid(getuid());
1290 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1291 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1292 strcpy(fn
,pwd
->pw_dir
);
1293 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1294 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1296 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1297 strcpy(fn
,pwd
->pw_dir
);
1298 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1299 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1302 fprintf(stderr
,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1303 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1304 DWORD junk
,type
,len
;
1308 if (( RegQueryValueEx32A(
1315 )!=ERROR_SUCCESS
) ||
1318 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1324 /********************* API FUNCTIONS ***************************************/
1328 * All functions are stubs to RegOpenKeyEx32W where all the
1331 * FIXME: security,options,desiredaccess,...
1334 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1335 * RegOpenKey32W -> RegOpenKeyEx32W
1338 /* RegOpenKeyExW [ADVAPI32.150] */
1339 DWORD
RegOpenKeyEx32W(
1346 LPKEYSTRUCT lpNextKey
,lpxkey
;
1349 dprintf_reg(stddeb
,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1350 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1353 lpNextKey
= lookup_hkey(hkey
);
1355 return SHELL_ERROR_BADKEY
;
1356 if (!lpszSubKey
|| !*lpszSubKey
) {
1357 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1358 *retkey
=currenthandle
;
1359 return SHELL_ERROR_SUCCESS
;
1361 split_keypath(lpszSubKey
,&wps
,&wpc
);
1363 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1366 lpxkey
=lpNextKey
->nextsub
;
1368 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1370 lpxkey
=lpxkey
->next
;
1374 return SHELL_ERROR_BADKEY
;
1379 add_handle(++currenthandle
,lpxkey
,samDesired
);
1380 *retkey
= currenthandle
;
1382 return SHELL_ERROR_SUCCESS
;
1385 /* RegOpenKeyW [ADVAPI32.151] */
1386 DWORD
RegOpenKey32W(
1391 dprintf_reg(stddeb
,"RegOpenKey32W(%lx,%s,%p)\n",
1392 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1394 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1398 /* RegOpenKeyExA [ADVAPI32.149] */
1399 DWORD
RegOpenKeyEx32A(
1409 dprintf_reg(stddeb
,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1410 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1413 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1416 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1422 /* RegOpenKeyA [ADVAPI32.148] */
1423 DWORD
RegOpenKey32A(
1428 dprintf_reg(stddeb
,"RegOpenKey32A(%lx,%s,%p)\n",
1429 (LONG
)hkey
,lpszSubKey
,retkey
1431 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1434 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1440 dprintf_reg(stddeb
,"RegOpenKey16(%lx,%s,%p)\n",
1441 (LONG
)hkey
,lpszSubKey
,retkey
1443 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1449 * All those functions convert their respective
1450 * arguments and call RegCreateKeyExW at the end.
1452 * FIXME: no security,no access attrib,no optionhandling yet.
1455 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1456 * RegCreateKey32W -> RegCreateKeyEx32W
1459 /* RegCreateKeyExW [ADVAPI32.131] */
1460 DWORD
RegCreateKeyEx32W(
1467 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1471 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1475 /*FIXME: handle security/access/whatever */
1476 dprintf_reg(stddeb
,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1488 lpNextKey
= lookup_hkey(hkey
);
1490 return SHELL_ERROR_BADKEY
;
1491 if (!lpszSubKey
|| !*lpszSubKey
) {
1492 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1493 *retkey
=currenthandle
;
1494 return SHELL_ERROR_SUCCESS
;
1496 split_keypath(lpszSubKey
,&wps
,&wpc
);
1498 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1501 lpxkey
=lpNextKey
->nextsub
;
1503 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1505 lpxkey
=lpxkey
->next
;
1513 add_handle(++currenthandle
,lpxkey
,samDesired
);
1514 *retkey
= currenthandle
;
1515 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1517 return SHELL_ERROR_SUCCESS
;
1519 /* good. now the hard part */
1521 lplpPrevKey
= &(lpNextKey
->nextsub
);
1522 lpxkey
= *lplpPrevKey
;
1524 lplpPrevKey
= &(lpxkey
->next
);
1525 lpxkey
= *lplpPrevKey
;
1527 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1528 if (!*lplpPrevKey
) {
1530 return SHELL_ERROR_OUTOFMEMORY
;
1532 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1533 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1534 (*lplpPrevKey
)->next
= NULL
;
1535 (*lplpPrevKey
)->nextsub
= NULL
;
1536 (*lplpPrevKey
)->values
= NULL
;
1537 (*lplpPrevKey
)->nrofvalues
= 0;
1539 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1541 (*lplpPrevKey
)->class = NULL
;
1542 lpNextKey
= *lplpPrevKey
;
1545 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1547 /*FIXME: flag handling correct? */
1548 lpNextKey
->flags
= fdwOptions
;
1550 lpNextKey
->class = strdupW(lpszClass
);
1552 lpNextKey
->class = NULL
;
1553 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1554 *retkey
= currenthandle
;
1555 *lpDispos
= REG_CREATED_NEW_KEY
;
1557 return SHELL_ERROR_SUCCESS
;
1560 /* RegCreateKeyW [ADVAPI32.132] */
1561 DWORD
RegCreateKey32W(
1568 dprintf_reg(stddeb
,"RegCreateKey32W(%lx,%s,%p)\n",
1569 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1571 ret
=RegCreateKeyEx32W(
1572 hkey
, /* key handle */
1573 lpszSubKey
, /* subkey name */
1574 0, /* reserved = 0 */
1575 NULL
, /* lpszClass? FIXME: ? */
1576 REG_OPTION_NON_VOLATILE
, /* options */
1577 KEY_ALL_ACCESS
, /* desired access attribs */
1578 NULL
, /* lpsecurity attributes */
1579 retkey
, /* lpretkey */
1580 &junk
/* disposition value */
1585 /* RegCreateKeyExA [ADVAPI32.130] */
1586 DWORD
RegCreateKeyEx32A(
1593 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1597 LPWSTR lpszSubKeyW
,lpszClassW
;
1600 dprintf_reg(stddeb
,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1612 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1616 lpszClassW
=strdupA2W(lpszClass
);
1619 ret
=RegCreateKeyEx32W(
1637 /* RegCreateKeyA [ADVAPI32.129] */
1638 DWORD
RegCreateKey32A(
1645 dprintf_reg(stddeb
,"RegCreateKey32A(%lx,%s,%p)\n",
1646 (LONG
)hkey
,lpszSubKey
,retkey
1648 return RegCreateKeyEx32A(
1649 hkey
, /* key handle */
1650 lpszSubKey
, /* subkey name */
1651 0, /* reserved = 0 */
1652 NULL
, /* lpszClass? FIXME: ? */
1653 REG_OPTION_NON_VOLATILE
,/* options */
1654 KEY_ALL_ACCESS
, /* desired access attribs */
1655 NULL
, /* lpsecurity attributes */
1656 retkey
, /* lpretkey */
1657 &junk
/* disposition value */
1661 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1662 DWORD
RegCreateKey16(
1667 dprintf_reg(stddeb
,"RegCreateKey16(%lx,%s,%p)\n",
1668 (LONG
)hkey
,lpszSubKey
,retkey
1670 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1674 * Query Value Functions
1675 * Win32 differs between keynames and valuenames.
1676 * multiple values may belong to one key, the special value
1677 * with name NULL is the default value used by the win31
1681 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1682 * RegQueryValue32W -> RegQueryValueEx32W
1685 /* RegQueryValueExW [ADVAPI32.158] */
1686 DWORD
RegQueryValueEx32W(
1688 LPWSTR lpszValueName
,
1689 LPDWORD lpdwReserved
,
1697 dprintf_reg(stddeb
,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1698 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1699 lpcbData
?*lpcbData
:0
1702 lpkey
= lookup_hkey(hkey
);
1704 return SHELL_ERROR_BADKEY
;
1705 if (lpszValueName
==NULL
) {
1706 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1707 if (lpkey
->values
[i
].name
==NULL
)
1710 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1711 if ( lpkey
->values
[i
].name
&&
1712 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
1716 if (i
==lpkey
->nrofvalues
) {
1717 if (lpszValueName
==NULL
) {
1719 *(WCHAR
*)lpbData
= 0;
1724 return SHELL_ERROR_SUCCESS
;
1726 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
1729 *lpdwType
= lpkey
->values
[i
].type
;
1730 if (lpbData
==NULL
) {
1732 return SHELL_ERROR_SUCCESS
;
1733 *lpcbData
= lpkey
->values
[i
].len
;
1734 return SHELL_ERROR_SUCCESS
;
1736 if (*lpcbData
<lpkey
->values
[i
].len
) {
1739 *lpcbData
= lpkey
->values
[i
].len
;
1740 return ERROR_MORE_DATA
;
1742 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
1743 *lpcbData
= lpkey
->values
[i
].len
;
1744 return SHELL_ERROR_SUCCESS
;
1747 /* RegQueryValueW [ADVAPI32.159] */
1748 DWORD
RegQueryValue32W(
1757 dprintf_reg(stddeb
,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1758 hkey
,W2C(lpszSubKey
,0),lpszData
,
1759 lpcbData
?*lpcbData
:0
1762 /* only open subkey, if we really do descend */
1763 if (lpszSubKey
&& *lpszSubKey
) {
1764 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
1765 if (ret
!=ERROR_SUCCESS
)
1771 ret
= RegQueryValueEx32W(
1773 NULL
, /* varname NULL -> compat */
1774 NULL
, /* lpdwReserved, must be NULL */
1784 /* RegQueryValueExA [ADVAPI32.157] */
1785 DWORD
RegQueryValueEx32A(
1787 LPSTR lpszValueName
,
1788 LPDWORD lpdwReserved
,
1793 LPWSTR lpszValueNameW
;
1799 dprintf_reg(stddeb
,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
1800 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1801 lpcbData
?*lpcbData
:0
1805 buf
= (LPBYTE
)xmalloc((*lpcbData
)*2);
1806 myxlen
= *lpcbData
*2;
1811 myxlen
= *lpcbData
*2;
1817 lpszValueNameW
=strdupA2W(lpszValueName
);
1819 lpszValueNameW
=NULL
;
1823 ret
=RegQueryValueEx32W(
1833 if (ret
==ERROR_SUCCESS
) {
1835 if (UNICONVMASK
& (1<<(type
))) {
1836 /* convert UNICODE to ASCII */
1837 strcpyWA(lpbData
,(LPWSTR
)buf
);
1838 *lpcbData
= myxlen
/2;
1840 if (myxlen
>*lpcbData
)
1841 ret
= ERROR_MORE_DATA
;
1843 memcpy(lpbData
,buf
,myxlen
);
1848 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
1849 *lpcbData
= myxlen
/2;
1852 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
1853 *lpcbData
= myxlen
/2;
1860 /* RegQueryValueEx [KERNEL.225] */
1861 DWORD
RegQueryValueEx16(
1863 LPSTR lpszValueName
,
1864 LPDWORD lpdwReserved
,
1869 dprintf_reg(stddeb
,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
1870 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1871 lpcbData
?*lpcbData
:0
1873 return RegQueryValueEx32A(
1883 /* RegQueryValueA [ADVAPI32.156] */
1884 DWORD
RegQueryValue32A(
1893 dprintf_reg(stddeb
,"RegQueryValue32A(%x,%s,%p,%ld)\n",
1894 hkey
,lpszSubKey
,lpszData
,
1895 lpcbData
?*lpcbData
:0
1898 /* only open subkey, if we really do descend */
1899 if (lpszSubKey
&& *lpszSubKey
) {
1900 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
1901 if (ret
!=ERROR_SUCCESS
)
1907 ret
= RegQueryValueEx32A(
1909 NULL
, /* lpszValueName NULL -> compat */
1910 NULL
, /* lpdwReserved, must be NULL */
1920 /* RegQueryValue [SHELL.6] [KERNEL.224] */
1921 DWORD
RegQueryValue16(
1927 dprintf_reg(stddeb
,"RegQueryValue16(%x,%s,%p,%ld)\n",
1928 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0
1930 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
1931 * anyway, so we just mask out the high 16 bit.
1932 * (this (not so much incidently;) hopefully fixes Aldus FH4)
1935 *lpcbData
&= 0xFFFF;
1936 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
1940 * Setting values of Registry keys
1943 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
1944 * RegSetValue32W -> RegSetValueEx32W
1947 /* RegSetValueExW [ADVAPI32.170] */
1948 DWORD
RegSetValueEx32W(
1950 LPWSTR lpszValueName
,
1959 dprintf_reg(stddeb
,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
1960 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
1962 /* we no longer care about the lpbData type here... */
1963 lpkey
= lookup_hkey(hkey
);
1965 return SHELL_ERROR_BADKEY
;
1967 lpkey
->flags
|= REG_OPTION_TAINTED
;
1969 if (lpszValueName
==NULL
) {
1970 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1971 if (lpkey
->values
[i
].name
==NULL
)
1974 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1975 if ( lpkey
->values
[i
].name
&&
1976 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
1980 if (i
==lpkey
->nrofvalues
) {
1981 lpkey
->values
= (LPKEYVALUE
)xrealloc(
1983 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
1985 lpkey
->nrofvalues
++;
1986 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
1988 if (lpkey
->values
[i
].name
==NULL
)
1990 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
1992 lpkey
->values
[i
].name
= NULL
;
1993 lpkey
->values
[i
].len
= cbData
;
1994 lpkey
->values
[i
].type
= dwType
;
1995 if (lpkey
->values
[i
].data
!=NULL
)
1996 free(lpkey
->values
[i
].data
);
1997 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
1998 lpkey
->values
[i
].lastmodified
= time(NULL
);
1999 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2000 return SHELL_ERROR_SUCCESS
;
2003 /* RegSetValueExA [ADVAPI32.169] */
2004 DWORD
RegSetValueEx32A(
2006 LPSTR lpszValueName
,
2013 LPWSTR lpszValueNameW
;
2016 dprintf_reg(stddeb
,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2017 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2019 if ((1<<dwType
) & UNICONVMASK
) {
2020 buf
=(LPBYTE
)strdupA2W(lpbData
);
2021 cbData
=2*strlen(lpbData
)+2;
2025 lpszValueNameW
= strdupA2W(lpszValueName
);
2027 lpszValueNameW
= NULL
;
2028 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2030 free(lpszValueNameW
);
2036 /* RegSetValueEx [KERNEL.226] */
2037 DWORD
RegSetValueEx16(
2039 LPSTR lpszValueName
,
2045 dprintf_reg(stddeb
,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2046 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2048 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2051 /* RegSetValueW [ADVAPI32.171] */
2052 DWORD
RegSetValue32W(
2062 dprintf_reg(stddeb
,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2063 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2065 if (lpszSubKey
&& *lpszSubKey
) {
2066 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2067 if (ret
!=ERROR_SUCCESS
)
2071 if (dwType
!=REG_SZ
) {
2072 fprintf(stddeb
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2075 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2076 dprintf_reg(stddeb
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2077 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2079 cbData
=2*lstrlen32W(lpszData
)+2;
2081 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2087 /* RegSetValueA [ADVAPI32.168] */
2088 DWORD
RegSetValue32A(
2098 dprintf_reg(stddeb
,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2099 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2101 if (lpszSubKey
&& *lpszSubKey
) {
2102 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2103 if (ret
!=ERROR_SUCCESS
)
2108 if (dwType
!=REG_SZ
) {
2109 dprintf_reg(stddeb
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2112 if (cbData
!=strlen(lpszData
)+1)
2113 cbData
=strlen(lpszData
)+1;
2114 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2120 /* RegSetValue [KERNEL.221] [SHELL.5] */
2121 DWORD
RegSetValue16(
2129 dprintf_reg(stddeb
,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2130 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2132 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2140 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2141 * RegEnumKey32W -> RegEnumKeyEx32W
2144 /* RegEnumKeyExW [ADVAPI32.139] */
2145 DWORD
RegEnumKeyEx32W(
2150 LPDWORD lpdwReserved
,
2155 LPKEYSTRUCT lpkey
,lpxkey
;
2157 dprintf_reg(stddeb
,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2158 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2160 lpkey
=lookup_hkey(hkey
);
2162 return SHELL_ERROR_BADKEY
;
2163 if (!lpkey
->nextsub
)
2164 return ERROR_NO_MORE_ITEMS
;
2165 lpxkey
=lpkey
->nextsub
;
2166 while (iSubkey
&& lpxkey
) {
2168 lpxkey
=lpxkey
->next
;
2170 if (iSubkey
|| !lpxkey
)
2171 return ERROR_NO_MORE_ITEMS
;
2172 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2173 return ERROR_MORE_DATA
;
2174 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2176 /* what should we write into it? */
2180 return ERROR_SUCCESS
;
2184 /* RegEnumKeyW [ADVAPI32.140] */
2185 DWORD
RegEnumKey32W(
2193 dprintf_reg(stddeb
,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2194 hkey
,iSubkey
,lpszName
,lpcchName
2196 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2198 /* RegEnumKeyExA [ADVAPI32.138] */
2199 DWORD
RegEnumKeyEx32A(
2204 LPDWORD lpdwReserved
,
2209 DWORD ret
,lpcchNameW
,lpcchClassW
;
2210 LPWSTR lpszNameW
,lpszClassW
;
2213 dprintf_reg(stddeb
,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2214 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2217 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2218 lpcchNameW
= *lpcchName
*2;
2224 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2225 lpcchClassW
= *lpcchClass
*2;
2230 ret
=RegEnumKeyEx32W(
2240 if (ret
==ERROR_SUCCESS
) {
2241 strcpyWA(lpszName
,lpszNameW
);
2242 *lpcchName
=strlen(lpszName
);
2244 strcpyWA(lpszClass
,lpszClassW
);
2245 *lpcchClass
=strlen(lpszClass
);
2255 /* RegEnumKeyA [ADVAPI32.137] */
2256 DWORD
RegEnumKey32A(
2264 dprintf_reg(stddeb
,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2265 hkey
,iSubkey
,lpszName
,lpcchName
2267 return RegEnumKeyEx32A(
2279 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2286 dprintf_reg(stddeb
,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2287 hkey
,iSubkey
,lpszName
,lpcchName
2289 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2293 * Enumerate Registry Values
2296 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2299 /* RegEnumValueW [ADVAPI32.142] */
2300 DWORD
RegEnumValue32W(
2305 LPDWORD lpdReserved
,
2313 dprintf_reg(stddeb
,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2314 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2316 lpkey
= lookup_hkey(hkey
);
2318 return SHELL_ERROR_BADKEY
;
2319 if (lpkey
->nrofvalues
<=iValue
)
2320 return ERROR_NO_MORE_ITEMS
;
2321 val
= lpkey
->values
+iValue
;
2324 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2325 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2326 return ERROR_MORE_DATA
;
2328 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2329 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2331 /* how to handle NULL value? */
2335 *lpdwType
=val
->type
;
2337 if (val
->len
>*lpcbData
)
2338 return ERROR_MORE_DATA
;
2339 memcpy(lpbData
,val
->data
,val
->len
);
2340 *lpcbData
= val
->len
;
2342 return SHELL_ERROR_SUCCESS
;
2345 /* RegEnumValueA [ADVAPI32.141] */
2346 DWORD
RegEnumValue32A(
2351 LPDWORD lpdReserved
,
2358 DWORD ret
,lpcbDataW
;
2360 dprintf_reg(stddeb
,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2361 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2364 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2366 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2367 lpcbDataW
= *lpcbData
*2;
2370 ret
=RegEnumValue32W(
2381 if (ret
==ERROR_SUCCESS
) {
2382 strcpyWA(lpszValue
,lpszValueW
);
2384 if ((1<<*lpdwType
) & UNICONVMASK
) {
2385 strcpyWA(lpbData
,(LPWSTR
)lpbDataW
);
2387 if (lpcbDataW
> *lpcbData
)
2388 ret
= ERROR_MORE_DATA
;
2390 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2392 *lpcbData
= lpcbDataW
;
2402 /* RegEnumValue [KERNEL.223] */
2403 DWORD
RegEnumValue16(
2408 LPDWORD lpdReserved
,
2413 dprintf_reg(stddeb
,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2414 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2416 return RegEnumValue32A(
2429 * Close registry key
2431 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2432 DWORD
RegCloseKey(HKEY hkey
) {
2433 dprintf_reg(stddeb
,"RegCloseKey(%x)\n",hkey
);
2434 remove_handle(hkey
);
2435 return ERROR_SUCCESS
;
2438 * Delete registry key
2441 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2443 /* RegDeleteKeyW [ADVAPI32.134] */
2444 DWORD
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2445 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2449 dprintf_reg(stddeb
,"RegDeleteKey32W(%x,%s)\n",
2450 hkey
,W2C(lpszSubKey
,0)
2452 lpNextKey
= lookup_hkey(hkey
);
2454 return SHELL_ERROR_BADKEY
;
2455 /* we need to know the previous key in the hier. */
2456 if (!lpszSubKey
|| !*lpszSubKey
)
2457 return SHELL_ERROR_BADKEY
;
2458 split_keypath(lpszSubKey
,&wps
,&wpc
);
2462 lpxkey
=lpNextKey
->nextsub
;
2464 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2466 lpxkey
=lpxkey
->next
;
2470 /* not found is success */
2471 return SHELL_ERROR_SUCCESS
;
2476 lpxkey
= lpNextKey
->nextsub
;
2477 lplpPrevKey
= &(lpNextKey
->nextsub
);
2479 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2481 lplpPrevKey
= &(lpxkey
->next
);
2482 lpxkey
= lpxkey
->next
;
2485 return SHELL_ERROR_SUCCESS
;
2486 if (lpxkey
->nextsub
)
2487 return SHELL_ERROR_CANTWRITE
;
2488 *lplpPrevKey
= lpxkey
->next
;
2489 free(lpxkey
->keyname
);
2491 free(lpxkey
->class);
2493 free(lpxkey
->values
);
2496 return SHELL_ERROR_SUCCESS
;
2499 /* RegDeleteKeyA [ADVAPI32.133] */
2500 DWORD
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2504 dprintf_reg(stddeb
,"RegDeleteKey32A(%x,%s)\n",
2507 lpszSubKeyW
=strdupA2W(lpszSubKey
);
2508 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2513 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2514 DWORD
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2515 dprintf_reg(stddeb
,"RegDeleteKey16(%x,%s)\n",
2518 return RegDeleteKey32A(hkey
,lpszSubKey
);
2522 * Delete registry value
2525 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2527 /* RegDeleteValueW [ADVAPI32.136] */
2528 DWORD
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
) {
2533 dprintf_reg(stddeb
,"RegDeleteValue32W(%x,%s)\n",
2534 hkey
,W2C(lpszValue
,0)
2536 lpkey
=lookup_hkey(hkey
);
2538 return SHELL_ERROR_BADKEY
;
2540 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2541 if ( lpkey
->values
[i
].name
&&
2542 !lstrcmp32W(lpkey
->values
[i
].name
,lpszValue
)
2546 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2547 if (lpkey
->values
[i
].name
==NULL
)
2550 if (i
==lpkey
->nrofvalues
)
2551 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2552 val
= lpkey
->values
+i
;
2553 if (val
->name
) free(val
->name
);
2554 if (val
->data
) free(val
->data
);
2558 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2560 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2562 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2564 lpkey
->nrofvalues
--;
2565 return SHELL_ERROR_SUCCESS
;
2568 /* RegDeleteValueA [ADVAPI32.135] */
2569 DWORD
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
) {
2573 dprintf_reg( stddeb
, "RegDeleteValue32A(%x,%s)\n", hkey
,lpszValue
);
2575 lpszValueW
=strdupA2W(lpszValue
);
2578 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2584 /* RegDeleteValue [KERNEL.222] */
2585 DWORD
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
) {
2586 dprintf_reg( stddeb
,"RegDeleteValue16(%x,%s)\n", hkey
,lpszValue
);
2587 return RegDeleteValue32A(hkey
,lpszValue
);
2590 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2591 DWORD
RegFlushKey(HKEY hkey
) {
2592 dprintf_reg(stddeb
,"RegFlushKey(%x), STUB.\n",hkey
);
2593 return SHELL_ERROR_SUCCESS
;
2596 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2598 /* RegQueryInfoKeyW [ADVAPI32.153] */
2599 DWORD
RegQueryInfoKey32W(
2603 LPDWORD lpdwReserved
,
2605 LPDWORD lpcchMaxSubkey
,
2606 LPDWORD lpcchMaxClass
,
2608 LPDWORD lpcchMaxValueName
,
2609 LPDWORD lpccbMaxValueData
,
2610 LPDWORD lpcbSecurityDescriptor
,
2613 LPKEYSTRUCT lpkey
,lpxkey
;
2614 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2617 dprintf_reg(stddeb
,"RegQueryInfoKey32W(%x,......)\n",hkey
);
2618 lpkey
=lookup_hkey(hkey
);
2620 return SHELL_ERROR_BADKEY
;
2623 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2624 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2625 return ERROR_MORE_DATA
;
2627 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2628 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2635 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2637 lpxkey
=lpkey
->nextsub
;
2638 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2641 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2642 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2643 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2644 maxclass
=lstrlen32W(lpxkey
->class);
2645 if (lpxkey
->nrofvalues
>maxvalues
)
2646 maxvalues
=lpxkey
->nrofvalues
;
2647 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2648 LPKEYVALUE val
=lpxkey
->values
+i
;
2650 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2651 maxvname
=lstrlen32W(val
->name
);
2652 if (val
->len
>maxvdata
)
2655 lpxkey
=lpxkey
->next
;
2657 if (!maxclass
) maxclass
= 1;
2658 if (!maxvname
) maxvname
= 1;
2660 *lpcSubKeys
= nrofkeys
;
2662 *lpcchMaxSubkey
= maxsubkey
*2;
2664 *lpcchMaxClass
= maxclass
*2;
2666 *lpcValues
= maxvalues
;
2667 if (lpcchMaxValueName
)
2668 *lpcchMaxValueName
= maxvname
;
2669 if (lpccbMaxValueData
)
2670 *lpccbMaxValueData
= maxvdata
;
2671 return SHELL_ERROR_SUCCESS
;
2674 /* RegQueryInfoKeyA [ADVAPI32.152] */
2675 DWORD
RegQueryInfoKey32A(
2679 LPDWORD lpdwReserved
,
2681 LPDWORD lpcchMaxSubkey
,
2682 LPDWORD lpcchMaxClass
,
2684 LPDWORD lpcchMaxValueName
,
2685 LPDWORD lpccbMaxValueData
,
2686 LPDWORD lpcbSecurityDescriptor
,
2692 dprintf_reg(stddeb
,"RegQueryInfoKey32A(%x,......)\n",hkey
);
2695 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2699 ret
=RegQueryInfoKey32W(
2710 lpcbSecurityDescriptor
,
2713 if (ret
==ERROR_SUCCESS
)
2714 strcpyWA(lpszClass
,lpszClassW
);
2721 if (lpcchMaxValueName
)
2722 *lpcchMaxValueName
/=2;