4 * Copyright 1996 Marcus Meissner
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
31 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
33 /* FIXME: following defines should be configured global ... */
35 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
36 #define WINE_PREFIX "/.wine"
37 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
38 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
40 /* relative in ~user/.wine/ : */
41 #define SAVE_CURRENT_USER "user.reg"
42 #define SAVE_LOCAL_MACHINE "system.reg"
44 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
45 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
47 /* one value of a key */
48 typedef struct tagKEYVALUE
50 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
51 DWORD type
; /* type of value */
52 DWORD len
; /* length of data */
53 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
54 LPBYTE data
; /* content, may be strings, binaries, etc. */
55 } KEYVALUE
,*LPKEYVALUE
;
58 typedef struct tagKEYSTRUCT
60 LPWSTR keyname
; /* name of THIS key (UNICODE) */
61 DWORD flags
; /* flags. */
64 DWORD nrofvalues
; /* nr of values in THIS key */
65 LPKEYVALUE values
; /* values in THIS key */
66 /* key management pointers */
67 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
68 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
69 } KEYSTRUCT
, *LPKEYSTRUCT
;
72 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
73 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
74 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
75 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
77 /* dynamic, not saved */
78 static KEYSTRUCT
*key_performance_data
=NULL
;
79 static KEYSTRUCT
*key_current_config
=NULL
;
80 static KEYSTRUCT
*key_dyn_data
=NULL
;
82 /* what valuetypes do we need to convert? */
83 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
85 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
86 #define strdupW(x) STRING32_strdupW(x)
87 #define strchrW(a,c) STRING32_lstrchrW(a,c)
89 static struct openhandle
{
94 static int nrofopenhandles
=0;
95 static int currenthandle
=1;
98 add_handle(HKEY hkey
,LPKEYSTRUCT lpkey
,REGSAM accessmask
) {
101 for (i
=0;i
<nrofopenhandles
;i
++) {
102 if (openhandles
[i
].lpkey
==lpkey
) {
103 dprintf_reg(stddeb
,"add_handle:Tried to add %p twice!\n",lpkey
);
105 if (openhandles
[i
].hkey
==hkey
) {
106 dprintf_reg(stddeb
,"add_handle:Tried to add %lx twice!\n",(LONG
)hkey
);
109 openhandles
=xrealloc( openhandles
,
110 sizeof(struct openhandle
)*(nrofopenhandles
+1)
112 openhandles
[i
].lpkey
= lpkey
;
113 openhandles
[i
].hkey
= hkey
;
114 openhandles
[i
].accessmask
= accessmask
;
119 get_handle(HKEY hkey
) {
122 for (i
=0;i
<nrofopenhandles
;i
++)
123 if (openhandles
[i
].hkey
==hkey
)
124 return openhandles
[i
].lpkey
;
125 dprintf_reg(stddeb
,"get_handle:Didn't find handle %lx?\n",(LONG
)hkey
);
130 remove_handle(HKEY hkey
) {
133 for (i
=0;i
<nrofopenhandles
;i
++)
134 if (openhandles
[i
].hkey
==hkey
)
136 if (i
==nrofopenhandles
) {
137 dprintf_reg(stddeb
,"remove_handle:Didn't find handle %08x?\n",hkey
);
140 memcpy( openhandles
+i
,
142 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
144 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
150 /* debug function, converts a unicode into a static memory area
151 * (sub for using two static strings, in case we need them in a single call)
154 W2C(LPCWSTR x
,int sub
) {
155 static LPSTR unicodedebug
[2]={NULL
,NULL
};
158 if (sub
!=0 && sub
!=1)
159 return "<W2C:bad sub>";
160 if (unicodedebug
[sub
]) HeapFree( SystemHeap
, 0, unicodedebug
[sub
] );
161 unicodedebug
[sub
] = HEAP_strdupWtoA( SystemHeap
, 0, x
);
162 return unicodedebug
[sub
];
166 lookup_hkey(HKEY hkey
) {
170 case HKEY_CLASSES_ROOT
:
171 return key_classes_root
;
172 case HKEY_CURRENT_USER
:
173 return key_current_user
;
174 case HKEY_LOCAL_MACHINE
:
175 return key_local_machine
;
178 case HKEY_PERFORMANCE_DATA
:
179 return key_performance_data
;
182 case HKEY_CURRENT_CONFIG
:
183 return key_current_config
;
185 dprintf_reg(stddeb
,"lookup_hkey(%lx), special key!\n",
188 return get_handle(hkey
);
194 * splits the unicode string 'wp' into an array of strings.
195 * the array is allocated by this function.
196 * the number of components will be stored in 'wpc'
197 * Free the array using FREE_KEY_PATH
200 split_keypath(LPCWSTR wp
,LPWSTR
**wpv
,int *wpc
) {
206 for (i
=0;ws
[i
];i
++) {
213 *wpv
= (LPWSTR
*)xmalloc(sizeof(LPWSTR
)*(*wpc
+2));
221 #define FREE_KEY_PATH free(wps[0]);free(wps);
224 * Shell initialisation, allocates keys.
226 void SHELL_StartupRegistry();
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
);
268 SHELL_StartupRegistry();
273 SHELL_StartupRegistry() {
276 char buf
[200],cpubuf
[200];
278 RegCreateKey16(HKEY_DYN_DATA
,"\\PerfStats\\StatData",&xhkey
);
280 RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey
);
282 F
=fopen("/proc/cpuinfo","r");
285 while (NULL
!=fgets(buf
,200,F
)) {
286 if (sscanf(buf
,"processor\t: %d",&x
)) {
291 RegCreateKey16(hkey
,buf
,&xhkey
);
293 if (sscanf(buf
,"cpu\t\t: %s",cpubuf
)) {
294 sprintf(buf
,"CPU %s",cpubuf
);
296 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,buf
,strlen(buf
));
306 RegCreateKey16(hkey
,"0",&xhkey
);
307 RegSetValueEx32A(xhkey
,"Identifier",0,REG_SZ
,"CPU 386",strlen("CPU 386"));
309 RegOpenKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System",&hkey
);
310 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
312 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
316 * string RegisteredOwner
317 * string RegisteredOrganization
320 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
325 if (-1!=gethostname(buf
,200)) {
326 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey
);
327 RegSetValueEx16(xhkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
331 /************************ SAVE Registry Function ****************************/
333 #define REGISTRY_SAVE_VERSION 0x00000001
335 /* Registry saveformat:
336 * If you change it, increase above number by 1, which will flush
337 * old registry database files.
340 * "WINE REGISTRY Version %d"
344 * valuename=lastmodified,type,data
348 * keyname,valuename,stringdata:
349 * the usual ascii characters from 0x00-0xff (well, not 0x00)
350 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
351 * ( "=\\\t" escaped in \uXXXX form.)
355 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
357 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
358 * SaveOnlyUpdatedKeys=yes
361 _save_check_tainted(LPKEYSTRUCT lpkey
) {
366 if (lpkey
->flags
& REG_OPTION_TAINTED
)
371 if (_save_check_tainted(lpkey
->nextsub
)) {
372 lpkey
->flags
|= REG_OPTION_TAINTED
;
381 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
394 if (escapeeq
&& *s
=='=')
397 fputc(*s
,F
); /* if \\ than put it twice. */
399 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
407 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
413 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
414 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
416 for (tabs
=level
;tabs
--;)
418 _save_USTRING(F
,lpxkey
->keyname
,1);
420 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
421 LPKEYVALUE val
=lpxkey
->values
+i
;
423 for (tabs
=level
+1;tabs
--;)
425 _save_USTRING(F
,val
->name
,0);
427 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
428 if ((1<<val
->type
) & UNICONVMASK
)
429 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
431 for (j
=0;j
<val
->len
;j
++)
432 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
435 /* descend recursively */
436 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
445 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
446 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
447 _save_check_tainted(lpkey
->nextsub
);
448 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
452 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
457 fprintf(stddeb
,__FILE__
":_savereg:Couldn't open %s for writing: %s\n",
462 if (!_savesubreg(F
,lpkey
,all
)) {
465 fprintf(stddeb
,__FILE__
":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
473 SHELL_SaveRegistry() {
481 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
487 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
499 if (lstrcmpi32A(buf
,"yes"))
501 pwd
=getpwuid(getuid());
502 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
506 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
507 strlen(SAVE_CURRENT_USER
) + 2 );
508 strcpy(fn
,pwd
->pw_dir
);
509 strcat(fn
,WINE_PREFIX
);
510 /* create the directory. don't care about errorcodes. */
511 mkdir(fn
,0755); /* drwxr-xr-x */
512 strcat(fn
,"/"SAVE_CURRENT_USER
);
513 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
514 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
515 if (_savereg(key_current_user
,tmp
,all
)) {
516 if (-1==rename(tmp
,fn
)) {
517 perror("rename tmp registry");
523 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
524 strcpy(fn
,pwd
->pw_dir
);
525 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
526 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
527 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
528 if (_savereg(key_local_machine
,tmp
,all
)) {
529 if (-1==rename(tmp
,fn
)) {
530 perror("rename tmp registry");
537 fprintf(stderr
,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
540 /************************ LOAD Registry Function ****************************/
543 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
544 LPKEYSTRUCT lpxkey
,*lplpkey
;
546 lplpkey
= &(lpkey
->nextsub
);
549 if (!lstrcmp32W(lpxkey
->keyname
,keyname
))
551 lplpkey
= &(lpxkey
->next
);
555 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
557 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
558 lpxkey
->keyname
= keyname
;
566 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
572 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
578 if ( val
->name
!=NULL
&&
579 !lstrcmp32W(val
->name
,name
)
584 if (i
==lpkey
->nrofvalues
) {
585 lpkey
->values
= xrealloc(
587 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
590 memset(val
,'\0',sizeof(KEYVALUE
));
596 if (val
->lastmodified
<lastmodified
) {
597 val
->lastmodified
=lastmodified
;
608 /* reads a line including dynamically enlarging the readbuffer and throwing
612 _wine_read_line(FILE *F
,char **buf
,int *len
) {
621 s
=fgets(curread
,mylen
,F
);
624 if (NULL
==(s
=strchr(curread
,'\n'))) {
625 /* buffer wasn't large enough */
626 curoff
= strlen(*buf
);
627 *buf
= xrealloc(*buf
,*len
*2);
628 curread
= *buf
+ curoff
;
629 mylen
= *len
; /* we filled up the buffer and
630 * got new '*len' bytes to fill
638 /* throw away comments */
639 if (**buf
=='#' || **buf
==';') {
644 if (s
) /* got end of line */
650 /* converts a char* into a UNICODE string (up to a special char)
651 * and returns the position exactly after that string
654 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
658 /* read up to "=" or "\0" or "\n" */
661 /* empty string is the win3.1 default value(NULL)*/
665 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
667 while (*s
&& (*s
!='\n') && (*s
!='=')) {
669 *ws
++=*((unsigned char*)s
++);
678 fprintf(stderr
,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
686 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
687 if (!sscanf(xbuf
,"%x",&wc
))
688 fprintf(stderr
,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf
,buf
);
690 *ws
++ =(unsigned short)wc
;
696 *str
= strdupW(*str
);
703 FILE *F
,LPKEYSTRUCT lpkey
,int level
,char **buf
,int *buflen
,int optflag
710 lpkey
->flags
|= optflag
;
712 /* good. we already got a line here ... so parse it */
722 fprintf(stderr
,"_load_subkey:Got a subhierarchy without resp. key?\n");
725 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
728 /* let the caller handle this line */
729 if (i
<level
|| **buf
=='\0')
732 /* it can be: a value or a keyname. Parse the name first */
733 s
=_wine_read_USTRING(s
,&name
);
735 /* switch() default: hack to avoid gotos */
739 lpxkey
=_find_or_add_key(lpkey
,name
);
742 int len
,lastmodified
,type
;
745 fprintf(stderr
,"_wine_load_subkey:unexpected character: %c\n",*s
);
749 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
750 fprintf(stderr
,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf
);
756 if ((1<<type
) & UNICONVMASK
) {
757 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
759 len
= lstrlen32W((LPWSTR
)data
)*2+2;
764 data
= (LPBYTE
)xmalloc(len
+1);
765 for (i
=0;i
<len
;i
++) {
767 if (*s
>='0' && *s
<='9')
769 if (*s
>='a' && *s
<='f')
771 if (*s
>='A' && *s
<='F')
774 if (*s
>='0' && *s
<='9')
776 if (*s
>='a' && *s
<='f')
778 if (*s
>='A' && *s
<='F')
783 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
786 /* read the next line */
787 if (!_wine_read_line(F
,buf
,buflen
))
794 _wine_loadsubreg(FILE *F
,LPKEYSTRUCT lpkey
,int optflag
) {
799 buf
=xmalloc(10);buflen
=10;
800 if (!_wine_read_line(F
,&buf
,&buflen
)) {
804 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
808 if (ver
!=REGISTRY_SAVE_VERSION
) {
809 dprintf_reg(stddeb
,__FILE__
":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
813 if (!_wine_read_line(F
,&buf
,&buflen
)) {
817 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
826 _wine_loadreg(LPKEYSTRUCT lpkey
,char *fn
,int optflag
) {
831 dprintf_reg(stddeb
,__FILE__
":Couldn't open %s for reading: %s\n",
836 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
845 _copy_registry(LPKEYSTRUCT from
,LPKEYSTRUCT to
) {
852 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
854 for (j
=0;j
<from
->nrofvalues
;j
++) {
858 valfrom
= from
->values
+j
;
860 if (name
) name
=strdupW(name
);
861 data
=(LPBYTE
)malloc(valfrom
->len
);
862 memcpy(data
,valfrom
->data
,valfrom
->len
);
870 valfrom
->lastmodified
873 _copy_registry(from
,lpxkey
);
878 /* WINDOWS 95 REGISTRY LOADER */
880 * Structure of a win95 registry database.
884 * 8 : DWORD offset_of_RGDB_part
885 * 0C..1F: ? (someone fill in please)
890 * 4..0x1B: ? (fill in)
891 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
893 * Disk Key Entry Structure:
894 * 00: DWORD - unknown
895 * 04: DWORD - unknown
896 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
897 * 0C: DWORD - disk address of PreviousLevel Key.
898 * 10: DWORD - disk address of Next Sublevel Key.
899 * 14: DWORD - disk address of Next Key (on same level).
900 * DKEP>18: WORD - Nr, Low Significant part.
901 * 1A: WORD - Nr, High Significant part.
903 * The disk address always points to the nr part of the previous key entry
904 * of the referenced key. Don't ask me why, or even if I got this correct
905 * from staring at 1kg of hexdumps. (DKEP)
907 * The number of the entry is the low byte of the Low Significant Part ored
908 * with 0x100 * (low byte of the High Significant part)
909 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
911 * There are two minor corrections to the position of that structure.
912 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
913 * the DKE reread from there.
914 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
915 * (FIXME: slightly better explanation needed here)
919 * 04: DWORD offset to next RGDB section (perhaps WORD)
924 * 00: DWORD nextkeyoffset - offset to the next disk key structure
925 * 08: WORD nrLS - low significant part of NR
926 * 0A: WORD nrHS - high significant part of NR
927 * 0C: DWORD bytesused - bytes used in this structure.
928 * 10: WORD name_len - length of name in bytes. without \0
929 * 12: WORD nr_of_values - number of values.
930 * 14: char name[name_len] - name string. No \0.
931 * 14+name_len: disk values
932 * nextkeyoffset: ... next disk key
935 * 00: DWORD type - value type (hmm, could be WORD too)
936 * 04: DWORD - unknown, usually 0
937 * 08: WORD namelen - length of Name. 0 means name=NULL
938 * 0C: WORD datalen - length of Data.
939 * 10: char name[namelen] - name, no \0
940 * 10+namelen: BYTE data[datalen] - data, without \0 if string
941 * 10+namelen+datalen: next values or disk key
943 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
944 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
945 * structure) and reading another RGDB_section.
946 * repeat until end of file.
948 * FIXME: this description needs some serious help, yes.
951 struct _w95keyvalue
{
953 unsigned short datalen
;
963 struct _w95keyvalue
*values
;
964 unsigned long dkeaddr
;
969 struct _w95key
*prevlvl
;
970 struct _w95key
*nextsub
;
971 struct _w95key
*next
;
974 /* fast lookup table dkeaddr->nr */
976 unsigned long dkeaddr
;
982 _w95_walk_tree(LPKEYSTRUCT lpkey
,struct _w95key
*key
) {
988 if (key
->name
== NULL
) {
989 fprintf(stderr
,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
994 lpxkey
=_find_or_add_key(lpkey
,strdupA2W(key
->name
));
996 if (key
->nrofvals
<0) {
997 /* shouldn't happen */
998 fprintf(stderr
,"key %s already processed!\n",key
->name
);
1002 for (i
=0;i
<key
->nrofvals
;i
++) {
1006 name
= strdupA2W(key
->values
[i
].name
);
1007 if (!*name
) name
= NULL
;
1008 free(key
->values
[i
].name
);
1010 len
= key
->values
[i
].datalen
;
1011 data
= key
->values
[i
].data
;
1012 if ((1<<key
->values
[i
].type
) & UNICONVMASK
) {
1013 data
= (BYTE
*)strdupA2W(data
);
1014 len
= lstrlen32W((LPWSTR
)data
)*2+2;
1015 free(key
->values
[i
].data
);
1020 key
->values
[i
].type
,
1023 key
->values
[i
].lastmodified
1030 key
->nrofvals
=-key
->nrofvals
-1;
1031 _w95_walk_tree(lpxkey
,key
->nextsub
);
1036 /* small helper function to adjust address offset (dkeaddrs) */
1037 static unsigned long
1038 _w95_adj_da(unsigned long dkeaddr
) {
1039 if ((dkeaddr
&0xFFF)<0x018) {
1042 diff
=0x1C-(dkeaddr
&0xFFF);
1043 return dkeaddr
+diff
;
1045 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1046 /* readjust to 0x000,
1047 * but ONLY if we are >0x1000 already
1049 if (dkeaddr
& ~0xFFF)
1050 return dkeaddr
& ~0xFFF;
1056 _w95dkecomp(struct _w95nr2da
*a
,struct _w95nr2da
*b
){return a
->dkeaddr
-b
->dkeaddr
;}
1058 static struct _w95key
*
1059 _w95dkelookup(unsigned long dkeaddr
,int n
,struct _w95nr2da
*nr2da
,struct _w95key
*keys
) {
1062 if (dkeaddr
== 0xFFFFFFFF)
1066 dkeaddr
=_w95_adj_da(dkeaddr
+0x1c);
1067 off
= (dkeaddr
-0x3c)/0x1c;
1069 if (nr2da
[(i
+off
)%n
].dkeaddr
== dkeaddr
)
1070 return keys
+nr2da
[(i
+off
)%n
].nr
;
1071 /* 0x3C happens often, just report unusual values */
1073 dprintf_reg(stddeb
,"search hasn't found dkeaddr %lx?\n",dkeaddr
);
1078 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1079 /* Disk Key Entry structure (RGKN part) */
1083 unsigned long x3
;/*usually 0xFFFFFFFF */
1084 unsigned long prevlvl
;
1085 unsigned long nextsub
;
1087 unsigned short nrLS
;
1088 unsigned short nrMS
;
1090 /* Disk Key Header structure (RGDB part) */
1092 unsigned long nextkeyoff
;
1093 unsigned short nrLS
;
1094 unsigned short nrMS
;
1095 unsigned long bytesused
;
1096 unsigned short keynamelen
;
1097 unsigned short values
;
1100 /* disk key values or nothing */
1102 /* Disk Key Value structure */
1106 unsigned short valnamelen
;
1107 unsigned short valdatalen
;
1108 /* valname, valdata */
1110 struct _w95nr2da
*nr2da
;
1115 unsigned long nr
,pos
,i
,where
,version
,rgdbsection
,end
,off_next_rgdb
;
1116 struct _w95key
*keys
;
1118 unsigned char *data
,*curdata
,*nextrgdb
;
1120 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1122 dprintf_reg(stddeb
,"Loading Win95 registry database '%s'\n",fn
);
1123 hfd
=OpenFile(fn
,&ofs
,OF_READ
);
1124 if (hfd
==HFILE_ERROR
)
1127 if (4!=_lread32(hfd
,magic
,4))
1129 if (strcmp(magic
,"CREG")) {
1130 fprintf(stddeb
,"%s is not a w95 registry.\n",fn
);
1133 if (4!=_lread32(hfd
,&version
,4))
1135 if (4!=_lread32(hfd
,&rgdbsection
,4))
1137 if (-1==_llseek(hfd
,0x20,SEEK_SET
))
1139 if (4!=_lread32(hfd
,magic
,4))
1141 if (strcmp(magic
,"RGKN")) {
1142 dprintf_reg(stddeb
,"second IFF header not RGKN, but %s\n",magic
);
1146 /* STEP 1: Keylink structures */
1147 if (-1==_llseek(hfd
,0x40,SEEK_SET
))
1152 nrofdkes
= (end
-where
)/sizeof(struct dke
)+100;
1153 data
= (char*)xmalloc(end
-where
);
1154 if ((end
-where
)!=_lread32(hfd
,data
,end
-where
))
1158 keys
= (struct _w95key
*)xmalloc(nrofdkes
* sizeof(struct _w95key
));
1159 memset(keys
,'\0',nrofdkes
*sizeof(struct _w95key
));
1160 nr2da
= (struct _w95nr2da
*)xmalloc(nrofdkes
* sizeof(struct _w95nr2da
));
1161 memset(nr2da
,'\0',nrofdkes
*sizeof(struct _w95nr2da
));
1163 for (i
=0;i
<nrofdkes
;i
++) {
1165 unsigned long dkeaddr
;
1167 pos
=curdata
-data
+0x40;
1168 memcpy(&dke
,curdata
,sizeof(dke
));
1169 curdata
+=sizeof(dke
);
1170 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1172 if ((dkeaddr
&0xFFF)<0x018) {
1175 diff
=0x1C-(dkeaddr
&0xFFF);
1177 curdata
+=diff
-sizeof(dke
);
1178 memcpy(&dke
,curdata
,sizeof(dke
));
1179 nr
= dke
.nrLS
+ (dke
.nrMS
<<8);
1180 curdata
+=sizeof(dke
);
1182 if (((dkeaddr
+0x1C)&0xFFF)<0x1C) {
1183 /* readjust to 0x000,
1184 * but ONLY if we are >0x1000 already
1186 if (dkeaddr
& ~0xFFF)
1187 dkeaddr
= dkeaddr
& ~0xFFF;
1190 /* 0xFFFFFFFF happens often, just report unusual values */
1192 dprintf_reg(stddeb
,"nr %ld exceeds nrofdkes %d, skipping.\n",nr
,nrofdkes
);
1195 if (keys
[nr
].dkeaddr
) {
1198 for (x
=sizeof(dke
);x
--;)
1199 if (((char*)&dke
)[x
])
1202 break; /* finished reading if we got only 0 */
1204 if ( (dke
.next
!=(long)keys
[nr
].next
) ||
1205 (dke
.nextsub
!=(long)keys
[nr
].nextsub
) ||
1206 (dke
.prevlvl
!=(long)keys
[nr
].prevlvl
)
1208 dprintf_reg(stddeb
,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr
,keys
[nr
].dkeaddr
,dkeaddr
);
1213 nr2da
[i
].dkeaddr
= dkeaddr
;
1215 keys
[nr
].dkeaddr
= dkeaddr
;
1216 keys
[nr
].x1
= dke
.x1
;
1217 keys
[nr
].x2
= dke
.x2
;
1218 keys
[nr
].x3
= dke
.x3
;
1219 keys
[nr
].prevlvl
= (struct _w95key
*)dke
.prevlvl
;
1220 keys
[nr
].nextsub
= (struct _w95key
*)dke
.nextsub
;
1221 keys
[nr
].next
= (struct _w95key
*)dke
.next
;
1225 qsort(nr2da
,nrofdkes
,sizeof(nr2da
[0]),
1226 (int(*)(const void *,const void*))_w95dkecomp
);
1228 /* STEP 2: keydata & values */
1229 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1231 end
= hfdinfo
.nFileSizeLow
;
1232 lastmodified
= DOSFS_FileTimeToUnixTime(&(hfdinfo
.ftLastWriteTime
));
1234 if (-1==_llseek(hfd
,rgdbsection
,SEEK_SET
))
1236 data
= (char*)xmalloc(end
-rgdbsection
);
1237 if ((end
-rgdbsection
)!=_lread32(hfd
,data
,end
-rgdbsection
))
1241 memcpy(magic
,curdata
,4);
1242 memcpy(&off_next_rgdb
,curdata
+4,4);
1243 nextrgdb
= curdata
+off_next_rgdb
;
1244 if (strcmp(magic
,"RGDB")) {
1245 dprintf_reg(stddeb
,"third IFF header not RGDB, but %s\n",magic
);
1252 struct _w95key
*key
,xkey
;
1255 if (curdata
>=nextrgdb
) {
1257 if (!strncmp(curdata
,"RGDB",4)) {
1258 memcpy(&off_next_rgdb
,curdata
+4,4);
1259 nextrgdb
= curdata
+off_next_rgdb
;
1262 dprintf_reg(stddeb
,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata
-data
,end
-rgdbsection
);
1266 #define XREAD(whereto,len) \
1267 if ((curdata-data+len)<end) {\
1268 memcpy(whereto,curdata,len);\
1273 XREAD(&dkh
,sizeof(dkh
));
1274 nr
= dkh
.nrLS
+ (dkh
.nrMS
<<8);
1275 if ((nr
>nrofdkes
) || (dkh
.nrLS
== 0xFFFF)) {
1276 if (dkh
.nrLS
== 0xFFFF) {
1277 /* skip over key using nextkeyoff */
1278 curdata
+=dkh
.nextkeyoff
-sizeof(struct dkh
);
1281 dprintf_reg(stddeb
,"haven't found nr %ld.\n",nr
);
1283 memset(key
,'\0',sizeof(xkey
));
1287 dprintf_reg(stddeb
,"key with nr=%ld has no dkeaddr?\n",nr
);
1289 key
->nrofvals
= dkh
.values
;
1290 key
->name
= (char*)xmalloc(dkh
.keynamelen
+1);
1292 XREAD(key
->name
,dkh
.keynamelen
);
1293 key
->name
[dkh
.keynamelen
]=0;
1294 if (key
->nrofvals
) {
1295 key
->values
= (struct _w95keyvalue
*)xmalloc(
1296 sizeof(struct _w95keyvalue
)*key
->nrofvals
1298 for (i
=0;i
<key
->nrofvals
;i
++) {
1301 XREAD(&dkv
,sizeof(dkv
));
1302 key
->values
[i
].type
= dkv
.type
;
1303 key
->values
[i
].name
= (char*)xmalloc(
1306 key
->values
[i
].datalen
= dkv
.valdatalen
;
1307 key
->values
[i
].data
= (unsigned char*)xmalloc(
1310 key
->values
[i
].x1
= dkv
.x1
;
1311 XREAD(key
->values
[i
].name
,dkv
.valnamelen
);
1312 XREAD(key
->values
[i
].data
,dkv
.valdatalen
);
1313 key
->values
[i
].data
[dkv
.valdatalen
]=0;
1314 key
->values
[i
].name
[dkv
.valnamelen
]=0;
1315 key
->values
[i
].lastmodified
=lastmodified
;
1318 if (bytesread
!= dkh
.nextkeyoff
) {
1319 if (dkh
.bytesused
!= bytesread
)
1321 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread
,dkh
.nextkeyoff
,
1324 curdata
+= dkh
.nextkeyoff
-bytesread
;
1326 key
->prevlvl
= _w95dkelookup((long)key
->prevlvl
,nrofdkes
,nr2da
,keys
);
1327 key
->nextsub
= _w95dkelookup((long)key
->nextsub
,nrofdkes
,nr2da
,keys
);
1328 key
->next
= _w95dkelookup((long)key
->next
,nrofdkes
,nr2da
,keys
);
1333 _w95_walk_tree(lpkey
,keys
);
1337 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1340 reghack - windows 3.11 registry data format demo program.
1342 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1343 a combined hash table and tree description, and finally a text table.
1345 The header is obvious from the struct header. The taboff1 and taboff2
1346 fields are always 0x20, and their usage is unknown.
1348 The 8-byte entry table has various entry types.
1350 tabent[0] is a root index. The second word has the index of the root of
1352 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1353 the index of the key/value that has that hash. Data with the same
1354 hash value are on a circular list. The other three words in the
1355 hash entry are always zero.
1356 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1357 entry: dirent and keyent/valent. They are identified by context.
1358 tabent[freeidx] is the first free entry. The first word in a free entry
1359 is the index of the next free entry. The last has 0 as a link.
1360 The other three words in the free list are probably irrelevant.
1362 Entries in text table are preceeded by a word at offset-2. This word
1363 has the value (2*index)+1, where index is the referring keyent/valent
1364 entry in the table. I have no suggestion for the 2* and the +1.
1365 Following the word, there are N bytes of data, as per the keyent/valent
1366 entry length. The offset of the keyent/valent entry is from the start
1367 of the text table to the first data byte.
1369 This information is not available from Microsoft. The data format is
1370 deduced from the reg.dat file by me. Mistakes may
1371 have been made. I claim no rights and give no guarantees for this program.
1373 Tor Sjøwall, tor@sn.no
1376 /* reg.dat header format */
1377 struct _w31_header
{
1378 char cookie
[8]; /* 'SHCC3.10' */
1379 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1380 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1381 unsigned long tabcnt
; /* number of entries in index table */
1382 unsigned long textoff
; /* offset of text part */
1383 unsigned long textsize
; /* byte size of text part */
1384 unsigned short hashsize
; /* hash size */
1385 unsigned short freeidx
; /* free index */
1388 /* generic format of table entries */
1389 struct _w31_tabent
{
1390 unsigned short w0
, w1
, w2
, w3
;
1393 /* directory tabent: */
1394 struct _w31_dirent
{
1395 unsigned short sibling_idx
; /* table index of sibling dirent */
1396 unsigned short child_idx
; /* table index of child dirent */
1397 unsigned short key_idx
; /* table index of key keyent */
1398 unsigned short value_idx
; /* table index of value valent */
1402 struct _w31_keyent
{
1403 unsigned short hash_idx
; /* hash chain index for string */
1404 unsigned short refcnt
; /* reference count */
1405 unsigned short length
; /* length of string */
1406 unsigned short string_off
; /* offset of string in text table */
1410 struct _w31_valent
{
1411 unsigned short hash_idx
; /* hash chain index for string */
1412 unsigned short refcnt
; /* reference count */
1413 unsigned short length
; /* length of string */
1414 unsigned short string_off
; /* offset of string in text table */
1417 /* recursive helper function to display a directory tree */
1419 __w31_dumptree( unsigned short idx
,
1421 struct _w31_tabent
*tab
,
1422 struct _w31_header
*head
,
1424 time_t lastmodified
,
1427 struct _w31_dirent
*dir
;
1428 struct _w31_keyent
*key
;
1429 struct _w31_valent
*val
;
1430 LPKEYSTRUCT xlpkey
= NULL
;
1432 static char tail
[400];
1435 dir
=(struct _w31_dirent
*)&tab
[idx
];
1438 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1440 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1441 tail
[key
->length
]='\0';
1442 /* all toplevel entries AND the entries in the
1443 * toplevel subdirectory belong to \SOFTWARE\Classes
1445 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1446 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1447 idx
=dir
->sibling_idx
;
1450 name
=STRING32_DupAnsiToUni(tail
);
1452 xlpkey
=_find_or_add_key(lpkey
,name
);
1454 /* only add if leaf node or valued node */
1455 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1456 if (dir
->value_idx
) {
1457 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1458 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1459 tail
[val
->length
]='\0';
1460 value
=STRING32_DupAnsiToUni(tail
);
1461 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1465 dprintf_reg(stddeb
,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx
);
1467 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1468 idx
=dir
->sibling_idx
;
1475 struct _w31_header head
;
1476 struct _w31_tabent
*tab
;
1480 BY_HANDLE_FILE_INFORMATION hfinfo
;
1481 time_t lastmodified
;
1485 hf
= OpenFile("reg.dat",&ofs
,OF_READ
);
1486 if (hf
==HFILE_ERROR
)
1489 /* read & dump header */
1490 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1491 dprintf_reg(stddeb
,"_w31_loadreg:reg.dat is too short.\n");
1495 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1496 dprintf_reg(stddeb
,"_w31_loadreg:reg.dat has bad signature.\n");
1501 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1502 /* read and dump index table */
1504 if (len
!=_lread32(hf
,tab
,len
)) {
1505 dprintf_reg(stderr
,"_w31_loadreg:couldn't read %d bytes.\n",len
);
1512 txt
= xmalloc(head
.textsize
);
1513 if (-1==_llseek(hf
,head
.textoff
,SEEK_SET
)) {
1514 dprintf_reg(stderr
,"_w31_loadreg:couldn't seek to textblock.\n");
1520 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1521 dprintf_reg(stderr
,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1528 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1529 dprintf_reg(stderr
,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1535 lastmodified
= DOSFS_FileTimeToUnixTime(&(hfinfo
.ftLastWriteTime
));
1537 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&hkey
)!=ERROR_SUCCESS
)
1539 lpkey
= lookup_hkey(hkey
);
1540 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1548 SHELL_LoadRegistry() {
1555 if (key_classes_root
==NULL
)
1558 /* Load windows 3.1 entries */
1560 /* Load windows 95 entries */
1561 _w95_loadreg("C:\\system.1st", key_local_machine
);
1562 _w95_loadreg("system.dat", key_local_machine
);
1563 _w95_loadreg("user.dat", key_users
);
1565 /* the global user default is loaded under HKEY_USERS\\.Default */
1566 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1567 lpkey
= lookup_hkey(hkey
);
1568 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1570 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1571 _copy_registry(lpkey
,key_current_user
);
1574 /* the global machine defaults */
1575 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1577 /* load the user saved registries */
1579 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1581 pwd
=getpwuid(getuid());
1582 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1583 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1584 strcpy(fn
,pwd
->pw_dir
);
1585 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1586 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1588 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1589 strcpy(fn
,pwd
->pw_dir
);
1590 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1591 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1594 fprintf(stderr
,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1595 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1596 DWORD junk
,type
,len
;
1600 if (( RegQueryValueEx32A(
1607 )!=ERROR_SUCCESS
) ||
1610 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1616 /********************* API FUNCTIONS ***************************************/
1620 * All functions are stubs to RegOpenKeyEx32W where all the
1623 * FIXME: security,options,desiredaccess,...
1626 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1627 * RegOpenKey32W -> RegOpenKeyEx32W
1630 /* RegOpenKeyExW [ADVAPI32.150] */
1631 DWORD
RegOpenKeyEx32W(
1638 LPKEYSTRUCT lpNextKey
,lpxkey
;
1641 dprintf_reg(stddeb
,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1642 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1645 lpNextKey
= lookup_hkey(hkey
);
1647 return SHELL_ERROR_BADKEY
;
1648 if (!lpszSubKey
|| !*lpszSubKey
) {
1649 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1650 *retkey
=currenthandle
;
1651 return SHELL_ERROR_SUCCESS
;
1653 split_keypath(lpszSubKey
,&wps
,&wpc
);
1655 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1658 lpxkey
=lpNextKey
->nextsub
;
1660 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1662 lpxkey
=lpxkey
->next
;
1666 return SHELL_ERROR_BADKEY
;
1671 add_handle(++currenthandle
,lpxkey
,samDesired
);
1672 *retkey
= currenthandle
;
1674 return SHELL_ERROR_SUCCESS
;
1677 /* RegOpenKeyW [ADVAPI32.151] */
1678 DWORD
RegOpenKey32W(
1683 dprintf_reg(stddeb
,"RegOpenKey32W(%lx,%s,%p)\n",
1684 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1686 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1690 /* RegOpenKeyExA [ADVAPI32.149] */
1691 DWORD
RegOpenKeyEx32A(
1701 dprintf_reg(stddeb
,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1702 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1705 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1708 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1714 /* RegOpenKeyA [ADVAPI32.148] */
1715 DWORD
RegOpenKey32A(
1720 dprintf_reg(stddeb
,"RegOpenKey32A(%lx,%s,%p)\n",
1721 (LONG
)hkey
,lpszSubKey
,retkey
1723 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1726 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1732 dprintf_reg(stddeb
,"RegOpenKey16(%lx,%s,%p)\n",
1733 (LONG
)hkey
,lpszSubKey
,retkey
1735 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1741 * All those functions convert their respective
1742 * arguments and call RegCreateKeyExW at the end.
1744 * FIXME: no security,no access attrib,no optionhandling yet.
1747 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1748 * RegCreateKey32W -> RegCreateKeyEx32W
1751 /* RegCreateKeyExW [ADVAPI32.131] */
1752 DWORD
RegCreateKeyEx32W(
1759 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1763 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1767 /*FIXME: handle security/access/whatever */
1768 dprintf_reg(stddeb
,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1780 lpNextKey
= lookup_hkey(hkey
);
1782 return SHELL_ERROR_BADKEY
;
1783 if (!lpszSubKey
|| !*lpszSubKey
) {
1784 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1785 *retkey
=currenthandle
;
1786 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1787 return SHELL_ERROR_SUCCESS
;
1789 split_keypath(lpszSubKey
,&wps
,&wpc
);
1791 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1794 lpxkey
=lpNextKey
->nextsub
;
1796 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
1798 lpxkey
=lpxkey
->next
;
1806 add_handle(++currenthandle
,lpxkey
,samDesired
);
1807 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1808 *retkey
= currenthandle
;
1810 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1812 return SHELL_ERROR_SUCCESS
;
1814 /* good. now the hard part */
1816 lplpPrevKey
= &(lpNextKey
->nextsub
);
1817 lpxkey
= *lplpPrevKey
;
1819 lplpPrevKey
= &(lpxkey
->next
);
1820 lpxkey
= *lplpPrevKey
;
1822 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1823 if (!*lplpPrevKey
) {
1825 return SHELL_ERROR_OUTOFMEMORY
;
1827 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1828 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1829 (*lplpPrevKey
)->next
= NULL
;
1830 (*lplpPrevKey
)->nextsub
= NULL
;
1831 (*lplpPrevKey
)->values
= NULL
;
1832 (*lplpPrevKey
)->nrofvalues
= 0;
1833 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1835 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1837 (*lplpPrevKey
)->class = NULL
;
1838 lpNextKey
= *lplpPrevKey
;
1841 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1843 /*FIXME: flag handling correct? */
1844 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1846 lpNextKey
->class = strdupW(lpszClass
);
1848 lpNextKey
->class = NULL
;
1849 *retkey
= currenthandle
;
1851 *lpDispos
= REG_CREATED_NEW_KEY
;
1853 return SHELL_ERROR_SUCCESS
;
1856 /* RegCreateKeyW [ADVAPI32.132] */
1857 DWORD
RegCreateKey32W(
1864 dprintf_reg(stddeb
,"RegCreateKey32W(%lx,%s,%p)\n",
1865 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1867 ret
=RegCreateKeyEx32W(
1868 hkey
, /* key handle */
1869 lpszSubKey
, /* subkey name */
1870 0, /* reserved = 0 */
1871 NULL
, /* lpszClass? FIXME: ? */
1872 REG_OPTION_NON_VOLATILE
, /* options */
1873 KEY_ALL_ACCESS
, /* desired access attribs */
1874 NULL
, /* lpsecurity attributes */
1875 retkey
, /* lpretkey */
1876 &junk
/* disposition value */
1881 /* RegCreateKeyExA [ADVAPI32.130] */
1882 DWORD
RegCreateKeyEx32A(
1889 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1893 LPWSTR lpszSubKeyW
,lpszClassW
;
1896 dprintf_reg(stddeb
,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1908 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1912 lpszClassW
=strdupA2W(lpszClass
);
1915 ret
=RegCreateKeyEx32W(
1933 /* RegCreateKeyA [ADVAPI32.129] */
1934 DWORD
RegCreateKey32A(
1941 dprintf_reg(stddeb
,"RegCreateKey32A(%lx,%s,%p)\n",
1942 (LONG
)hkey
,lpszSubKey
,retkey
1944 return RegCreateKeyEx32A(
1945 hkey
, /* key handle */
1946 lpszSubKey
, /* subkey name */
1947 0, /* reserved = 0 */
1948 NULL
, /* lpszClass? FIXME: ? */
1949 REG_OPTION_NON_VOLATILE
,/* options */
1950 KEY_ALL_ACCESS
, /* desired access attribs */
1951 NULL
, /* lpsecurity attributes */
1952 retkey
, /* lpretkey */
1953 &junk
/* disposition value */
1957 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1958 DWORD
RegCreateKey16(
1963 dprintf_reg(stddeb
,"RegCreateKey16(%lx,%s,%p)\n",
1964 (LONG
)hkey
,lpszSubKey
,retkey
1966 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1970 * Query Value Functions
1971 * Win32 differs between keynames and valuenames.
1972 * multiple values may belong to one key, the special value
1973 * with name NULL is the default value used by the win31
1977 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1978 * RegQueryValue32W -> RegQueryValueEx32W
1981 /* RegQueryValueExW [ADVAPI32.158] */
1982 DWORD
RegQueryValueEx32W(
1984 LPWSTR lpszValueName
,
1985 LPDWORD lpdwReserved
,
1993 dprintf_reg(stddeb
,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1994 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1995 lpcbData
?*lpcbData
:0
1998 lpkey
= lookup_hkey(hkey
);
2000 return SHELL_ERROR_BADKEY
;
2001 if (lpszValueName
==NULL
) {
2002 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2003 if (lpkey
->values
[i
].name
==NULL
)
2006 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2007 if ( lpkey
->values
[i
].name
&&
2008 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
2012 if (i
==lpkey
->nrofvalues
) {
2013 if (lpszValueName
==NULL
) {
2015 *(WCHAR
*)lpbData
= 0;
2020 return SHELL_ERROR_SUCCESS
;
2022 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
2025 *lpdwType
= lpkey
->values
[i
].type
;
2026 if (lpbData
==NULL
) {
2028 return SHELL_ERROR_SUCCESS
;
2029 *lpcbData
= lpkey
->values
[i
].len
;
2030 return SHELL_ERROR_SUCCESS
;
2032 if (*lpcbData
<lpkey
->values
[i
].len
) {
2035 *lpcbData
= lpkey
->values
[i
].len
;
2036 return ERROR_MORE_DATA
;
2038 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
2039 *lpcbData
= lpkey
->values
[i
].len
;
2040 return SHELL_ERROR_SUCCESS
;
2043 /* RegQueryValueW [ADVAPI32.159] */
2044 DWORD
RegQueryValue32W(
2053 dprintf_reg(stddeb
,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2054 hkey
,W2C(lpszSubKey
,0),lpszData
,
2055 lpcbData
?*lpcbData
:0
2058 /* only open subkey, if we really do descend */
2059 if (lpszSubKey
&& *lpszSubKey
) {
2060 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
2061 if (ret
!=ERROR_SUCCESS
)
2067 ret
= RegQueryValueEx32W(
2069 NULL
, /* varname NULL -> compat */
2070 NULL
, /* lpdwReserved, must be NULL */
2080 /* RegQueryValueExA [ADVAPI32.157] */
2081 DWORD
RegQueryValueEx32A(
2083 LPSTR lpszValueName
,
2084 LPDWORD lpdwReserved
,
2089 LPWSTR lpszValueNameW
;
2095 dprintf_reg(stddeb
,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2096 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2097 lpcbData
?*lpcbData
:0
2101 buf
= (LPBYTE
)xmalloc((*lpcbData
)*2);
2102 myxlen
= *lpcbData
*2;
2107 myxlen
= *lpcbData
*2;
2113 lpszValueNameW
=strdupA2W(lpszValueName
);
2115 lpszValueNameW
=NULL
;
2119 ret
=RegQueryValueEx32W(
2129 if (ret
==ERROR_SUCCESS
) {
2131 if (UNICONVMASK
& (1<<(type
))) {
2132 /* convert UNICODE to ASCII */
2133 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2134 *lpcbData
= myxlen
/2;
2136 if (myxlen
>*lpcbData
)
2137 ret
= ERROR_MORE_DATA
;
2139 memcpy(lpbData
,buf
,myxlen
);
2144 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2145 *lpcbData
= myxlen
/2;
2148 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2149 *lpcbData
= myxlen
/2;
2156 /* RegQueryValueEx [KERNEL.225] */
2157 DWORD
RegQueryValueEx16(
2159 LPSTR lpszValueName
,
2160 LPDWORD lpdwReserved
,
2165 dprintf_reg(stddeb
,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2166 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2167 lpcbData
?*lpcbData
:0
2169 return RegQueryValueEx32A(
2179 /* RegQueryValueA [ADVAPI32.156] */
2180 DWORD
RegQueryValue32A(
2189 dprintf_reg(stddeb
,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2190 hkey
,lpszSubKey
,lpszData
,
2191 lpcbData
?*lpcbData
:0
2194 /* only open subkey, if we really do descend */
2195 if (lpszSubKey
&& *lpszSubKey
) {
2196 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
2197 if (ret
!=ERROR_SUCCESS
)
2203 ret
= RegQueryValueEx32A(
2205 NULL
, /* lpszValueName NULL -> compat */
2206 NULL
, /* lpdwReserved, must be NULL */
2216 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2217 DWORD
RegQueryValue16(
2223 dprintf_reg(stddeb
,"RegQueryValue16(%x,%s,%p,%ld)\n",
2224 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0
2226 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2227 * anyway, so we just mask out the high 16 bit.
2228 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2231 *lpcbData
&= 0xFFFF;
2232 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2236 * Setting values of Registry keys
2239 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2240 * RegSetValue32W -> RegSetValueEx32W
2243 /* RegSetValueExW [ADVAPI32.170] */
2244 DWORD
RegSetValueEx32W(
2246 LPWSTR lpszValueName
,
2255 dprintf_reg(stddeb
,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2256 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
2258 /* we no longer care about the lpbData type here... */
2259 lpkey
= lookup_hkey(hkey
);
2261 return SHELL_ERROR_BADKEY
;
2263 lpkey
->flags
|= REG_OPTION_TAINTED
;
2265 if (lpszValueName
==NULL
) {
2266 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2267 if (lpkey
->values
[i
].name
==NULL
)
2270 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2271 if ( lpkey
->values
[i
].name
&&
2272 !lstrcmp32W(lpszValueName
,lpkey
->values
[i
].name
)
2276 if (i
==lpkey
->nrofvalues
) {
2277 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2279 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2281 lpkey
->nrofvalues
++;
2282 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2284 if (lpkey
->values
[i
].name
==NULL
)
2286 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2288 lpkey
->values
[i
].name
= NULL
;
2289 lpkey
->values
[i
].len
= cbData
;
2290 lpkey
->values
[i
].type
= dwType
;
2291 if (lpkey
->values
[i
].data
!=NULL
)
2292 free(lpkey
->values
[i
].data
);
2293 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2294 lpkey
->values
[i
].lastmodified
= time(NULL
);
2295 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2296 return SHELL_ERROR_SUCCESS
;
2299 /* RegSetValueExA [ADVAPI32.169] */
2300 DWORD
RegSetValueEx32A(
2302 LPSTR lpszValueName
,
2309 LPWSTR lpszValueNameW
;
2312 dprintf_reg(stddeb
,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2313 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2315 if ((1<<dwType
) & UNICONVMASK
) {
2316 buf
=(LPBYTE
)strdupA2W(lpbData
);
2317 cbData
=2*strlen(lpbData
)+2;
2321 lpszValueNameW
= strdupA2W(lpszValueName
);
2323 lpszValueNameW
= NULL
;
2324 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2326 free(lpszValueNameW
);
2332 /* RegSetValueEx [KERNEL.226] */
2333 DWORD
RegSetValueEx16(
2335 LPSTR lpszValueName
,
2341 dprintf_reg(stddeb
,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2342 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2344 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2347 /* RegSetValueW [ADVAPI32.171] */
2348 DWORD
RegSetValue32W(
2358 dprintf_reg(stddeb
,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2359 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2361 if (lpszSubKey
&& *lpszSubKey
) {
2362 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2363 if (ret
!=ERROR_SUCCESS
)
2367 if (dwType
!=REG_SZ
) {
2368 fprintf(stddeb
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2371 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2372 dprintf_reg(stddeb
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2373 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2375 cbData
=2*lstrlen32W(lpszData
)+2;
2377 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2383 /* RegSetValueA [ADVAPI32.168] */
2384 DWORD
RegSetValue32A(
2394 dprintf_reg(stddeb
,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2395 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2397 if (lpszSubKey
&& *lpszSubKey
) {
2398 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2399 if (ret
!=ERROR_SUCCESS
)
2404 if (dwType
!=REG_SZ
) {
2405 dprintf_reg(stddeb
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2408 if (cbData
!=strlen(lpszData
)+1)
2409 cbData
=strlen(lpszData
)+1;
2410 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2416 /* RegSetValue [KERNEL.221] [SHELL.5] */
2417 DWORD
RegSetValue16(
2425 dprintf_reg(stddeb
,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2426 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2428 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2436 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2437 * RegEnumKey32W -> RegEnumKeyEx32W
2440 /* RegEnumKeyExW [ADVAPI32.139] */
2441 DWORD
RegEnumKeyEx32W(
2446 LPDWORD lpdwReserved
,
2451 LPKEYSTRUCT lpkey
,lpxkey
;
2453 dprintf_reg(stddeb
,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2454 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2456 lpkey
=lookup_hkey(hkey
);
2458 return SHELL_ERROR_BADKEY
;
2459 if (!lpkey
->nextsub
)
2460 return ERROR_NO_MORE_ITEMS
;
2461 lpxkey
=lpkey
->nextsub
;
2462 while (iSubkey
&& lpxkey
) {
2464 lpxkey
=lpxkey
->next
;
2466 if (iSubkey
|| !lpxkey
)
2467 return ERROR_NO_MORE_ITEMS
;
2468 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2469 return ERROR_MORE_DATA
;
2470 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2472 /* what should we write into it? */
2476 return ERROR_SUCCESS
;
2480 /* RegEnumKeyW [ADVAPI32.140] */
2481 DWORD
RegEnumKey32W(
2489 dprintf_reg(stddeb
,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2490 hkey
,iSubkey
,lpszName
,lpcchName
2492 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2494 /* RegEnumKeyExA [ADVAPI32.138] */
2495 DWORD
RegEnumKeyEx32A(
2500 LPDWORD lpdwReserved
,
2505 DWORD ret
,lpcchNameW
,lpcchClassW
;
2506 LPWSTR lpszNameW
,lpszClassW
;
2509 dprintf_reg(stddeb
,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2510 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2513 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2514 lpcchNameW
= *lpcchName
*2;
2520 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2521 lpcchClassW
= *lpcchClass
*2;
2526 ret
=RegEnumKeyEx32W(
2536 if (ret
==ERROR_SUCCESS
) {
2537 lstrcpyWtoA(lpszName
,lpszNameW
);
2538 *lpcchName
=strlen(lpszName
);
2540 lstrcpyWtoA(lpszClass
,lpszClassW
);
2541 *lpcchClass
=strlen(lpszClass
);
2551 /* RegEnumKeyA [ADVAPI32.137] */
2552 DWORD
RegEnumKey32A(
2560 dprintf_reg(stddeb
,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2561 hkey
,iSubkey
,lpszName
,lpcchName
2563 return RegEnumKeyEx32A(
2575 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2582 dprintf_reg(stddeb
,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2583 hkey
,iSubkey
,lpszName
,lpcchName
2585 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2589 * Enumerate Registry Values
2592 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2595 /* RegEnumValueW [ADVAPI32.142] */
2596 DWORD
RegEnumValue32W(
2601 LPDWORD lpdReserved
,
2609 dprintf_reg(stddeb
,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2610 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2612 lpkey
= lookup_hkey(hkey
);
2614 return SHELL_ERROR_BADKEY
;
2615 if (lpkey
->nrofvalues
<=iValue
)
2616 return ERROR_NO_MORE_ITEMS
;
2617 val
= lpkey
->values
+iValue
;
2620 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2621 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2622 return ERROR_MORE_DATA
;
2624 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2625 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2627 /* how to handle NULL value? */
2631 *lpdwType
=val
->type
;
2633 if (val
->len
>*lpcbData
)
2634 return ERROR_MORE_DATA
;
2635 memcpy(lpbData
,val
->data
,val
->len
);
2636 *lpcbData
= val
->len
;
2638 return SHELL_ERROR_SUCCESS
;
2641 /* RegEnumValueA [ADVAPI32.141] */
2642 DWORD
RegEnumValue32A(
2647 LPDWORD lpdReserved
,
2654 DWORD ret
,lpcbDataW
;
2656 dprintf_reg(stddeb
,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2657 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2660 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2662 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2663 lpcbDataW
= *lpcbData
*2;
2666 ret
=RegEnumValue32W(
2677 if (ret
==ERROR_SUCCESS
) {
2678 lstrcpyWtoA(lpszValue
,lpszValueW
);
2680 if ((1<<*lpdwType
) & UNICONVMASK
) {
2681 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2683 if (lpcbDataW
> *lpcbData
)
2684 ret
= ERROR_MORE_DATA
;
2686 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2688 *lpcbData
= lpcbDataW
;
2698 /* RegEnumValue [KERNEL.223] */
2699 DWORD
RegEnumValue16(
2704 LPDWORD lpdReserved
,
2709 dprintf_reg(stddeb
,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2710 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2712 return RegEnumValue32A(
2725 * Close registry key
2727 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2728 DWORD
RegCloseKey(HKEY hkey
) {
2729 dprintf_reg(stddeb
,"RegCloseKey(%x)\n",hkey
);
2730 remove_handle(hkey
);
2731 return ERROR_SUCCESS
;
2734 * Delete registry key
2737 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2739 /* RegDeleteKeyW [ADVAPI32.134] */
2740 DWORD
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2741 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2745 dprintf_reg(stddeb
,"RegDeleteKey32W(%x,%s)\n",
2746 hkey
,W2C(lpszSubKey
,0)
2748 lpNextKey
= lookup_hkey(hkey
);
2750 return SHELL_ERROR_BADKEY
;
2751 /* we need to know the previous key in the hier. */
2752 if (!lpszSubKey
|| !*lpszSubKey
)
2753 return SHELL_ERROR_BADKEY
;
2754 split_keypath(lpszSubKey
,&wps
,&wpc
);
2758 lpxkey
=lpNextKey
->nextsub
;
2760 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2762 lpxkey
=lpxkey
->next
;
2766 /* not found is success */
2767 return SHELL_ERROR_SUCCESS
;
2772 lpxkey
= lpNextKey
->nextsub
;
2773 lplpPrevKey
= &(lpNextKey
->nextsub
);
2775 if (!lstrcmp32W(wps
[i
],lpxkey
->keyname
))
2777 lplpPrevKey
= &(lpxkey
->next
);
2778 lpxkey
= lpxkey
->next
;
2781 return SHELL_ERROR_SUCCESS
;
2782 if (lpxkey
->nextsub
)
2783 return SHELL_ERROR_CANTWRITE
;
2784 *lplpPrevKey
= lpxkey
->next
;
2785 free(lpxkey
->keyname
);
2787 free(lpxkey
->class);
2789 free(lpxkey
->values
);
2792 return SHELL_ERROR_SUCCESS
;
2795 /* RegDeleteKeyA [ADVAPI32.133] */
2796 DWORD
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2800 dprintf_reg(stddeb
,"RegDeleteKey32A(%x,%s)\n",
2803 lpszSubKeyW
=strdupA2W(lpszSubKey
);
2804 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2809 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2810 DWORD
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2811 dprintf_reg(stddeb
,"RegDeleteKey16(%x,%s)\n",
2814 return RegDeleteKey32A(hkey
,lpszSubKey
);
2818 * Delete registry value
2821 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2823 /* RegDeleteValueW [ADVAPI32.136] */
2824 DWORD
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
) {
2829 dprintf_reg(stddeb
,"RegDeleteValue32W(%x,%s)\n",
2830 hkey
,W2C(lpszValue
,0)
2832 lpkey
=lookup_hkey(hkey
);
2834 return SHELL_ERROR_BADKEY
;
2836 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2837 if ( lpkey
->values
[i
].name
&&
2838 !lstrcmp32W(lpkey
->values
[i
].name
,lpszValue
)
2842 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2843 if (lpkey
->values
[i
].name
==NULL
)
2846 if (i
==lpkey
->nrofvalues
)
2847 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2848 val
= lpkey
->values
+i
;
2849 if (val
->name
) free(val
->name
);
2850 if (val
->data
) free(val
->data
);
2854 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2856 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2858 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2860 lpkey
->nrofvalues
--;
2861 return SHELL_ERROR_SUCCESS
;
2864 /* RegDeleteValueA [ADVAPI32.135] */
2865 DWORD
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
) {
2869 dprintf_reg( stddeb
, "RegDeleteValue32A(%x,%s)\n", hkey
,lpszValue
);
2871 lpszValueW
=strdupA2W(lpszValue
);
2874 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2880 /* RegDeleteValue [KERNEL.222] */
2881 DWORD
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
) {
2882 dprintf_reg( stddeb
,"RegDeleteValue16(%x,%s)\n", hkey
,lpszValue
);
2883 return RegDeleteValue32A(hkey
,lpszValue
);
2886 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2887 DWORD
RegFlushKey(HKEY hkey
) {
2888 dprintf_reg(stddeb
,"RegFlushKey(%x), STUB.\n",hkey
);
2889 return SHELL_ERROR_SUCCESS
;
2892 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2894 /* RegQueryInfoKeyW [ADVAPI32.153] */
2895 DWORD
RegQueryInfoKey32W(
2899 LPDWORD lpdwReserved
,
2901 LPDWORD lpcchMaxSubkey
,
2902 LPDWORD lpcchMaxClass
,
2904 LPDWORD lpcchMaxValueName
,
2905 LPDWORD lpccbMaxValueData
,
2906 LPDWORD lpcbSecurityDescriptor
,
2909 LPKEYSTRUCT lpkey
,lpxkey
;
2910 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2913 dprintf_reg(stddeb
,"RegQueryInfoKey32W(%x,......)\n",hkey
);
2914 lpkey
=lookup_hkey(hkey
);
2916 return SHELL_ERROR_BADKEY
;
2919 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2920 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2921 return ERROR_MORE_DATA
;
2923 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2924 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2931 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2933 lpxkey
=lpkey
->nextsub
;
2934 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2937 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2938 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2939 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2940 maxclass
=lstrlen32W(lpxkey
->class);
2941 if (lpxkey
->nrofvalues
>maxvalues
)
2942 maxvalues
=lpxkey
->nrofvalues
;
2943 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2944 LPKEYVALUE val
=lpxkey
->values
+i
;
2946 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2947 maxvname
=lstrlen32W(val
->name
);
2948 if (val
->len
>maxvdata
)
2951 lpxkey
=lpxkey
->next
;
2953 if (!maxclass
) maxclass
= 1;
2954 if (!maxvname
) maxvname
= 1;
2956 *lpcSubKeys
= nrofkeys
;
2958 *lpcchMaxSubkey
= maxsubkey
*2;
2960 *lpcchMaxClass
= maxclass
*2;
2962 *lpcValues
= maxvalues
;
2963 if (lpcchMaxValueName
)
2964 *lpcchMaxValueName
= maxvname
;
2965 if (lpccbMaxValueData
)
2966 *lpccbMaxValueData
= maxvdata
;
2967 return SHELL_ERROR_SUCCESS
;
2970 /* RegQueryInfoKeyA [ADVAPI32.152] */
2971 DWORD
RegQueryInfoKey32A(
2975 LPDWORD lpdwReserved
,
2977 LPDWORD lpcchMaxSubkey
,
2978 LPDWORD lpcchMaxClass
,
2980 LPDWORD lpcchMaxValueName
,
2981 LPDWORD lpccbMaxValueData
,
2982 LPDWORD lpcbSecurityDescriptor
,
2988 dprintf_reg(stddeb
,"RegQueryInfoKey32A(%x,......)\n",hkey
);
2991 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2995 ret
=RegQueryInfoKey32W(
3006 lpcbSecurityDescriptor
,
3009 if (ret
==ERROR_SUCCESS
)
3010 lstrcpyWtoA(lpszClass
,lpszClassW
);
3017 if (lpcchMaxValueName
)
3018 *lpcchMaxValueName
/=2;