4 * Copyright 1996 Marcus Meissner
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
30 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
32 /* FIXME: following defines should be configured global ... */
34 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
35 #define WINE_PREFIX "/.wine"
36 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
37 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
39 /* relative in ~user/.wine/ : */
40 #define SAVE_CURRENT_USER "user.reg"
41 #define SAVE_LOCAL_MACHINE "system.reg"
43 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
44 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
46 /* one value of a key */
47 typedef struct tagKEYVALUE
49 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
50 DWORD type
; /* type of value */
51 DWORD len
; /* length of data */
52 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
53 LPBYTE data
; /* content, may be strings, binaries, etc. */
54 } KEYVALUE
,*LPKEYVALUE
;
57 typedef struct tagKEYSTRUCT
59 LPWSTR keyname
; /* name of THIS key (UNICODE) */
60 DWORD flags
; /* flags. */
63 DWORD nrofvalues
; /* nr of values in THIS key */
64 LPKEYVALUE values
; /* values in THIS key */
65 /* key management pointers */
66 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
67 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
68 } KEYSTRUCT
, *LPKEYSTRUCT
;
71 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
72 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
73 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
74 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
76 /* dynamic, not saved */
77 static KEYSTRUCT
*key_performance_data
=NULL
;
78 static KEYSTRUCT
*key_current_config
=NULL
;
79 static KEYSTRUCT
*key_dyn_data
=NULL
;
81 /* what valuetypes do we need to convert? */
82 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
84 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
85 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
86 #define strdupW(x) STRING32_strdupW(x)
87 #define strcmpniW(a,b) STRING32_lstrcmpniW(a,b)
88 #define strchrW(a,c) STRING32_lstrchrW(a,c)
89 #define strcpyWA(a,b) STRING32_UniToAnsi(a,b)
91 static struct openhandle
{
96 static int nrofopenhandles
=0;
97 static int currenthandle
=1;
100 add_handle(HKEY hkey
,LPKEYSTRUCT lpkey
,REGSAM accessmask
) {
103 for (i
=0;i
<nrofopenhandles
;i
++) {
104 if (openhandles
[i
].lpkey
==lpkey
) {
105 dprintf_reg(stddeb
,"add_handle:Tried to add %p twice!\n",lpkey
);
107 if (openhandles
[i
].hkey
==hkey
) {
108 dprintf_reg(stddeb
,"add_handle:Tried to add %lx twice!\n",(LONG
)hkey
);
111 openhandles
=xrealloc( openhandles
,
112 sizeof(struct openhandle
)*(nrofopenhandles
+1)
114 openhandles
[i
].lpkey
= lpkey
;
115 openhandles
[i
].hkey
= hkey
;
116 openhandles
[i
].accessmask
= accessmask
;
121 get_handle(HKEY hkey
) {
124 for (i
=0;i
<nrofopenhandles
;i
++)
125 if (openhandles
[i
].hkey
==hkey
)
126 return openhandles
[i
].lpkey
;
127 dprintf_reg(stddeb
,"get_handle:Didn't find handle %lx?\n",(LONG
)hkey
);
132 remove_handle(HKEY hkey
) {
135 for (i
=0;i
<nrofopenhandles
;i
++)
136 if (openhandles
[i
].hkey
==hkey
)
138 if (i
==nrofopenhandles
) {
139 dprintf_reg(stddeb
,"remove_handle:Didn't find handle %08x?\n",hkey
);
142 memcpy( openhandles
+i
,
144 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
146 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
152 /* debug function, converts a unicode into a static memory area
153 * (sub for using two static strings, in case we need them in a single call)
156 W2C(LPCWSTR x
,int sub
) {
157 static LPSTR unicodedebug
[2]={NULL
,NULL
};
160 if (sub
!=0 && sub
!=1)
161 return "<W2C:bad sub>";
162 if (unicodedebug
[sub
]) free(unicodedebug
[sub
]);
163 unicodedebug
[sub
] = strdupW2A(x
);
164 return unicodedebug
[sub
];
168 lookup_hkey(HKEY hkey
) {
172 case HKEY_CLASSES_ROOT
:
173 return key_classes_root
;
174 case HKEY_CURRENT_USER
:
175 return key_current_user
;
176 case HKEY_LOCAL_MACHINE
:
177 return key_local_machine
;
180 case HKEY_PERFORMANCE_DATA
:
181 return key_performance_data
;
184 case HKEY_CURRENT_CONFIG
:
185 return key_current_config
;
187 dprintf_reg(stddeb
,"lookup_hkey(%lx), special key!\n",
190 return get_handle(hkey
);
196 * splits the unicode string 'wp' into an array of strings.
197 * the array is allocated by this function.
198 * the number of components will be stored in 'wpc'
199 * Free the array using FREE_KEY_PATH
202 split_keypath(LPCWSTR wp
,LPWSTR
**wpv
,int *wpc
) {
208 for (i
=0;ws
[i
];i
++) {
215 *wpv
= (LPWSTR
*)xmalloc(sizeof(LPWSTR
)*(*wpc
+2));
223 #define FREE_KEY_PATH free(wps[0]);free(wps);
226 * Shell initialisation, allocates keys.
228 void SHELL_StartupRegistry();
233 HKEY cl_r_hkey
,c_u_hkey
;
234 #define ADD_ROOT_KEY(xx) \
235 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
236 memset(xx,'\0',sizeof(KEYSTRUCT));\
237 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
239 ADD_ROOT_KEY(key_local_machine
);
240 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
241 fprintf(stderr
,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
244 key_classes_root
= lookup_hkey(cl_r_hkey
);
246 ADD_ROOT_KEY(key_users
);
249 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
250 * (later, when a win32 registry editing tool becomes avail.)
252 while (pwd
=getpwent()) {
253 if (pwd
->pw_name
== NULL
)
255 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
256 RegCloseKey(c_u_hkey
);
259 pwd
=getpwuid(getuid());
260 if (pwd
&& pwd
->pw_name
) {
261 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
262 key_current_user
= lookup_hkey(c_u_hkey
);
264 ADD_ROOT_KEY(key_current_user
);
266 ADD_ROOT_KEY(key_performance_data
);
267 ADD_ROOT_KEY(key_current_config
);
268 ADD_ROOT_KEY(key_dyn_data
);
270 SHELL_StartupRegistry();
275 SHELL_StartupRegistry() {
278 char buf
[200],cpubuf
[200];
280 RegCreateKey16(HKEY_DYN_DATA
,"\\PerfStats\\StatData",&xhkey
);
282 RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey
);
284 F
=fopen("/proc/cpuinfo","r");
287 while (NULL
!=fgets(buf
,200,F
)) {
288 if (sscanf(buf
,"processor\t: %d",&x
)) {
293 RegCreateKey16(hkey
,buf
,&xhkey
);
295 if (sscanf(buf
,"cpu\t\t: %s",cpubuf
)) {
296 sprintf(buf
,"CPU %s",cpubuf
);
298 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,buf
,strlen(buf
));
308 RegCreateKey16(hkey
,"0",&xhkey
);
309 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,"CPU 386",strlen("CPU 386"));
311 RegOpenKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System",&hkey
);
312 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
314 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
318 * string RegisteredOwner
319 * string RegisteredOrganization
322 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
327 if (-1!=gethostname(buf
,200)) {
328 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey
);
329 RegSetValueEx16(xhkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
333 /************************ SAVE Registry Function ****************************/
335 #define REGISTRY_SAVE_VERSION 0x00000001
337 /* Registry saveformat:
338 * If you change it, increase above number by 1, which will flush
339 * old registry database files.
342 * "WINE REGISTRY Version %d"
346 * valuename=lastmodified,type,data
350 * keyname,valuename,stringdata:
351 * the usual ascii characters from 0x00-0xff (well, not 0x00)
352 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
353 * ( "=\\\t" escaped in \uXXXX form.)
357 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
359 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
360 * SaveOnlyUpdatedKeys=yes
363 _save_check_tainted(LPKEYSTRUCT lpkey
) {
368 if (lpkey
->flags
& REG_OPTION_TAINTED
)
373 if (_save_check_tainted(lpkey
->nextsub
)) {
374 lpkey
->flags
|= REG_OPTION_TAINTED
;
383 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
396 if (escapeeq
&& *s
=='=')
399 fputc(*s
,F
); /* if \\ than put it twice. */
401 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
409 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
415 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
416 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
418 for (tabs
=level
;tabs
--;)
420 _save_USTRING(F
,lpxkey
->keyname
,1);
422 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
423 LPKEYVALUE val
=lpxkey
->values
+i
;
425 for (tabs
=level
+1;tabs
--;)
427 _save_USTRING(F
,val
->name
,0);
429 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
430 if ((1<<val
->type
) & UNICONVMASK
)
431 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
433 for (j
=0;j
<val
->len
;j
++)
434 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
437 /* descend recursively */
438 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
447 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
448 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
449 _save_check_tainted(lpkey
->nextsub
);
450 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
454 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
459 fprintf(stddeb
,__FILE__
":_savereg:Couldn't open %s for writing: %s\n",
464 if (!_savesubreg(F
,lpkey
,all
)) {
467 fprintf(stddeb
,__FILE__
":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
475 SHELL_SaveRegistry() {
483 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
489 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
501 if (lstrcmpi32A(buf
,"yes"))
503 pwd
=getpwuid(getuid());
504 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
506 char *tmp
= tmpnam(NULL
);
507 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
508 strlen(SAVE_CURRENT_USER
) + 2 );
509 strcpy(fn
,pwd
->pw_dir
);
510 strcat(fn
,WINE_PREFIX
);
511 /* create the directory. don't care about errorcodes. */
512 mkdir(fn
,0755); /* drwxr-xr-x */
513 strcat(fn
,"/"SAVE_CURRENT_USER
);
514 if (_savereg(key_current_user
,tmp
,all
)) rename(tmp
,fn
);
516 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
517 strcpy(fn
,pwd
->pw_dir
);
518 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
519 if (_savereg(key_local_machine
,tmp
,all
)) rename(tmp
,fn
);
522 fprintf(stderr
,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
525 /************************ LOAD Registry Function ****************************/
528 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
529 LPKEYSTRUCT lpxkey
,*lplpkey
;
531 lplpkey
= &(lpkey
->nextsub
);
534 if (!lstrcmp32W(lpxkey
->keyname
,keyname
))
536 lplpkey
= &(lpxkey
->next
);
540 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
542 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
543 lpxkey
->keyname
= keyname
;
551 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
557 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
563 if ( val
->name
!=NULL
&&
564 !lstrcmp32W(val
->name
,name
)
569 if (i
==lpkey
->nrofvalues
) {
570 lpkey
->values
= xrealloc(
572 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
575 memset(val
,'\0',sizeof(KEYVALUE
));
581 if (val
->lastmodified
<lastmodified
) {
582 val
->lastmodified
=lastmodified
;
593 /* reads a line including dynamically enlarging the readbuffer and throwing
597 _wine_read_line(FILE *F
,char **buf
,int *len
) {
606 s
=fgets(curread
,mylen
,F
);
609 if (NULL
==(s
=strchr(curread
,'\n'))) {
610 /* buffer wasn't large enough */
611 curoff
= strlen(*buf
);
612 *buf
= xrealloc(*buf
,*len
*2);
613 curread
= *buf
+ curoff
;
614 mylen
= *len
; /* we filled up the buffer and
615 * got new '*len' bytes to fill
623 /* throw away comments */
624 if (**buf
=='#' || **buf
==';') {
629 if (s
) /* got end of line */
635 /* converts a char* into a UNICODE string (up to a special char)
636 * and returns the position exactly after that string
639 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
643 /* read up to "=" or "\0" or "\n" */
646 /* empty string is the win3.1 default value(NULL)*/
650 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
652 while (*s
&& (*s
!='\n') && (*s
!='=')) {
654 *ws
++=*((unsigned char*)s
++);
663 fprintf(stderr
,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
671 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
672 if (!sscanf(xbuf
,"%x",&wc
))
673 fprintf(stderr
,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf
,buf
);
675 *ws
++ =(unsigned short)wc
;
681 *str
= strdupW(*str
);
688 FILE *F
,LPKEYSTRUCT lpkey
,int level
,char **buf
,int *buflen
,int optflag
695 lpkey
->flags
|= optflag
;
697 /* good. we already got a line here ... so parse it */
707 fprintf(stderr
,"_load_subkey:Got a subhierarchy without resp. key?\n");
710 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
713 /* let the caller handle this line */
714 if (i
<level
|| **buf
=='\0')
717 /* it can be: a value or a keyname. Parse the name first */
718 s
=_wine_read_USTRING(s
,&name
);
720 /* switch() default: hack to avoid gotos */
724 lpxkey
=_find_or_add_key(lpkey
,name
);
727 int len
,lastmodified
,type
;
730 fprintf(stderr
,"_wine_load_subkey:unexpected character: %c\n",*s
);
734 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
735 fprintf(stderr
,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf
);
741 if ((1<<type
) & UNICONVMASK
) {
742 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
744 len
= lstrlen32W((LPWSTR
)data
)*2+2;
749 data
= (LPBYTE
)xmalloc(len
+1);
750 for (i
=0;i
<len
;i
++) {
752 if (*s
>='0' && *s
<='9')
754 if (*s
>='a' && *s
<='f')
756 if (*s
>='A' && *s
<='F')
759 if (*s
>='0' && *s
<='9')
761 if (*s
>='a' && *s
<='f')
763 if (*s
>='A' && *s
<='F')
768 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
771 /* read the next line */
772 if (!_wine_read_line(F
,buf
,buflen
))
779 _wine_loadsubreg(FILE *F
,LPKEYSTRUCT lpkey
,int optflag
) {
784 buf
=xmalloc(10);buflen
=10;
785 if (!_wine_read_line(F
,&buf
,&buflen
)) {
789 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
793 if (ver
!=REGISTRY_SAVE_VERSION
) {
794 dprintf_reg(stddeb
,__FILE__
":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
798 if (!_wine_read_line(F
,&buf
,&buflen
)) {
802 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
811 _wine_loadreg(LPKEYSTRUCT lpkey
,char *fn
,int optflag
) {
816 dprintf_reg(stddeb
,__FILE__
":Couldn't open %s for reading: %s\n",
821 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
830 _copy_registry(LPKEYSTRUCT from
,LPKEYSTRUCT to
) {
837 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
839 for (j
=0;j
<from
->nrofvalues
;j
++) {
843 valfrom
= from
->values
+j
;
845 if (name
) name
=strdupW(name
);
846 data
=(LPBYTE
)malloc(valfrom
->len
);
847 memcpy(data
,valfrom
->data
,valfrom
->len
);
855 valfrom
->lastmodified
858 _copy_registry(from
,lpxkey
);
863 /* WINDOWS 95 REGISTRY LOADER */
865 * Structure of a win95 registry database.
869 * 8 : DWORD offset_of_RGDB_part
870 * 0C..1F: ? (someone fill in please)
875 * 4..0x1B: ? (fill in)
876 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
878 * Disk Key Entry Structure:
879 * 00: DWORD - unknown
880 * 04: DWORD - unknown
881 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
882 * 0C: DWORD - disk address of PreviousLevel Key.
883 * 10: DWORD - disk address of Next Sublevel Key.
884 * 14: DWORD - disk address of Next Key (on same level).
885 * DKEP>18: WORD - Nr, Low Significant part.
886 * 1A: WORD - Nr, High Significant part.
888 * The disk address always points to the nr part of the previous key entry
889 * of the referenced key. Don't ask me why, or even if I got this correct
890 * from staring at 1kg of hexdumps. (DKEP)
892 * The number of the entry is the low byte of the Low Significant Part ored
893 * with 0x100 * (low byte of the High Significant part)
894 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
896 * There are two minor corrections to the position of that structure.
897 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
898 * the DKE reread from there.
899 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
900 * (FIXME: slightly better explanation needed here)
904 * 04: DWORD offset to next RGDB section (perhaps WORD)
909 * 00: DWORD nextkeyoffset - offset to the next disk key structure
910 * 08: WORD nrLS - low significant part of NR
911 * 0A: WORD nrHS - high significant part of NR
912 * 0C: DWORD bytesused - bytes used in this structure.
913 * 10: WORD name_len - length of name in bytes. without \0
914 * 12: WORD nr_of_values - number of values.
915 * 14: char name[name_len] - name string. No \0.
916 * 14+name_len: disk values
917 * nextkeyoffset: ... next disk key
920 * 00: DWORD type - value type (hmm, could be WORD too)
921 * 04: DWORD - unknown, usually 0
922 * 08: WORD namelen - length of Name. 0 means name=NULL
923 * 0C: WORD datalen - length of Data.
924 * 10: char name[namelen] - name, no \0
925 * 10+namelen: BYTE data[datalen] - data, without \0 if string
926 * 10+namelen+datalen: next values or disk key
928 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
929 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
930 * structure) and reading another RGDB_section.
931 * repeat until end of file.
933 * FIXME: this description needs some serious help, yes.
936 struct _w95keyvalue
{
938 unsigned short datalen
;
948 struct _w95keyvalue
*values
;
949 unsigned long dkeaddr
;
954 struct _w95key
*prevlvl
;
955 struct _w95key
*nextsub
;
956 struct _w95key
*next
;
959 /* fast lookup table dkeaddr->nr */
961 unsigned long dkeaddr
;
967 _w95_walk_tree(LPKEYSTRUCT lpkey
,struct _w95key
*key
) {
973 if (key
->name
== NULL
) {
974 fprintf(stderr
,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
979 lpxkey
=_find_or_add_key(lpkey
,strdupA2W(key
->name
));
981 if (key
->nrofvals
<0) {
982 /* shouldn't happen */
983 fprintf(stderr
,"key %s already processed!\n",key
->name
);
987 for (i
=0;i
<key
->nrofvals
;i
++) {
991 name
= strdupA2W(key
->values
[i
].name
);
992 if (!*name
) name
= NULL
;
993 free(key
->values
[i
].name
);
995 len
= key
->values
[i
].datalen
;
996 data
= key
->values
[i
].data
;
997 if ((1<<key
->values
[i
].type
) & UNICONVMASK
) {
998 data
= (BYTE
*)strdupA2W(data
);
999 len
= lstrlen32W((LPWSTR
)data
)*2+2;
1000 free(key
->values
[i
].data
);
1005 key
->values
[i
].type
,
1008 key
->values
[i
].lastmodified
1015 key
->nrofvals
=-key
->nrofvals
-1;
1016 _w95_walk_tree(lpxkey
,key
->nextsub
);
1021 /* small helper function to adjust address offset (dkeaddrs) */
1022 static unsigned long
1023 _w95_adj_da(unsigned long dkeaddr
) {
1024 if ((dkeaddr
&0xFFF)<0x018) {
1027 diff
=0x1C-(dkeaddr
&0xFFF);
1028 return dkeaddr
+diff
;
1030 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1031 /* readjust to 0x000,
1032 * but ONLY if we are >0x1000 already
1034 if (dkeaddr
& ~0xFFF)
1035 return dkeaddr
& ~0xFFF;
1041 _w95dkecomp(struct _w95nr2da
*a
,struct _w95nr2da
*b
){return a
->dkeaddr
-b
->dkeaddr
;}
1043 static struct _w95key
*
1044 _w95dkelookup(unsigned long dkeaddr
,int n
,struct _w95nr2da
*nr2da
,struct _w95key
*keys
) {
1047 if (dkeaddr
== 0xFFFFFFFF)
1051 dkeaddr
=_w95_adj_da(dkeaddr
+0x1c);
1052 off
= (dkeaddr
-0x3c)/0x1c;
1054 if (nr2da
[(i
+off
)%n
].dkeaddr
== dkeaddr
)
1055 return keys
+nr2da
[(i
+off
)%n
].nr
;
1056 /* 0x3C happens often, just report unusual values */
1058 dprintf_reg(stddeb
,"search hasn't found dkeaddr %lx?\n",dkeaddr
);
1063 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1064 /* Disk Key Entry structure (RGKN part) */
1068 unsigned long x3
;/*usually 0xFFFFFFFF */
1069 unsigned long prevlvl
;
1070 unsigned long nextsub
;
1072 unsigned short nrLS
;
1073 unsigned short nrMS
;
1075 /* Disk Key Header structure (RGDB part) */
1077 unsigned long nextkeyoff
;
1078 unsigned short nrLS
;
1079 unsigned short nrMS
;
1080 unsigned long bytesused
;
1081 unsigned short keynamelen
;
1082 unsigned short values
;
1085 /* disk key values or nothing */
1087 /* Disk Key Value structure */
1091 unsigned short valnamelen
;
1092 unsigned short valdatalen
;
1093 /* valname, valdata */
1095 struct _w95nr2da
*nr2da
;
1100 unsigned long nr
,pos
,i
,where
,version
,rgdbsection
,end
,off_next_rgdb
;
1101 struct _w95key
*keys
;
1103 unsigned char *data
,*curdata
,*nextrgdb
;
1105 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1107 dprintf_reg(stddeb
,"Loading Win95 registry database '%s'\n",fn
);
1108 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1109 if (hfd
==HFILE_ERROR
)
1112 if (4!=_lread32(hfd
,magic
,4))
1114 if (strcmp(magic
,"CREG")) {
1115 fprintf(stddeb
,"%s is not a w95 registry.\n",fn
);
1118 if (4!=_lread32(hfd
,&version
,4))
1120 if (4!=_lread32(hfd
,&rgdbsection
,4))
1122 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1124 if (4!=_lread32(hfd
,magic
,4))
1126 if (strcmp(magic
,"RGKN")) {
1127 dprintf_reg(stddeb
,"second IFF header not RGKN, but %s\n",magic
);
1131 /* STEP 1: Keylink structures */
1132 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1137 nrofdkes
= (end
-where
)/sizeof(struct dke
)+100;
1138 data
= (char*)xmalloc(end
-where
);
1139 if ((end
-where
)!=_lread32(hfd
,data
,end
-where
))
1143 keys
= (struct _w95key
*)xmalloc(nrofdkes
* sizeof(struct _w95key
));
1144 memset(keys
,'\0',nrofdkes
*sizeof(struct _w95key
));
1145 nr2da
= (struct _w95nr2da
*)xmalloc(nrofdkes
* sizeof(struct _w95nr2da
));
1146 memset(nr2da
,'\0',nrofdkes
*sizeof(struct _w95nr2da
));
1148 for (i
=0;i
<nrofdkes
;i
++) {
1150 unsigned long dkeaddr
;
1152 pos
=curdata
-data
+0x40;
1153 memcpy(&dke
,curdata
,sizeof(dke
));
1154 curdata
+=sizeof(dke
);
1155 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1157 if ((dkeaddr
&0xFFF)<0x018) {
1160 diff
=0x1C-(dkeaddr
&0xFFF);
1162 curdata
+=diff
-sizeof(dke
);
1163 memcpy(&dke
,curdata
,sizeof(dke
));
1164 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1165 curdata
+=sizeof(dke
);
1167 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1168 /* readjust to 0x000,
1169 * but ONLY if we are >0x1000 already
1171 if (dkeaddr
& ~0xFFF)
1172 dkeaddr
= dkeaddr
& ~0xFFF;
1175 /* 0xFFFFFFFF happens often, just report unusual values */
1177 dprintf_reg(stddeb
,"nr %ld exceeds nrofdkes %d, skipping.\n",nr
,nrofdkes
);
1180 if (keys
[nr
].dkeaddr
) {
1183 for (x
=sizeof(dke
);x
--;)
1184 if (((char*)&dke
)[x
])
1187 break; /* finished reading if we got only 0 */
1189 if ( (dke
.next
!=(long)keys
[nr
].next
) ||
1190 (dke
.nextsub
!=(long)keys
[nr
].nextsub
) ||
1191 (dke
.prevlvl
!=(long)keys
[nr
].prevlvl
)
1193 dprintf_reg(stddeb
,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr
,keys
[nr
].dkeaddr
,dkeaddr
);
1198 nr2da
[i
].dkeaddr
= dkeaddr
;
1200 keys
[nr
].dkeaddr
= dkeaddr
;
1201 keys
[nr
].x1
= dke
.x1
;
1202 keys
[nr
].x2
= dke
.x2
;
1203 keys
[nr
].x3
= dke
.x3
;
1204 keys
[nr
].prevlvl
= (struct _w95key
*)dke
.prevlvl
;
1205 keys
[nr
].nextsub
= (struct _w95key
*)dke
.nextsub
;
1206 keys
[nr
].next
= (struct _w95key
*)dke
.next
;
1210 qsort(nr2da
,nrofdkes
,sizeof(nr2da
[0]),
1211 (int(*)(const void *,const void*))_w95dkecomp
);
1213 /* STEP 2: keydata & values */
1214 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1216 end
= hfdinfo
.nFileSizeLow
;
1217 lastmodified
= DOSFS_FileTimeToUnixTime(&(hfdinfo
.ftLastWriteTime
));
1219 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1221 data
= (char*)xmalloc(end
-rgdbsection
);
1222 if ((end
-rgdbsection
)!=_lread32(hfd
,data
,end
-rgdbsection
))
1226 memcpy(magic
,curdata
,4);
1227 memcpy(&off_next_rgdb
,curdata
+4,4);
1228 nextrgdb
= curdata
+off_next_rgdb
;
1229 if (strcmp(magic
,"RGDB")) {
1230 dprintf_reg(stddeb
,"third IFF header not RGDB, but %s\n",magic
);
1237 struct _w95key
*key
,xkey
;
1240 if (curdata
>=nextrgdb
) {
1242 if (!strncmp(curdata
,"RGDB",4)) {
1243 memcpy(&off_next_rgdb
,curdata
+4,4);
1244 nextrgdb
= curdata
+off_next_rgdb
;
1247 dprintf_reg(stddeb
,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata
-data
,end
-rgdbsection
);
1251 #define XREAD(whereto,len) \
1252 if ((curdata-data+len)<end) {\
1253 memcpy(whereto,curdata,len);\
1258 XREAD(&dkh
,sizeof(dkh
));
1259 nr
= dkh
.nrLS
+ (dkh
.nrMS
<<8);
1260 if ((nr
>nrofdkes
) || (dkh
.nrLS
== 0xFFFF)) {
1261 if (dkh
.nrLS
== 0xFFFF) {
1262 /* skip over key using nextkeyoff */
1263 curdata
+=dkh
.nextkeyoff
-sizeof(struct dkh
);
1266 dprintf_reg(stddeb
,"haven't found nr %ld.\n",nr
);
1268 memset(key
,'\0',sizeof(xkey
));
1272 dprintf_reg(stddeb
,"key with nr=%ld has no dkeaddr?\n",nr
);
1274 key
->nrofvals
= dkh
.values
;
1275 key
->name
= (char*)xmalloc(dkh
.keynamelen
+1);
1277 XREAD(key
->name
,dkh
.keynamelen
);
1278 key
->name
[dkh
.keynamelen
]=0;
1279 if (key
->nrofvals
) {
1280 key
->values
= (struct _w95keyvalue
*)xmalloc(
1281 sizeof(struct _w95keyvalue
)*key
->nrofvals
1283 for (i
=0;i
<key
->nrofvals
;i
++) {
1286 XREAD(&dkv
,sizeof(dkv
));
1287 key
->values
[i
].type
= dkv
.type
;
1288 key
->values
[i
].name
= (char*)xmalloc(
1291 key
->values
[i
].datalen
= dkv
.valdatalen
;
1292 key
->values
[i
].data
= (unsigned char*)xmalloc(
1295 key
->values
[i
].x1
= dkv
.x1
;
1296 XREAD(key
->values
[i
].name
,dkv
.valnamelen
);
1297 XREAD(key
->values
[i
].data
,dkv
.valdatalen
);
1298 key
->values
[i
].data
[dkv
.valdatalen
]=0;
1299 key
->values
[i
].name
[dkv
.valnamelen
]=0;
1300 key
->values
[i
].lastmodified
=lastmodified
;
1303 if (bytesread
!= dkh
.nextkeyoff
) {
1304 if (dkh
.bytesused
!= bytesread
)
1306 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread
,dkh
.nextkeyoff
,
1309 curdata
+= dkh
.nextkeyoff
-bytesread
;
1311 key
->prevlvl
= _w95dkelookup((long)key
->prevlvl
,nrofdkes
,nr2da
,keys
);
1312 key
->nextsub
= _w95dkelookup((long)key
->nextsub
,nrofdkes
,nr2da
,keys
);
1313 key
->next
= _w95dkelookup((long)key
->next
,nrofdkes
,nr2da
,keys
);
1318 _w95_walk_tree(lpkey
,keys
);
1322 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1325 reghack - windows 3.11 registry data format demo program.
1327 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1328 a combined hash table and tree description, and finally a text table.
1330 The header is obvious from the struct header. The taboff1 and taboff2
1331 fields are always 0x20, and their usage is unknown.
1333 The 8-byte entry table has various entry types.
1335 tabent[0] is a root index. The second word has the index of the root of
1337 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1338 the index of the key/value that has that hash. Data with the same
1339 hash value are on a circular list. The other three words in the
1340 hash entry are always zero.
1341 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1342 entry: dirent and keyent/valent. They are identified by context.
1343 tabent[freeidx] is the first free entry. The first word in a free entry
1344 is the index of the next free entry. The last has 0 as a link.
1345 The other three words in the free list are probably irrelevant.
1347 Entries in text table are preceeded by a word at offset-2. This word
1348 has the value (2*index)+1, where index is the referring keyent/valent
1349 entry in the table. I have no suggestion for the 2* and the +1.
1350 Following the word, there are N bytes of data, as per the keyent/valent
1351 entry length. The offset of the keyent/valent entry is from the start
1352 of the text table to the first data byte.
1354 This information is not available from Microsoft. The data format is
1355 deduced from the reg.dat file by me. Mistakes may
1356 have been made. I claim no rights and give no guarantees for this program.
1358 Tor Sjøwall, tor@sn.no
1361 /* reg.dat header format */
1362 struct _w31_header
{
1363 char cookie
[8]; /* 'SHCC3.10' */
1364 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1365 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1366 unsigned long tabcnt
; /* number of entries in index table */
1367 unsigned long textoff
; /* offset of text part */
1368 unsigned long textsize
; /* byte size of text part */
1369 unsigned short hashsize
; /* hash size */
1370 unsigned short freeidx
; /* free index */
1373 /* generic format of table entries */
1374 struct _w31_tabent
{
1375 unsigned short w0
, w1
, w2
, w3
;
1378 /* directory tabent: */
1379 struct _w31_dirent
{
1380 unsigned short sibling_idx
; /* table index of sibling dirent */
1381 unsigned short child_idx
; /* table index of child dirent */
1382 unsigned short key_idx
; /* table index of key keyent */
1383 unsigned short value_idx
; /* table index of value valent */
1387 struct _w31_keyent
{
1388 unsigned short hash_idx
; /* hash chain index for string */
1389 unsigned short refcnt
; /* reference count */
1390 unsigned short length
; /* length of string */
1391 unsigned short string_off
; /* offset of string in text table */
1395 struct _w31_valent
{
1396 unsigned short hash_idx
; /* hash chain index for string */
1397 unsigned short refcnt
; /* reference count */
1398 unsigned short length
; /* length of string */
1399 unsigned short string_off
; /* offset of string in text table */
1402 /* recursive helper function to display a directory tree */
1404 __w31_dumptree( unsigned short idx
,
1406 struct _w31_tabent
*tab
,
1407 struct _w31_header
*head
,
1409 time_t lastmodified
,
1412 struct _w31_dirent
*dir
;
1413 struct _w31_keyent
*key
;
1414 struct _w31_valent
*val
;
1417 static char tail
[400];
1420 dir
=(struct _w31_dirent
*)&tab
[idx
];
1423 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1425 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1426 tail
[key
->length
]='\0';
1427 /* all toplevel entries AND the entries in the
1428 * toplevel subdirectory belong to \SOFTWARE\Classes
1430 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1431 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1432 idx
=dir
->sibling_idx
;
1435 name
=STRING32_DupAnsiToUni(tail
);
1437 xlpkey
=_find_or_add_key(lpkey
,name
);
1439 /* only add if leaf node or valued node */
1440 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1441 if (dir
->value_idx
) {
1442 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1443 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1444 tail
[val
->length
]='\0';
1445 value
=STRING32_DupAnsiToUni(tail
);
1446 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1450 dprintf_reg(stddeb
,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx
);
1452 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1453 idx
=dir
->sibling_idx
;
1460 struct _w31_header head
;
1461 struct _w31_tabent
*tab
;
1465 BY_HANDLE_FILE_INFORMATION hfinfo
;
1466 time_t lastmodified
;
1470 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1471 if (hf
==HFILE_ERROR
)
1474 /* read & dump header */
1475 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1476 dprintf_reg(stddeb
,"_w31_loadreg:reg.dat is too short.\n");
1480 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1481 dprintf_reg(stddeb
,"_w31_loadreg:reg.dat has bad signature.\n");
1486 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1487 /* read and dump index table */
1489 if (len
!=_lread32(hf
,tab
,len
)) {
1490 dprintf_reg(stderr
,"_w31_loadreg:couldn't read %d bytes.\n",len
);
1497 txt
= xmalloc(head
.textsize
);
1498 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1499 dprintf_reg(stderr
,"_w31_loadreg:couldn't seek to textblock.\n");
1505 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1506 dprintf_reg(stderr
,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1513 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1514 dprintf_reg(stderr
,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1520 lastmodified
= DOSFS_FileTimeToUnixTime(&(hfinfo
.ftLastWriteTime
));
1522 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&hkey
)!=ERROR_SUCCESS
)
1524 lpkey
= lookup_hkey(hkey
);
1525 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1533 SHELL_LoadRegistry() {
1540 if (key_classes_root
==NULL
)
1543 /* Load windows 3.1 entries */
1545 /* Load windows 95 entries */
1546 _w95_loadreg("C:\\system.1st", key_local_machine
);
1547 _w95_loadreg("system.dat", key_local_machine
);
1548 _w95_loadreg("user.dat", key_users
);
1550 /* the global user default is loaded under HKEY_USERS\\.Default */
1551 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1552 lpkey
= lookup_hkey(hkey
);
1553 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1555 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1556 _copy_registry(lpkey
,key_current_user
);
1559 /* the global machine defaults */
1560 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1562 /* load the user saved registries */
1564 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1566 pwd
=getpwuid(getuid());
1567 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1568 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1569 strcpy(fn
,pwd
->pw_dir
);
1570 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1571 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1573 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1574 strcpy(fn
,pwd
->pw_dir
);
1575 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1576 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1579 fprintf(stderr
,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1580 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1581 DWORD junk
,type
,len
;
1585 if (( RegQueryValueEx32A(
1592 )!=ERROR_SUCCESS
) ||
1595 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1601 /********************* API FUNCTIONS ***************************************/
1605 * All functions are stubs to RegOpenKeyEx32W where all the
1608 * FIXME: security,options,desiredaccess,...
1611 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1612 * RegOpenKey32W -> RegOpenKeyEx32W
1615 /* RegOpenKeyExW [ADVAPI32.150] */
1616 DWORD
RegOpenKeyEx32W(
1623 LPKEYSTRUCT lpNextKey
,lpxkey
;
1626 dprintf_reg(stddeb
,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1627 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1630 lpNextKey
= lookup_hkey(hkey
);
1632 return SHELL_ERROR_BADKEY
;
1633 if (!lpszSubKey
|| !*lpszSubKey
) {
1634 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1635 *retkey
=currenthandle
;
1636 return SHELL_ERROR_SUCCESS
;
1638 split_keypath(lpszSubKey
,&wps
,&wpc
);
1640 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1643 lpxkey
=lpNextKey
->nextsub
;
1645 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1647 lpxkey
=lpxkey
->next
;
1651 return SHELL_ERROR_BADKEY
;
1656 add_handle(++currenthandle
,lpxkey
,samDesired
);
1657 *retkey
= currenthandle
;
1659 return SHELL_ERROR_SUCCESS
;
1662 /* RegOpenKeyW [ADVAPI32.151] */
1663 DWORD
RegOpenKey32W(
1668 dprintf_reg(stddeb
,"RegOpenKey32W(%lx,%s,%p)\n",
1669 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1671 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1675 /* RegOpenKeyExA [ADVAPI32.149] */
1676 DWORD
RegOpenKeyEx32A(
1686 dprintf_reg(stddeb
,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1687 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1690 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1693 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1699 /* RegOpenKeyA [ADVAPI32.148] */
1700 DWORD
RegOpenKey32A(
1705 dprintf_reg(stddeb
,"RegOpenKey32A(%lx,%s,%p)\n",
1706 (LONG
)hkey
,lpszSubKey
,retkey
1708 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1711 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1717 dprintf_reg(stddeb
,"RegOpenKey16(%lx,%s,%p)\n",
1718 (LONG
)hkey
,lpszSubKey
,retkey
1720 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1726 * All those functions convert their respective
1727 * arguments and call RegCreateKeyExW at the end.
1729 * FIXME: no security,no access attrib,no optionhandling yet.
1732 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1733 * RegCreateKey32W -> RegCreateKeyEx32W
1736 /* RegCreateKeyExW [ADVAPI32.131] */
1737 DWORD
RegCreateKeyEx32W(
1744 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1748 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1752 /*FIXME: handle security/access/whatever */
1753 dprintf_reg(stddeb
,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1765 lpNextKey
= lookup_hkey(hkey
);
1767 return SHELL_ERROR_BADKEY
;
1768 if (!lpszSubKey
|| !*lpszSubKey
) {
1769 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1770 *retkey
=currenthandle
;
1771 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1772 return SHELL_ERROR_SUCCESS
;
1774 split_keypath(lpszSubKey
,&wps
,&wpc
);
1776 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1779 lpxkey
=lpNextKey
->nextsub
;
1781 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1783 lpxkey
=lpxkey
->next
;
1791 add_handle(++currenthandle
,lpxkey
,samDesired
);
1792 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1793 *retkey
= currenthandle
;
1795 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1797 return SHELL_ERROR_SUCCESS
;
1799 /* good. now the hard part */
1801 lplpPrevKey
= &(lpNextKey
->nextsub
);
1802 lpxkey
= *lplpPrevKey
;
1804 lplpPrevKey
= &(lpxkey
->next
);
1805 lpxkey
= *lplpPrevKey
;
1807 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1808 if (!*lplpPrevKey
) {
1810 return SHELL_ERROR_OUTOFMEMORY
;
1812 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1813 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1814 (*lplpPrevKey
)->next
= NULL
;
1815 (*lplpPrevKey
)->nextsub
= NULL
;
1816 (*lplpPrevKey
)->values
= NULL
;
1817 (*lplpPrevKey
)->nrofvalues
= 0;
1818 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1820 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1822 (*lplpPrevKey
)->class = NULL
;
1823 lpNextKey
= *lplpPrevKey
;
1826 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1828 /*FIXME: flag handling correct? */
1829 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1831 lpNextKey
->class = strdupW(lpszClass
);
1833 lpNextKey
->class = NULL
;
1834 *retkey
= currenthandle
;
1836 *lpDispos
= REG_CREATED_NEW_KEY
;
1838 return SHELL_ERROR_SUCCESS
;
1841 /* RegCreateKeyW [ADVAPI32.132] */
1842 DWORD
RegCreateKey32W(
1849 dprintf_reg(stddeb
,"RegCreateKey32W(%lx,%s,%p)\n",
1850 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1852 ret
=RegCreateKeyEx32W(
1853 hkey
, /* key handle */
1854 lpszSubKey
, /* subkey name */
1855 0, /* reserved = 0 */
1856 NULL
, /* lpszClass? FIXME: ? */
1857 REG_OPTION_NON_VOLATILE
, /* options */
1858 KEY_ALL_ACCESS
, /* desired access attribs */
1859 NULL
, /* lpsecurity attributes */
1860 retkey
, /* lpretkey */
1861 &junk
/* disposition value */
1866 /* RegCreateKeyExA [ADVAPI32.130] */
1867 DWORD
RegCreateKeyEx32A(
1874 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1878 LPWSTR lpszSubKeyW
,lpszClassW
;
1881 dprintf_reg(stddeb
,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1893 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1897 lpszClassW
=strdupA2W(lpszClass
);
1900 ret
=RegCreateKeyEx32W(
1918 /* RegCreateKeyA [ADVAPI32.129] */
1919 DWORD
RegCreateKey32A(
1926 dprintf_reg(stddeb
,"RegCreateKey32A(%lx,%s,%p)\n",
1927 (LONG
)hkey
,lpszSubKey
,retkey
1929 return RegCreateKeyEx32A(
1930 hkey
, /* key handle */
1931 lpszSubKey
, /* subkey name */
1932 0, /* reserved = 0 */
1933 NULL
, /* lpszClass? FIXME: ? */
1934 REG_OPTION_NON_VOLATILE
,/* options */
1935 KEY_ALL_ACCESS
, /* desired access attribs */
1936 NULL
, /* lpsecurity attributes */
1937 retkey
, /* lpretkey */
1938 &junk
/* disposition value */
1942 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1943 DWORD
RegCreateKey16(
1948 dprintf_reg(stddeb
,"RegCreateKey16(%lx,%s,%p)\n",
1949 (LONG
)hkey
,lpszSubKey
,retkey
1951 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1955 * Query Value Functions
1956 * Win32 differs between keynames and valuenames.
1957 * multiple values may belong to one key, the special value
1958 * with name NULL is the default value used by the win31
1962 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1963 * RegQueryValue32W -> RegQueryValueEx32W
1966 /* RegQueryValueExW [ADVAPI32.158] */
1967 DWORD
RegQueryValueEx32W(
1969 LPWSTR lpszValueName
,
1970 LPDWORD lpdwReserved
,
1978 dprintf_reg(stddeb
,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1979 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1980 lpcbData
?*lpcbData
:0
1983 lpkey
= lookup_hkey(hkey
);
1985 return SHELL_ERROR_BADKEY
;
1986 if (lpszValueName
==NULL
) {
1987 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1988 if (lpkey
->values
[i
].name
==NULL
)
1991 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1992 if ( lpkey
->values
[i
].name
&&
1993 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
1997 if (i
==lpkey
->nrofvalues
) {
1998 if (lpszValueName
==NULL
) {
2000 *(WCHAR
*)lpbData
= 0;
2005 return SHELL_ERROR_SUCCESS
;
2007 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
2010 *lpdwType
= lpkey
->values
[i
].type
;
2011 if (lpbData
==NULL
) {
2013 return SHELL_ERROR_SUCCESS
;
2014 *lpcbData
= lpkey
->values
[i
].len
;
2015 return SHELL_ERROR_SUCCESS
;
2017 if (*lpcbData
<lpkey
->values
[i
].len
) {
2020 *lpcbData
= lpkey
->values
[i
].len
;
2021 return ERROR_MORE_DATA
;
2023 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2024 *lpcbData
= lpkey
->values
[i
].len
;
2025 return SHELL_ERROR_SUCCESS
;
2028 /* RegQueryValueW [ADVAPI32.159] */
2029 DWORD
RegQueryValue32W(
2038 dprintf_reg(stddeb
,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2039 hkey
,W2C(lpszSubKey
,0),lpszData
,
2040 lpcbData
?*lpcbData
:0
2043 /* only open subkey, if we really do descend */
2044 if (lpszSubKey
&& *lpszSubKey
) {
2045 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
2046 if (ret
!=ERROR_SUCCESS
)
2052 ret
= RegQueryValueEx32W(
2054 NULL
, /* varname NULL -> compat */
2055 NULL
, /* lpdwReserved, must be NULL */
2065 /* RegQueryValueExA [ADVAPI32.157] */
2066 DWORD
RegQueryValueEx32A(
2068 LPSTR lpszValueName
,
2069 LPDWORD lpdwReserved
,
2074 LPWSTR lpszValueNameW
;
2080 dprintf_reg(stddeb
,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2081 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2082 lpcbData
?*lpcbData
:0
2086 buf
= (LPBYTE
)xmalloc((*lpcbData
)*2);
2087 myxlen
= *lpcbData
*2;
2092 myxlen
= *lpcbData
*2;
2098 lpszValueNameW
=strdupA2W(lpszValueName
);
2100 lpszValueNameW
=NULL
;
2104 ret
=RegQueryValueEx32W(
2114 if (ret
==ERROR_SUCCESS
) {
2116 if (UNICONVMASK
& (1<<(type
))) {
2117 /* convert UNICODE to ASCII */
2118 strcpyWA(lpbData
,(LPWSTR
)buf
);
2119 *lpcbData
= myxlen
/2;
2121 if (myxlen
>*lpcbData
)
2122 ret
= ERROR_MORE_DATA
;
2124 memcpy(lpbData
,buf
,myxlen
);
2129 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2130 *lpcbData
= myxlen
/2;
2133 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2134 *lpcbData
= myxlen
/2;
2141 /* RegQueryValueEx [KERNEL.225] */
2142 DWORD
RegQueryValueEx16(
2144 LPSTR lpszValueName
,
2145 LPDWORD lpdwReserved
,
2150 dprintf_reg(stddeb
,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2151 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2152 lpcbData
?*lpcbData
:0
2154 return RegQueryValueEx32A(
2164 /* RegQueryValueA [ADVAPI32.156] */
2165 DWORD
RegQueryValue32A(
2174 dprintf_reg(stddeb
,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2175 hkey
,lpszSubKey
,lpszData
,
2176 lpcbData
?*lpcbData
:0
2179 /* only open subkey, if we really do descend */
2180 if (lpszSubKey
&& *lpszSubKey
) {
2181 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
2182 if (ret
!=ERROR_SUCCESS
)
2188 ret
= RegQueryValueEx32A(
2190 NULL
, /* lpszValueName NULL -> compat */
2191 NULL
, /* lpdwReserved, must be NULL */
2201 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2202 DWORD
RegQueryValue16(
2208 dprintf_reg(stddeb
,"RegQueryValue16(%x,%s,%p,%ld)\n",
2209 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0
2211 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2212 * anyway, so we just mask out the high 16 bit.
2213 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2216 *lpcbData
&= 0xFFFF;
2217 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2221 * Setting values of Registry keys
2224 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2225 * RegSetValue32W -> RegSetValueEx32W
2228 /* RegSetValueExW [ADVAPI32.170] */
2229 DWORD
RegSetValueEx32W(
2231 LPWSTR lpszValueName
,
2240 dprintf_reg(stddeb
,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2241 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
2243 /* we no longer care about the lpbData type here... */
2244 lpkey
= lookup_hkey(hkey
);
2246 return SHELL_ERROR_BADKEY
;
2248 lpkey
->flags
|= REG_OPTION_TAINTED
;
2250 if (lpszValueName
==NULL
) {
2251 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2252 if (lpkey
->values
[i
].name
==NULL
)
2255 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2256 if ( lpkey
->values
[i
].name
&&
2257 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
2261 if (i
==lpkey
->nrofvalues
) {
2262 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2264 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2266 lpkey
->nrofvalues
++;
2267 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2269 if (lpkey
->values
[i
].name
==NULL
)
2271 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2273 lpkey
->values
[i
].name
= NULL
;
2274 lpkey
->values
[i
].len
= cbData
;
2275 lpkey
->values
[i
].type
= dwType
;
2276 if (lpkey
->values
[i
].data
!=NULL
)
2277 free(lpkey
->values
[i
].data
);
2278 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2279 lpkey
->values
[i
].lastmodified
= time(NULL
);
2280 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2281 return SHELL_ERROR_SUCCESS
;
2284 /* RegSetValueExA [ADVAPI32.169] */
2285 DWORD
RegSetValueEx32A(
2287 LPSTR lpszValueName
,
2294 LPWSTR lpszValueNameW
;
2297 dprintf_reg(stddeb
,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2298 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2300 if ((1<<dwType
) & UNICONVMASK
) {
2301 buf
=(LPBYTE
)strdupA2W(lpbData
);
2302 cbData
=2*strlen(lpbData
)+2;
2306 lpszValueNameW
= strdupA2W(lpszValueName
);
2308 lpszValueNameW
= NULL
;
2309 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2311 free(lpszValueNameW
);
2317 /* RegSetValueEx [KERNEL.226] */
2318 DWORD
RegSetValueEx16(
2320 LPSTR lpszValueName
,
2326 dprintf_reg(stddeb
,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2327 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2329 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2332 /* RegSetValueW [ADVAPI32.171] */
2333 DWORD
RegSetValue32W(
2343 dprintf_reg(stddeb
,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2344 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2346 if (lpszSubKey
&& *lpszSubKey
) {
2347 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2348 if (ret
!=ERROR_SUCCESS
)
2352 if (dwType
!=REG_SZ
) {
2353 fprintf(stddeb
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2356 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2357 dprintf_reg(stddeb
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2358 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2360 cbData
=2*lstrlen32W(lpszData
)+2;
2362 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2368 /* RegSetValueA [ADVAPI32.168] */
2369 DWORD
RegSetValue32A(
2379 dprintf_reg(stddeb
,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2380 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2382 if (lpszSubKey
&& *lpszSubKey
) {
2383 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2384 if (ret
!=ERROR_SUCCESS
)
2389 if (dwType
!=REG_SZ
) {
2390 dprintf_reg(stddeb
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2393 if (cbData
!=strlen(lpszData
)+1)
2394 cbData
=strlen(lpszData
)+1;
2395 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2401 /* RegSetValue [KERNEL.221] [SHELL.5] */
2402 DWORD
RegSetValue16(
2410 dprintf_reg(stddeb
,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2411 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2413 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2421 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2422 * RegEnumKey32W -> RegEnumKeyEx32W
2425 /* RegEnumKeyExW [ADVAPI32.139] */
2426 DWORD
RegEnumKeyEx32W(
2431 LPDWORD lpdwReserved
,
2436 LPKEYSTRUCT lpkey
,lpxkey
;
2438 dprintf_reg(stddeb
,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2439 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2441 lpkey
=lookup_hkey(hkey
);
2443 return SHELL_ERROR_BADKEY
;
2444 if (!lpkey
->nextsub
)
2445 return ERROR_NO_MORE_ITEMS
;
2446 lpxkey
=lpkey
->nextsub
;
2447 while (iSubkey
&& lpxkey
) {
2449 lpxkey
=lpxkey
->next
;
2451 if (iSubkey
|| !lpxkey
)
2452 return ERROR_NO_MORE_ITEMS
;
2453 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2454 return ERROR_MORE_DATA
;
2455 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2457 /* what should we write into it? */
2461 return ERROR_SUCCESS
;
2465 /* RegEnumKeyW [ADVAPI32.140] */
2466 DWORD
RegEnumKey32W(
2474 dprintf_reg(stddeb
,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2475 hkey
,iSubkey
,lpszName
,lpcchName
2477 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2479 /* RegEnumKeyExA [ADVAPI32.138] */
2480 DWORD
RegEnumKeyEx32A(
2485 LPDWORD lpdwReserved
,
2490 DWORD ret
,lpcchNameW
,lpcchClassW
;
2491 LPWSTR lpszNameW
,lpszClassW
;
2494 dprintf_reg(stddeb
,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2495 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2498 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2499 lpcchNameW
= *lpcchName
*2;
2505 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2506 lpcchClassW
= *lpcchClass
*2;
2511 ret
=RegEnumKeyEx32W(
2521 if (ret
==ERROR_SUCCESS
) {
2522 strcpyWA(lpszName
,lpszNameW
);
2523 *lpcchName
=strlen(lpszName
);
2525 strcpyWA(lpszClass
,lpszClassW
);
2526 *lpcchClass
=strlen(lpszClass
);
2536 /* RegEnumKeyA [ADVAPI32.137] */
2537 DWORD
RegEnumKey32A(
2545 dprintf_reg(stddeb
,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2546 hkey
,iSubkey
,lpszName
,lpcchName
2548 return RegEnumKeyEx32A(
2560 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2567 dprintf_reg(stddeb
,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2568 hkey
,iSubkey
,lpszName
,lpcchName
2570 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2574 * Enumerate Registry Values
2577 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2580 /* RegEnumValueW [ADVAPI32.142] */
2581 DWORD
RegEnumValue32W(
2586 LPDWORD lpdReserved
,
2594 dprintf_reg(stddeb
,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2595 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2597 lpkey
= lookup_hkey(hkey
);
2599 return SHELL_ERROR_BADKEY
;
2600 if (lpkey
->nrofvalues
<=iValue
)
2601 return ERROR_NO_MORE_ITEMS
;
2602 val
= lpkey
->values
+iValue
;
2605 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2606 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2607 return ERROR_MORE_DATA
;
2609 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2610 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2612 /* how to handle NULL value? */
2616 *lpdwType
=val
->type
;
2618 if (val
->len
>*lpcbData
)
2619 return ERROR_MORE_DATA
;
2620 memcpy(lpbData
,val
->data
,val
->len
);
2621 *lpcbData
= val
->len
;
2623 return SHELL_ERROR_SUCCESS
;
2626 /* RegEnumValueA [ADVAPI32.141] */
2627 DWORD
RegEnumValue32A(
2632 LPDWORD lpdReserved
,
2639 DWORD ret
,lpcbDataW
;
2641 dprintf_reg(stddeb
,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2642 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2645 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2647 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2648 lpcbDataW
= *lpcbData
*2;
2651 ret
=RegEnumValue32W(
2662 if (ret
==ERROR_SUCCESS
) {
2663 strcpyWA(lpszValue
,lpszValueW
);
2665 if ((1<<*lpdwType
) & UNICONVMASK
) {
2666 strcpyWA(lpbData
,(LPWSTR
)lpbDataW
);
2668 if (lpcbDataW
> *lpcbData
)
2669 ret
= ERROR_MORE_DATA
;
2671 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2673 *lpcbData
= lpcbDataW
;
2683 /* RegEnumValue [KERNEL.223] */
2684 DWORD
RegEnumValue16(
2689 LPDWORD lpdReserved
,
2694 dprintf_reg(stddeb
,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2695 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2697 return RegEnumValue32A(
2710 * Close registry key
2712 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2713 DWORD
RegCloseKey(HKEY hkey
) {
2714 dprintf_reg(stddeb
,"RegCloseKey(%x)\n",hkey
);
2715 remove_handle(hkey
);
2716 return ERROR_SUCCESS
;
2719 * Delete registry key
2722 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2724 /* RegDeleteKeyW [ADVAPI32.134] */
2725 DWORD
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2726 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2730 dprintf_reg(stddeb
,"RegDeleteKey32W(%x,%s)\n",
2731 hkey
,W2C(lpszSubKey
,0)
2733 lpNextKey
= lookup_hkey(hkey
);
2735 return SHELL_ERROR_BADKEY
;
2736 /* we need to know the previous key in the hier. */
2737 if (!lpszSubKey
|| !*lpszSubKey
)
2738 return SHELL_ERROR_BADKEY
;
2739 split_keypath(lpszSubKey
,&wps
,&wpc
);
2743 lpxkey
=lpNextKey
->nextsub
;
2745 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2747 lpxkey
=lpxkey
->next
;
2751 /* not found is success */
2752 return SHELL_ERROR_SUCCESS
;
2757 lpxkey
= lpNextKey
->nextsub
;
2758 lplpPrevKey
= &(lpNextKey
->nextsub
);
2760 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2762 lplpPrevKey
= &(lpxkey
->next
);
2763 lpxkey
= lpxkey
->next
;
2766 return SHELL_ERROR_SUCCESS
;
2767 if (lpxkey
->nextsub
)
2768 return SHELL_ERROR_CANTWRITE
;
2769 *lplpPrevKey
= lpxkey
->next
;
2770 free(lpxkey
->keyname
);
2772 free(lpxkey
->class);
2774 free(lpxkey
->values
);
2777 return SHELL_ERROR_SUCCESS
;
2780 /* RegDeleteKeyA [ADVAPI32.133] */
2781 DWORD
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2785 dprintf_reg(stddeb
,"RegDeleteKey32A(%x,%s)\n",
2788 lpszSubKeyW
=strdupA2W(lpszSubKey
);
2789 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2794 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2795 DWORD
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2796 dprintf_reg(stddeb
,"RegDeleteKey16(%x,%s)\n",
2799 return RegDeleteKey32A(hkey
,lpszSubKey
);
2803 * Delete registry value
2806 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2808 /* RegDeleteValueW [ADVAPI32.136] */
2809 DWORD
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
) {
2814 dprintf_reg(stddeb
,"RegDeleteValue32W(%x,%s)\n",
2815 hkey
,W2C(lpszValue
,0)
2817 lpkey
=lookup_hkey(hkey
);
2819 return SHELL_ERROR_BADKEY
;
2821 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2822 if ( lpkey
->values
[i
].name
&&
2823 !lstrcmp32W(lpkey
->values
[i
].name
,lpszValue
)
2827 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2828 if (lpkey
->values
[i
].name
==NULL
)
2831 if (i
==lpkey
->nrofvalues
)
2832 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2833 val
= lpkey
->values
+i
;
2834 if (val
->name
) free(val
->name
);
2835 if (val
->data
) free(val
->data
);
2839 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2841 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2843 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2845 lpkey
->nrofvalues
--;
2846 return SHELL_ERROR_SUCCESS
;
2849 /* RegDeleteValueA [ADVAPI32.135] */
2850 DWORD
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
) {
2854 dprintf_reg( stddeb
, "RegDeleteValue32A(%x,%s)\n", hkey
,lpszValue
);
2856 lpszValueW
=strdupA2W(lpszValue
);
2859 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2865 /* RegDeleteValue [KERNEL.222] */
2866 DWORD
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
) {
2867 dprintf_reg( stddeb
,"RegDeleteValue16(%x,%s)\n", hkey
,lpszValue
);
2868 return RegDeleteValue32A(hkey
,lpszValue
);
2871 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2872 DWORD
RegFlushKey(HKEY hkey
) {
2873 dprintf_reg(stddeb
,"RegFlushKey(%x), STUB.\n",hkey
);
2874 return SHELL_ERROR_SUCCESS
;
2877 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2879 /* RegQueryInfoKeyW [ADVAPI32.153] */
2880 DWORD
RegQueryInfoKey32W(
2884 LPDWORD lpdwReserved
,
2886 LPDWORD lpcchMaxSubkey
,
2887 LPDWORD lpcchMaxClass
,
2889 LPDWORD lpcchMaxValueName
,
2890 LPDWORD lpccbMaxValueData
,
2891 LPDWORD lpcbSecurityDescriptor
,
2894 LPKEYSTRUCT lpkey
,lpxkey
;
2895 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2898 dprintf_reg(stddeb
,"RegQueryInfoKey32W(%x,......)\n",hkey
);
2899 lpkey
=lookup_hkey(hkey
);
2901 return SHELL_ERROR_BADKEY
;
2904 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2905 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2906 return ERROR_MORE_DATA
;
2908 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2909 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2916 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2918 lpxkey
=lpkey
->nextsub
;
2919 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2922 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2923 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2924 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2925 maxclass
=lstrlen32W(lpxkey
->class);
2926 if (lpxkey
->nrofvalues
>maxvalues
)
2927 maxvalues
=lpxkey
->nrofvalues
;
2928 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2929 LPKEYVALUE val
=lpxkey
->values
+i
;
2931 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2932 maxvname
=lstrlen32W(val
->name
);
2933 if (val
->len
>maxvdata
)
2936 lpxkey
=lpxkey
->next
;
2938 if (!maxclass
) maxclass
= 1;
2939 if (!maxvname
) maxvname
= 1;
2941 *lpcSubKeys
= nrofkeys
;
2943 *lpcchMaxSubkey
= maxsubkey
*2;
2945 *lpcchMaxClass
= maxclass
*2;
2947 *lpcValues
= maxvalues
;
2948 if (lpcchMaxValueName
)
2949 *lpcchMaxValueName
= maxvname
;
2950 if (lpccbMaxValueData
)
2951 *lpccbMaxValueData
= maxvdata
;
2952 return SHELL_ERROR_SUCCESS
;
2955 /* RegQueryInfoKeyA [ADVAPI32.152] */
2956 DWORD
RegQueryInfoKey32A(
2960 LPDWORD lpdwReserved
,
2962 LPDWORD lpcchMaxSubkey
,
2963 LPDWORD lpcchMaxClass
,
2965 LPDWORD lpcchMaxValueName
,
2966 LPDWORD lpccbMaxValueData
,
2967 LPDWORD lpcbSecurityDescriptor
,
2973 dprintf_reg(stddeb
,"RegQueryInfoKey32A(%x,......)\n",hkey
);
2976 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2980 ret
=RegQueryInfoKey32W(
2991 lpcbSecurityDescriptor
,
2994 if (ret
==ERROR_SUCCESS
)
2995 strcpyWA(lpszClass
,lpszClassW
);
3002 if (lpcchMaxValueName
)
3003 *lpcchMaxValueName
/=2;