4 * Copyright 1996 Marcus Meissner
6 * December 21, 1997 - Kevin Cozens
7 * Fixed bugs in the _w95_loadreg() function. Added extra information
8 * regarding the format of the Windows '95 registry files.
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
32 #define DEBUG_W95_LOADREG 0
34 /* FIXME: following defines should be configured global ... */
36 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
37 #define WINE_PREFIX "/.wine"
38 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
39 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
41 /* relative in ~user/.wine/ : */
42 #define SAVE_CURRENT_USER "user.reg"
43 #define SAVE_LOCAL_MACHINE "system.reg"
45 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
46 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
48 /* one value of a key */
49 typedef struct tagKEYVALUE
51 LPWSTR name
; /* name of value (UNICODE) or NULL for win31 */
52 DWORD type
; /* type of value */
53 DWORD len
; /* length of data in BYTEs */
54 DWORD lastmodified
; /* time of seconds since 1.1.1970 */
55 LPBYTE data
; /* content, may be strings, binaries, etc. */
56 } KEYVALUE
,*LPKEYVALUE
;
59 typedef struct tagKEYSTRUCT
61 LPWSTR keyname
; /* name of THIS key (UNICODE) */
62 DWORD flags
; /* flags. */
65 DWORD nrofvalues
; /* nr of values in THIS key */
66 LPKEYVALUE values
; /* values in THIS key */
67 /* key management pointers */
68 struct tagKEYSTRUCT
*next
; /* next key on same hierarchy */
69 struct tagKEYSTRUCT
*nextsub
; /* keys that hang below THIS key */
70 } KEYSTRUCT
, *LPKEYSTRUCT
;
73 static KEYSTRUCT
*key_classes_root
=NULL
; /* windows 3.1 global values */
74 static KEYSTRUCT
*key_current_user
=NULL
; /* user specific values */
75 static KEYSTRUCT
*key_local_machine
=NULL
;/* machine specific values */
76 static KEYSTRUCT
*key_users
=NULL
; /* all users? */
78 /* dynamic, not saved */
79 static KEYSTRUCT
*key_performance_data
=NULL
;
80 static KEYSTRUCT
*key_current_config
=NULL
;
81 static KEYSTRUCT
*key_dyn_data
=NULL
;
83 /* what valuetypes do we need to convert? */
84 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
86 extern LPWSTR __cdecl
CRTDLL_wcschr(LPWSTR a
,WCHAR c
);
88 static LPWSTR
strdupA2W(LPCSTR src
)
90 LPWSTR dest
=xmalloc(2*strlen(src
)+2);
91 lstrcpyAtoW(dest
,src
);
95 static LPWSTR
strdupW(LPCWSTR a
) {
99 len
=sizeof(WCHAR
)*(lstrlen32W(a
)+1);
100 b
=(LPWSTR
)xmalloc(len
);
106 static struct openhandle
{
111 static int nrofopenhandles
=0;
112 static int currenthandle
=1;
115 add_handle(HKEY hkey
,LPKEYSTRUCT lpkey
,REGSAM accessmask
) {
118 for (i
=0;i
<nrofopenhandles
;i
++) {
119 if (openhandles
[i
].lpkey
==lpkey
) {
120 WARN(reg
, "Tried to add %p twice!\n",lpkey
);
122 if (openhandles
[i
].hkey
==hkey
) {
123 WARN(reg
, "Tried to add %lx twice!\n",(LONG
)hkey
);
126 openhandles
=xrealloc( openhandles
,
127 sizeof(struct openhandle
)*(nrofopenhandles
+1)
129 openhandles
[i
].lpkey
= lpkey
;
130 openhandles
[i
].hkey
= hkey
;
131 openhandles
[i
].accessmask
= accessmask
;
136 get_handle(HKEY hkey
) {
139 for (i
=0;i
<nrofopenhandles
;i
++)
140 if (openhandles
[i
].hkey
==hkey
)
141 return openhandles
[i
].lpkey
;
142 WARN(reg
, "Didn't find handle %lx?\n",(LONG
)hkey
);
147 remove_handle(HKEY hkey
) {
150 for (i
=0;i
<nrofopenhandles
;i
++)
151 if (openhandles
[i
].hkey
==hkey
)
153 if (i
==nrofopenhandles
) {
154 WARN(reg
, "Didn't find handle %08x?\n",hkey
);
157 memcpy( openhandles
+i
,
159 sizeof(struct openhandle
)*(nrofopenhandles
-i
-1)
161 openhandles
=xrealloc(openhandles
,sizeof(struct openhandle
)*(nrofopenhandles
-1));
167 /* debug function, converts a unicode into a static memory area
168 * (sub for using two static strings, in case we need them in a single call)
171 W2C(LPCWSTR x
,int sub
) {
172 static LPSTR unicodedebug
[2]={NULL
,NULL
};
175 if (sub
!=0 && sub
!=1)
176 return "<W2C:bad sub>";
177 if (unicodedebug
[sub
]) HeapFree( SystemHeap
, 0, unicodedebug
[sub
] );
178 unicodedebug
[sub
] = HEAP_strdupWtoA( SystemHeap
, 0, x
);
179 return unicodedebug
[sub
];
183 lookup_hkey(HKEY hkey
) {
187 case HKEY_CLASSES_ROOT
:
188 return key_classes_root
;
189 case HKEY_CURRENT_USER
:
190 return key_current_user
;
191 case HKEY_LOCAL_MACHINE
:
192 return key_local_machine
;
195 case HKEY_PERFORMANCE_DATA
:
196 return key_performance_data
;
199 case HKEY_CURRENT_CONFIG
:
200 return key_current_config
;
202 WARN(reg
, "(%lx), special key!\n",
205 return get_handle(hkey
);
211 * splits the unicode string 'wp' into an array of strings.
212 * the array is allocated by this function.
213 * the number of components will be stored in 'wpc'
214 * Free the array using FREE_KEY_PATH
217 split_keypath(LPCWSTR wp
,LPWSTR
**wpv
,int *wpc
) {
221 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
223 for (i
=0;ws
[i
];i
++) {
230 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
238 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
241 * Shell initialisation, allocates keys.
243 void SHELL_StartupRegistry();
248 HKEY cl_r_hkey
,c_u_hkey
;
249 #define ADD_ROOT_KEY(xx) \
250 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
251 memset(xx,'\0',sizeof(KEYSTRUCT));\
252 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
254 ADD_ROOT_KEY(key_local_machine
);
255 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
256 fprintf(stderr
,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
259 key_classes_root
= lookup_hkey(cl_r_hkey
);
261 ADD_ROOT_KEY(key_users
);
264 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
265 * (later, when a win32 registry editing tool becomes avail.)
267 while (pwd
=getpwent()) {
268 if (pwd
->pw_name
== NULL
)
270 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
271 RegCloseKey(c_u_hkey
);
274 pwd
=getpwuid(getuid());
275 if (pwd
&& pwd
->pw_name
) {
276 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
277 key_current_user
= lookup_hkey(c_u_hkey
);
279 ADD_ROOT_KEY(key_current_user
);
281 ADD_ROOT_KEY(key_performance_data
);
282 ADD_ROOT_KEY(key_current_config
);
283 ADD_ROOT_KEY(key_dyn_data
);
285 SHELL_StartupRegistry();
290 SHELL_StartupRegistry() {
294 RegCreateKey16(HKEY_DYN_DATA
,"\\PerfStats\\StatData",&hkey
);
297 RegOpenKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System",&hkey
);
298 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
300 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
304 * string RegisteredOwner
305 * string RegisteredOrganization
308 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
313 if (-1!=gethostname(buf
,200)) {
314 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
315 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
319 /************************ SAVE Registry Function ****************************/
321 #define REGISTRY_SAVE_VERSION 0x00000001
323 /* Registry saveformat:
324 * If you change it, increase above number by 1, which will flush
325 * old registry database files.
328 * "WINE REGISTRY Version %d"
332 * valuename=lastmodified,type,data
336 * keyname,valuename,stringdata:
337 * the usual ascii characters from 0x00-0xff (well, not 0x00)
338 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
339 * ( "=\\\t" escaped in \uXXXX form.)
343 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
345 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
346 * SaveOnlyUpdatedKeys=yes
349 _save_check_tainted(LPKEYSTRUCT lpkey
) {
354 if (lpkey
->flags
& REG_OPTION_TAINTED
)
359 if (_save_check_tainted(lpkey
->nextsub
)) {
360 lpkey
->flags
|= REG_OPTION_TAINTED
;
369 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
382 if (escapeeq
&& *s
=='=')
385 fputc(*s
,F
); /* if \\ then put it twice. */
387 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
395 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
401 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
402 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
404 for (tabs
=level
;tabs
--;)
406 _save_USTRING(F
,lpxkey
->keyname
,1);
408 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
409 LPKEYVALUE val
=lpxkey
->values
+i
;
411 for (tabs
=level
+1;tabs
--;)
413 _save_USTRING(F
,val
->name
,0);
415 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
416 if ((1<<val
->type
) & UNICONVMASK
)
417 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
419 for (j
=0;j
<val
->len
;j
++)
420 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
423 /* descend recursively */
424 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
433 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
434 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
435 _save_check_tainted(lpkey
->nextsub
);
436 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
440 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
445 fprintf(stddeb
,__FILE__
":_savereg:Couldn't open %s for writing: %s\n",
450 if (!_savesubreg(F
,lpkey
,all
)) {
453 fprintf(stddeb
,__FILE__
":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
461 SHELL_SaveRegistry() {
469 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
475 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
487 if (lstrcmpi32A(buf
,"yes"))
489 pwd
=getpwuid(getuid());
490 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
494 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
495 strlen(SAVE_CURRENT_USER
) + 2 );
496 strcpy(fn
,pwd
->pw_dir
);
497 strcat(fn
,WINE_PREFIX
);
498 /* create the directory. don't care about errorcodes. */
499 mkdir(fn
,0755); /* drwxr-xr-x */
500 strcat(fn
,"/"SAVE_CURRENT_USER
);
501 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
502 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
503 if (_savereg(key_current_user
,tmp
,all
)) {
504 if (-1==rename(tmp
,fn
)) {
505 perror("rename tmp registry");
511 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
512 strcpy(fn
,pwd
->pw_dir
);
513 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
514 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
515 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
516 if (_savereg(key_local_machine
,tmp
,all
)) {
517 if (-1==rename(tmp
,fn
)) {
518 perror("rename tmp registry");
525 fprintf(stderr
,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
528 /************************ LOAD Registry Function ****************************/
531 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
532 LPKEYSTRUCT lpxkey
,*lplpkey
;
538 lplpkey
= &(lpkey
->nextsub
);
541 if (!lstrcmpi32W(lpxkey
->keyname
,keyname
))
543 lplpkey
= &(lpxkey
->next
);
547 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
549 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
550 lpxkey
->keyname
= keyname
;
558 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
564 if (name
&& !*name
) {/* empty string equals default (NULL) value */
569 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
575 if ( val
->name
!=NULL
&&
576 !lstrcmpi32W(val
->name
,name
)
581 if (i
==lpkey
->nrofvalues
) {
582 lpkey
->values
= xrealloc(
584 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
587 memset(val
,'\0',sizeof(KEYVALUE
));
593 if (val
->lastmodified
<lastmodified
) {
594 val
->lastmodified
=lastmodified
;
605 /* reads a line including dynamically enlarging the readbuffer and throwing
609 _wine_read_line(FILE *F
,char **buf
,int *len
) {
618 s
=fgets(curread
,mylen
,F
);
621 if (NULL
==(s
=strchr(curread
,'\n'))) {
622 /* buffer wasn't large enough */
623 curoff
= strlen(*buf
);
624 *buf
= xrealloc(*buf
,*len
*2);
625 curread
= *buf
+ curoff
;
626 mylen
= *len
; /* we filled up the buffer and
627 * got new '*len' bytes to fill
635 /* throw away comments */
636 if (**buf
=='#' || **buf
==';') {
641 if (s
) /* got end of line */
647 /* converts a char* into a UNICODE string (up to a special char)
648 * and returns the position exactly after that string
651 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
655 /* read up to "=" or "\0" or "\n" */
658 /* empty string is the win3.1 default value(NULL)*/
662 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
664 while (*s
&& (*s
!='\n') && (*s
!='=')) {
666 *ws
++=*((unsigned char*)s
++);
675 fprintf(stderr
,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
683 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
684 if (!sscanf(xbuf
,"%x",&wc
))
685 fprintf(stderr
,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf
,buf
);
687 *ws
++ =(unsigned short)wc
;
694 *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 TRACE(reg
,"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 WARN(reg
,"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
)xmalloc(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..0F: ? (someone fill in please)
886 * 10: WORD number of RGDB blocks
888 * 14: WORD always 0000?
889 * 16: WORD always 0001?
890 * 18..1F: ? (someone fill in please)
895 * 4 : DWORD offset to first RGDB section
896 * 8 : DWORD offset to ?
897 * C..0x1B: ? (fill in)
898 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
900 * Disk Key Entry Structure:
901 * 00: DWORD - Free entry indicator(?)
902 * 04: DWORD - Hash = sum of bytes of keyname
903 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
904 * 0C: DWORD - disk address of PreviousLevel Key.
905 * 10: DWORD - disk address of Next Sublevel Key.
906 * 14: DWORD - disk address of Next Key (on same level).
907 * DKEP>18: WORD - Nr, Low Significant part.
908 * 1A: WORD - Nr, High Significant part.
910 * The disk address always points to the nr part of the previous key entry
911 * of the referenced key. Don't ask me why, or even if I got this correct
912 * from staring at 1kg of hexdumps. (DKEP)
914 * The High significant part of the structure seems to equal the number
915 * of the RGDB section. The low significant part is a unique ID within
918 * There are two minor corrections to the position of that structure.
919 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
920 * the DKE reread from there.
921 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
922 * CPS - I have not experienced the above phenomenon in my registry files
926 * 04: DWORD offset to next RGDB section
928 * 0C: WORD always 000d?
929 * 0E: WORD RGDB block number
930 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
935 * 00: DWORD nextkeyoffset - offset to the next disk key structure
936 * 08: WORD nrLS - low significant part of NR
937 * 0A: WORD nrHS - high significant part of NR
938 * 0C: DWORD bytesused - bytes used in this structure.
939 * 10: WORD name_len - length of name in bytes. without \0
940 * 12: WORD nr_of_values - number of values.
941 * 14: char name[name_len] - name string. No \0.
942 * 14+name_len: disk values
943 * nextkeyoffset: ... next disk key
946 * 00: DWORD type - value type (hmm, could be WORD too)
947 * 04: DWORD - unknown, usually 0
948 * 08: WORD namelen - length of Name. 0 means name=NULL
949 * 0C: WORD datalen - length of Data.
950 * 10: char name[namelen] - name, no \0
951 * 10+namelen: BYTE data[datalen] - data, without \0 if string
952 * 10+namelen+datalen: next values or disk key
954 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
955 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
956 * structure) and reading another RGDB_section.
957 * repeat until end of file.
959 * An interesting relationship exists in RGDB_section. The value at offset
960 * 10 equals the value at offset 4 minus the value at offset 8. I have no
961 * idea at the moment what this means. (Kevin Cozens)
963 * FIXME: this description needs some serious help, yes.
966 struct _w95keyvalue
{
968 unsigned short datalen
;
978 struct _w95keyvalue
*values
;
979 struct _w95key
*prevlvl
;
980 struct _w95key
*nextsub
;
981 struct _w95key
*next
;
994 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
997 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
999 lstrcpynAtoW(dest
,src
,nchars
+1);
1004 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1005 int nrLS
, int nrMS
, struct _w95_info
*info
)
1008 /* Disk Key Header structure (RGDB part) */
1010 unsigned long nextkeyoff
;
1011 unsigned short nrLS
;
1012 unsigned short nrMS
;
1013 unsigned long bytesused
;
1014 unsigned short keynamelen
;
1015 unsigned short values
;
1018 /* disk key values or nothing */
1020 /* Disk Key Value structure */
1024 unsigned short valnamelen
;
1025 unsigned short valdatalen
;
1026 /* valname, valdata */
1032 char *rgdbdata
= info
->rgdbbuffer
;
1033 int nbytes
= info
->rgdbsize
;
1034 char *curdata
= rgdbdata
;
1035 char *end
= rgdbdata
+ nbytes
;
1037 char *next
= rgdbdata
;
1043 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1045 memcpy(&off_next_rgdb
,curdata
+4,4);
1046 next
= curdata
+ off_next_rgdb
;
1047 nrgdb
= (int) *((short *)curdata
+ 7);
1049 } while (nrgdb
!= nrMS
&& (next
< end
));
1051 /* curdata now points to the start of the right RGDB section */
1054 #define XREAD(whereto,len) \
1055 if ((curdata + len) <end) {\
1056 memcpy(whereto,curdata,len);\
1062 XREAD(&dkh
, sizeof (dkh
));
1063 if (dkh
.nrLS
== nrLS
) break;
1065 curdata
+= dkh
.nextkeyoff
- sizeof(dkh
);
1066 } while (curdata
< next
);
1068 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1070 if (nrgdb
!= dkh
.nrMS
) {
1074 assert((dkh
.keynamelen
<2) || curdata
[0]);
1075 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1076 curdata
+= dkh
.keynamelen
;
1078 for (i
=0;i
< dkh
.values
; i
++) {
1084 XREAD(&dkv
,sizeof(dkv
));
1086 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1087 curdata
+= dkv
.valnamelen
;
1089 if ((1 << dkv
.type
) & UNICONVMASK
) {
1090 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1091 len
= 2*(dkv
.valdatalen
+ 1);
1093 /* I don't think we want to NULL terminate all data */
1094 data
= xmalloc(dkv
.valdatalen
);
1095 memcpy (data
, curdata
, dkv
.valdatalen
);
1096 len
= dkv
.valdatalen
;
1099 curdata
+= dkv
.valdatalen
;
1116 _w95_walkrgkn(LPKEYSTRUCT prevkey
, char *off
, struct _w95_info
*info
)
1119 /* Disk Key Entry structure (RGKN part) */
1123 unsigned long x3
;/*usually 0xFFFFFFFF */
1124 unsigned long prevlvl
;
1125 unsigned long nextsub
;
1127 unsigned short nrLS
;
1128 unsigned short nrMS
;
1129 } *dke
= (struct dke
*)off
;
1133 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1136 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1137 /* XXX <-- This is a hack*/
1142 if (dke
->nextsub
!= -1 &&
1143 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1144 && (dke
->nextsub
> 0x20)) {
1146 _w95_walkrgkn(lpxkey
,
1147 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1151 if (dke
->next
!= -1 &&
1152 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1153 (dke
->next
> 0x20)) {
1154 _w95_walkrgkn(prevkey
,
1155 info
->rgknbuffer
+ dke
->next
- 0x20,
1163 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1166 unsigned long where
,version
,rgdbsection
,end
;
1167 struct _w95_info info
;
1169 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1171 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1172 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1173 if (hfd
==HFILE_ERROR32
)
1176 if (4!=_lread32(hfd
,magic
,4))
1178 if (strcmp(magic
,"CREG")) {
1179 fprintf(stddeb
,"%s is not a w95 registry.\n",fn
);
1182 if (4!=_lread32(hfd
,&version
,4))
1184 if (4!=_lread32(hfd
,&rgdbsection
,4))
1186 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1188 if (4!=_lread32(hfd
,magic
,4))
1190 if (strcmp(magic
,"RGKN")) {
1191 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1195 /* STEP 1: Keylink structures */
1196 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1201 info
.rgknsize
= end
- where
;
1202 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1203 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1206 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1209 end
= hfdinfo
.nFileSizeLow
;
1210 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1212 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1215 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1216 info
.rgdbsize
= end
- rgdbsection
;
1218 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1222 _w95_walkrgkn(lpkey
, NULL
, &info
);
1224 free (info
.rgdbbuffer
);
1225 free (info
.rgknbuffer
);
1228 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1231 reghack - windows 3.11 registry data format demo program.
1233 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1234 a combined hash table and tree description, and finally a text table.
1236 The header is obvious from the struct header. The taboff1 and taboff2
1237 fields are always 0x20, and their usage is unknown.
1239 The 8-byte entry table has various entry types.
1241 tabent[0] is a root index. The second word has the index of the root of
1243 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1244 the index of the key/value that has that hash. Data with the same
1245 hash value are on a circular list. The other three words in the
1246 hash entry are always zero.
1247 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1248 entry: dirent and keyent/valent. They are identified by context.
1249 tabent[freeidx] is the first free entry. The first word in a free entry
1250 is the index of the next free entry. The last has 0 as a link.
1251 The other three words in the free list are probably irrelevant.
1253 Entries in text table are preceeded by a word at offset-2. This word
1254 has the value (2*index)+1, where index is the referring keyent/valent
1255 entry in the table. I have no suggestion for the 2* and the +1.
1256 Following the word, there are N bytes of data, as per the keyent/valent
1257 entry length. The offset of the keyent/valent entry is from the start
1258 of the text table to the first data byte.
1260 This information is not available from Microsoft. The data format is
1261 deduced from the reg.dat file by me. Mistakes may
1262 have been made. I claim no rights and give no guarantees for this program.
1264 Tor Sjøwall, tor@sn.no
1267 /* reg.dat header format */
1268 struct _w31_header
{
1269 char cookie
[8]; /* 'SHCC3.10' */
1270 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1271 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1272 unsigned long tabcnt
; /* number of entries in index table */
1273 unsigned long textoff
; /* offset of text part */
1274 unsigned long textsize
; /* byte size of text part */
1275 unsigned short hashsize
; /* hash size */
1276 unsigned short freeidx
; /* free index */
1279 /* generic format of table entries */
1280 struct _w31_tabent
{
1281 unsigned short w0
, w1
, w2
, w3
;
1284 /* directory tabent: */
1285 struct _w31_dirent
{
1286 unsigned short sibling_idx
; /* table index of sibling dirent */
1287 unsigned short child_idx
; /* table index of child dirent */
1288 unsigned short key_idx
; /* table index of key keyent */
1289 unsigned short value_idx
; /* table index of value valent */
1293 struct _w31_keyent
{
1294 unsigned short hash_idx
; /* hash chain index for string */
1295 unsigned short refcnt
; /* reference count */
1296 unsigned short length
; /* length of string */
1297 unsigned short string_off
; /* offset of string in text table */
1301 struct _w31_valent
{
1302 unsigned short hash_idx
; /* hash chain index for string */
1303 unsigned short refcnt
; /* reference count */
1304 unsigned short length
; /* length of string */
1305 unsigned short string_off
; /* offset of string in text table */
1308 /* recursive helper function to display a directory tree */
1310 __w31_dumptree( unsigned short idx
,
1312 struct _w31_tabent
*tab
,
1313 struct _w31_header
*head
,
1315 time_t lastmodified
,
1318 struct _w31_dirent
*dir
;
1319 struct _w31_keyent
*key
;
1320 struct _w31_valent
*val
;
1321 LPKEYSTRUCT xlpkey
= NULL
;
1323 static char tail
[400];
1326 dir
=(struct _w31_dirent
*)&tab
[idx
];
1329 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1331 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1332 tail
[key
->length
]='\0';
1333 /* all toplevel entries AND the entries in the
1334 * toplevel subdirectory belong to \SOFTWARE\Classes
1336 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1337 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1338 idx
=dir
->sibling_idx
;
1341 name
=strdupA2W(tail
);
1343 xlpkey
=_find_or_add_key(lpkey
,name
);
1345 /* only add if leaf node or valued node */
1346 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1347 if (dir
->value_idx
) {
1348 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1349 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1350 tail
[val
->length
]='\0';
1351 value
=strdupA2W(tail
);
1352 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1356 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1358 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1359 idx
=dir
->sibling_idx
;
1366 struct _w31_header head
;
1367 struct _w31_tabent
*tab
;
1371 BY_HANDLE_FILE_INFORMATION hfinfo
;
1372 time_t lastmodified
;
1376 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1377 if (hf
==HFILE_ERROR32
)
1380 /* read & dump header */
1381 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1382 ERR(reg
, "reg.dat is too short.\n");
1386 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1387 ERR(reg
, "reg.dat has bad signature.\n");
1392 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1393 /* read and dump index table */
1395 if (len
!=_lread32(hf
,tab
,len
)) {
1396 ERR(reg
,"couldn't read %d bytes.\n",len
);
1403 txt
= xmalloc(head
.textsize
);
1404 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1405 ERR(reg
,"couldn't seek to textblock.\n");
1411 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1412 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1419 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1420 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1426 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1428 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&hkey
)!=ERROR_SUCCESS
)
1430 lpkey
= lookup_hkey(hkey
);
1431 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1439 SHELL_LoadRegistry() {
1446 if (key_classes_root
==NULL
)
1449 /* Load windows 3.1 entries */
1451 /* Load windows 95 entries */
1452 _w95_loadreg("C:\\system.1st", key_local_machine
);
1453 _w95_loadreg("system.dat", key_local_machine
);
1454 _w95_loadreg("user.dat", key_users
);
1456 /* the global user default is loaded under HKEY_USERS\\.Default */
1457 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1458 lpkey
= lookup_hkey(hkey
);
1459 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1461 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1462 _copy_registry(lpkey
,key_current_user
);
1465 /* the global machine defaults */
1466 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1468 /* load the user saved registries */
1470 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1472 pwd
=getpwuid(getuid());
1473 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1474 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1475 strcpy(fn
,pwd
->pw_dir
);
1476 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1477 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1479 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1480 strcpy(fn
,pwd
->pw_dir
);
1481 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1482 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1485 fprintf(stderr
,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1486 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1487 DWORD junk
,type
,len
;
1491 if (( RegQueryValueEx32A(
1498 )!=ERROR_SUCCESS
) ||
1501 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1507 /********************* API FUNCTIONS ***************************************/
1511 * All functions are stubs to RegOpenKeyEx32W where all the
1514 * FIXME: security,options,desiredaccess,...
1517 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1518 * RegOpenKey32W -> RegOpenKeyEx32W
1521 /* RegOpenKeyExW [ADVAPI32.150] */
1522 DWORD WINAPI
RegOpenKeyEx32W(
1529 LPKEYSTRUCT lpNextKey
,lpxkey
;
1532 TRACE(reg
,"(%lx,%s,%ld,%lx,%p)\n",
1533 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1536 lpNextKey
= lookup_hkey(hkey
);
1538 return SHELL_ERROR_BADKEY
;
1539 if (!lpszSubKey
|| !*lpszSubKey
) {
1540 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1541 *retkey
=currenthandle
;
1542 return SHELL_ERROR_SUCCESS
;
1544 split_keypath(lpszSubKey
,&wps
,&wpc
);
1546 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1549 lpxkey
=lpNextKey
->nextsub
;
1551 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1553 lpxkey
=lpxkey
->next
;
1557 return SHELL_ERROR_BADKEY
;
1562 add_handle(++currenthandle
,lpxkey
,samDesired
);
1563 *retkey
= currenthandle
;
1565 return SHELL_ERROR_SUCCESS
;
1568 /* RegOpenKeyW [ADVAPI32.151] */
1569 DWORD WINAPI
RegOpenKey32W(
1574 TRACE(reg
,"(%lx,%s,%p)\n",
1575 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1577 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1581 /* RegOpenKeyExA [ADVAPI32.149] */
1582 DWORD WINAPI
RegOpenKeyEx32A(
1592 TRACE(reg
,"(%lx,%s,%ld,%lx,%p)\n",
1593 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1596 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1599 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1605 /* RegOpenKeyA [ADVAPI32.148] */
1606 DWORD WINAPI
RegOpenKey32A(
1611 TRACE(reg
,"(%lx,%s,%p)\n",
1612 (LONG
)hkey
,lpszSubKey
,retkey
1614 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1617 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1618 DWORD WINAPI
RegOpenKey16(
1623 TRACE(reg
,"(%lx,%s,%p)\n",
1624 (LONG
)hkey
,lpszSubKey
,retkey
1626 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1632 * All those functions convert their respective
1633 * arguments and call RegCreateKeyExW at the end.
1635 * FIXME: no security,no access attrib,no optionhandling yet.
1638 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1639 * RegCreateKey32W -> RegCreateKeyEx32W
1642 /* RegCreateKeyExW [ADVAPI32.131] */
1643 DWORD WINAPI
RegCreateKeyEx32W(
1650 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1654 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1658 /*FIXME: handle security/access/whatever */
1659 TRACE(reg
,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1671 lpNextKey
= lookup_hkey(hkey
);
1673 return SHELL_ERROR_BADKEY
;
1674 if (!lpszSubKey
|| !*lpszSubKey
) {
1675 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1676 *retkey
=currenthandle
;
1677 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1678 return SHELL_ERROR_SUCCESS
;
1680 split_keypath(lpszSubKey
,&wps
,&wpc
);
1682 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1685 lpxkey
=lpNextKey
->nextsub
;
1687 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1689 lpxkey
=lpxkey
->next
;
1697 add_handle(++currenthandle
,lpxkey
,samDesired
);
1698 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1699 *retkey
= currenthandle
;
1701 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1703 return SHELL_ERROR_SUCCESS
;
1705 /* good. now the hard part */
1707 lplpPrevKey
= &(lpNextKey
->nextsub
);
1708 lpxkey
= *lplpPrevKey
;
1710 lplpPrevKey
= &(lpxkey
->next
);
1711 lpxkey
= *lplpPrevKey
;
1713 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1714 if (!*lplpPrevKey
) {
1716 return SHELL_ERROR_OUTOFMEMORY
;
1718 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1719 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1720 (*lplpPrevKey
)->next
= NULL
;
1721 (*lplpPrevKey
)->nextsub
= NULL
;
1722 (*lplpPrevKey
)->values
= NULL
;
1723 (*lplpPrevKey
)->nrofvalues
= 0;
1724 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1726 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1728 (*lplpPrevKey
)->class = NULL
;
1729 lpNextKey
= *lplpPrevKey
;
1732 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1734 /*FIXME: flag handling correct? */
1735 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1737 lpNextKey
->class = strdupW(lpszClass
);
1739 lpNextKey
->class = NULL
;
1740 *retkey
= currenthandle
;
1742 *lpDispos
= REG_CREATED_NEW_KEY
;
1744 return SHELL_ERROR_SUCCESS
;
1747 /* RegCreateKeyW [ADVAPI32.132] */
1748 DWORD WINAPI
RegCreateKey32W(
1755 TRACE(reg
,"(%lx,%s,%p)\n",
1756 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1758 ret
=RegCreateKeyEx32W(
1759 hkey
, /* key handle */
1760 lpszSubKey
, /* subkey name */
1761 0, /* reserved = 0 */
1762 NULL
, /* lpszClass? FIXME: ? */
1763 REG_OPTION_NON_VOLATILE
, /* options */
1764 KEY_ALL_ACCESS
, /* desired access attribs */
1765 NULL
, /* lpsecurity attributes */
1766 retkey
, /* lpretkey */
1767 &junk
/* disposition value */
1772 /* RegCreateKeyExA [ADVAPI32.130] */
1773 DWORD WINAPI
RegCreateKeyEx32A(
1780 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1784 LPWSTR lpszSubKeyW
,lpszClassW
;
1787 TRACE(reg
,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1799 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1803 lpszClassW
=strdupA2W(lpszClass
);
1806 ret
=RegCreateKeyEx32W(
1824 /* RegCreateKeyA [ADVAPI32.129] */
1825 DWORD WINAPI
RegCreateKey32A(
1832 TRACE(reg
,"(%lx,%s,%p)\n",
1833 (LONG
)hkey
,lpszSubKey
,retkey
1835 return RegCreateKeyEx32A(
1836 hkey
, /* key handle */
1837 lpszSubKey
, /* subkey name */
1838 0, /* reserved = 0 */
1839 NULL
, /* lpszClass? FIXME: ? */
1840 REG_OPTION_NON_VOLATILE
,/* options */
1841 KEY_ALL_ACCESS
, /* desired access attribs */
1842 NULL
, /* lpsecurity attributes */
1843 retkey
, /* lpretkey */
1844 &junk
/* disposition value */
1848 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1849 DWORD WINAPI
RegCreateKey16(
1854 TRACE(reg
,"(%lx,%s,%p)\n",
1855 (LONG
)hkey
,lpszSubKey
,retkey
1857 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1861 * Query Value Functions
1862 * Win32 differs between keynames and valuenames.
1863 * multiple values may belong to one key, the special value
1864 * with name NULL is the default value used by the win31
1868 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1869 * RegQueryValue32W -> RegQueryValueEx32W
1872 /* RegQueryValueExW [ADVAPI32.158] */
1873 DWORD WINAPI
RegQueryValueEx32W(
1875 LPWSTR lpszValueName
,
1876 LPDWORD lpdwReserved
,
1884 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
1885 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1886 lpcbData
?*lpcbData
:0);
1888 lpkey
= lookup_hkey(hkey
);
1890 return SHELL_ERROR_BADKEY
;
1891 if (lpszValueName
&& !*lpszValueName
)
1892 lpszValueName
= NULL
;
1893 if (lpszValueName
==NULL
) {
1894 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1895 if (lpkey
->values
[i
].name
==NULL
)
1898 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1899 if ( lpkey
->values
[i
].name
&&
1900 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
1904 if (i
==lpkey
->nrofvalues
) {
1905 if (lpszValueName
==NULL
) {
1907 *(WCHAR
*)lpbData
= 0;
1912 return SHELL_ERROR_SUCCESS
;
1914 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
1917 *lpdwType
= lpkey
->values
[i
].type
;
1918 if (lpbData
==NULL
) {
1920 return SHELL_ERROR_SUCCESS
;
1921 *lpcbData
= lpkey
->values
[i
].len
;
1922 return SHELL_ERROR_SUCCESS
;
1924 if (*lpcbData
<lpkey
->values
[i
].len
) {
1925 *(WCHAR
*)lpbData
= 0;
1926 *lpcbData
= lpkey
->values
[i
].len
;
1927 return ERROR_MORE_DATA
;
1929 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
1930 *lpcbData
= lpkey
->values
[i
].len
;
1931 return SHELL_ERROR_SUCCESS
;
1934 /* RegQueryValueW [ADVAPI32.159] */
1935 DWORD WINAPI
RegQueryValue32W(
1944 TRACE(reg
,"(%x,%s,%p,%ld)\n",
1945 hkey
,W2C(lpszSubKey
,0),lpszData
,
1946 lpcbData
?*lpcbData
:0);
1948 /* only open subkey, if we really do descend */
1949 if (lpszSubKey
&& *lpszSubKey
) {
1950 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
1951 if (ret
!=ERROR_SUCCESS
)
1957 ret
= RegQueryValueEx32W(
1959 NULL
, /* varname NULL -> compat */
1960 NULL
, /* lpdwReserved, must be NULL */
1970 /* RegQueryValueExA [ADVAPI32.157] */
1971 DWORD WINAPI
RegQueryValueEx32A(
1973 LPSTR lpszValueName
,
1974 LPDWORD lpdwReserved
,
1979 LPWSTR lpszValueNameW
;
1985 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
1986 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1987 lpcbData
?*lpcbData
:0);
1990 lpszValueNameW
=strdupA2W(lpszValueName
);
1992 lpszValueNameW
=NULL
;
2001 ret
=RegQueryValueEx32W(
2010 if (ret
==ERROR_MORE_DATA
) {
2011 buf
= (LPBYTE
)xmalloc(*mylen
);
2013 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2014 myxlen
= 2*(*lpcbData
);
2019 myxlen
= *lpcbData
*2;
2024 ret
=RegQueryValueEx32W(
2034 if (ret
==ERROR_SUCCESS
) {
2036 if (UNICONVMASK
& (1<<(type
))) {
2037 /* convert UNICODE to ASCII */
2038 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2039 *lpcbData
= myxlen
/2;
2041 if (myxlen
>*lpcbData
)
2042 ret
= ERROR_MORE_DATA
;
2044 memcpy(lpbData
,buf
,myxlen
);
2049 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2050 *lpcbData
= myxlen
/2;
2053 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2054 *lpcbData
= myxlen
/2;
2061 /* RegQueryValueEx [KERNEL.225] */
2062 DWORD WINAPI
RegQueryValueEx16(
2064 LPSTR lpszValueName
,
2065 LPDWORD lpdwReserved
,
2070 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
2071 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2072 lpcbData
?*lpcbData
:0);
2074 return RegQueryValueEx32A(
2084 /* RegQueryValueA [ADVAPI32.156] */
2085 DWORD WINAPI
RegQueryValue32A(
2094 TRACE(reg
,"(%x,%s,%p,%ld)\n",
2095 hkey
,lpszSubKey
,lpszData
,
2096 lpcbData
?*lpcbData
:0);
2098 /* only open subkey, if we really do descend */
2099 if (lpszSubKey
&& *lpszSubKey
) {
2100 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
2101 if (ret
!=ERROR_SUCCESS
)
2107 ret
= RegQueryValueEx32A(
2109 NULL
, /* lpszValueName NULL -> compat */
2110 NULL
, /* lpdwReserved, must be NULL */
2120 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2121 DWORD WINAPI
RegQueryValue16(
2127 TRACE(reg
,"(%x,%s,%p,%ld)\n",
2128 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0);
2130 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2131 * anyway, so we just mask out the high 16 bit.
2132 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2135 *lpcbData
&= 0xFFFF;
2136 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2140 * Setting values of Registry keys
2143 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2144 * RegSetValue32W -> RegSetValueEx32W
2147 /* RegSetValueExW [ADVAPI32.170] */
2148 DWORD WINAPI
RegSetValueEx32W(
2150 LPWSTR lpszValueName
,
2159 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2160 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
2162 /* we no longer care about the lpbData type here... */
2163 lpkey
= lookup_hkey(hkey
);
2165 return SHELL_ERROR_BADKEY
;
2167 lpkey
->flags
|= REG_OPTION_TAINTED
;
2169 if (lpszValueName
==NULL
) {
2170 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2171 if (lpkey
->values
[i
].name
==NULL
)
2174 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2175 if ( lpkey
->values
[i
].name
&&
2176 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2180 if (i
==lpkey
->nrofvalues
) {
2181 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2183 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2185 lpkey
->nrofvalues
++;
2186 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2188 if (lpkey
->values
[i
].name
==NULL
)
2190 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2192 lpkey
->values
[i
].name
= NULL
;
2193 lpkey
->values
[i
].len
= cbData
;
2194 lpkey
->values
[i
].type
= dwType
;
2195 if (lpkey
->values
[i
].data
!=NULL
)
2196 free(lpkey
->values
[i
].data
);
2197 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2198 lpkey
->values
[i
].lastmodified
= time(NULL
);
2199 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2200 return SHELL_ERROR_SUCCESS
;
2203 /* RegSetValueExA [ADVAPI32.169] */
2204 DWORD WINAPI
RegSetValueEx32A(
2206 LPSTR lpszValueName
,
2213 LPWSTR lpszValueNameW
;
2216 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2217 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2219 if ((1<<dwType
) & UNICONVMASK
) {
2220 buf
=(LPBYTE
)strdupA2W(lpbData
);
2221 cbData
=2*strlen(lpbData
)+2;
2225 lpszValueNameW
= strdupA2W(lpszValueName
);
2227 lpszValueNameW
= NULL
;
2228 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2230 free(lpszValueNameW
);
2236 /* RegSetValueEx [KERNEL.226] */
2237 DWORD WINAPI
RegSetValueEx16(
2239 LPSTR lpszValueName
,
2245 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2246 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2248 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2251 /* RegSetValueW [ADVAPI32.171] */
2252 DWORD WINAPI
RegSetValue32W(
2262 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2263 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2265 if (lpszSubKey
&& *lpszSubKey
) {
2266 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2267 if (ret
!=ERROR_SUCCESS
)
2271 if (dwType
!=REG_SZ
) {
2272 fprintf(stddeb
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2275 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2276 TRACE(reg
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2277 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2279 cbData
=2*lstrlen32W(lpszData
)+2;
2281 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2287 /* RegSetValueA [ADVAPI32.168] */
2288 DWORD WINAPI
RegSetValue32A(
2298 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2299 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2301 if (lpszSubKey
&& *lpszSubKey
) {
2302 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2303 if (ret
!=ERROR_SUCCESS
)
2308 if (dwType
!=REG_SZ
) {
2309 TRACE(reg
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2312 if (cbData
!=strlen(lpszData
)+1)
2313 cbData
=strlen(lpszData
)+1;
2314 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2320 /* RegSetValue [KERNEL.221] [SHELL.5] */
2321 DWORD WINAPI
RegSetValue16(
2329 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2330 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2332 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2340 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2341 * RegEnumKey32W -> RegEnumKeyEx32W
2344 /* RegEnumKeyExW [ADVAPI32.139] */
2345 DWORD WINAPI
RegEnumKeyEx32W(
2350 LPDWORD lpdwReserved
,
2355 LPKEYSTRUCT lpkey
,lpxkey
;
2357 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2358 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2360 lpkey
=lookup_hkey(hkey
);
2362 return SHELL_ERROR_BADKEY
;
2363 if (!lpkey
->nextsub
)
2364 return ERROR_NO_MORE_ITEMS
;
2365 lpxkey
=lpkey
->nextsub
;
2366 while (iSubkey
&& lpxkey
) {
2368 lpxkey
=lpxkey
->next
;
2370 if (iSubkey
|| !lpxkey
)
2371 return ERROR_NO_MORE_ITEMS
;
2372 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2373 return ERROR_MORE_DATA
;
2374 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2376 /* what should we write into it? */
2380 return ERROR_SUCCESS
;
2384 /* RegEnumKeyW [ADVAPI32.140] */
2385 DWORD WINAPI
RegEnumKey32W(
2393 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2394 hkey
,iSubkey
,lpszName
,lpcchName
2396 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2398 /* RegEnumKeyExA [ADVAPI32.138] */
2399 DWORD WINAPI
RegEnumKeyEx32A(
2404 LPDWORD lpdwReserved
,
2409 DWORD ret
,lpcchNameW
,lpcchClassW
;
2410 LPWSTR lpszNameW
,lpszClassW
;
2413 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2414 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2417 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2418 lpcchNameW
= *lpcchName
*2;
2424 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2425 lpcchClassW
= *lpcchClass
*2;
2430 ret
=RegEnumKeyEx32W(
2440 if (ret
==ERROR_SUCCESS
) {
2441 lstrcpyWtoA(lpszName
,lpszNameW
);
2442 *lpcchName
=strlen(lpszName
);
2444 lstrcpyWtoA(lpszClass
,lpszClassW
);
2445 *lpcchClass
=strlen(lpszClass
);
2455 /* RegEnumKeyA [ADVAPI32.137] */
2456 DWORD WINAPI
RegEnumKey32A(
2464 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2465 hkey
,iSubkey
,lpszName
,lpcchName
2467 return RegEnumKeyEx32A(
2479 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2480 DWORD WINAPI
RegEnumKey16(
2486 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2487 hkey
,iSubkey
,lpszName
,lpcchName
2489 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2493 * Enumerate Registry Values
2496 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2499 /* RegEnumValueW [ADVAPI32.142] */
2500 DWORD WINAPI
RegEnumValue32W(
2505 LPDWORD lpdReserved
,
2513 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2514 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2516 lpkey
= lookup_hkey(hkey
);
2518 return SHELL_ERROR_BADKEY
;
2519 if (lpkey
->nrofvalues
<=iValue
)
2520 return ERROR_NO_MORE_ITEMS
;
2521 val
= lpkey
->values
+iValue
;
2524 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2525 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2526 return ERROR_MORE_DATA
;
2528 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2529 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2535 *lpdwType
=val
->type
;
2537 if (val
->len
>*lpcbData
)
2538 return ERROR_MORE_DATA
;
2539 memcpy(lpbData
,val
->data
,val
->len
);
2540 *lpcbData
= val
->len
;
2542 return SHELL_ERROR_SUCCESS
;
2545 /* RegEnumValueA [ADVAPI32.141] */
2546 DWORD WINAPI
RegEnumValue32A(
2551 LPDWORD lpdReserved
,
2558 DWORD ret
,lpcbDataW
;
2560 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2561 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2564 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2566 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2567 lpcbDataW
= *lpcbData
*2;
2570 ret
=RegEnumValue32W(
2581 if (ret
==ERROR_SUCCESS
) {
2582 lstrcpyWtoA(lpszValue
,lpszValueW
);
2584 if ((1<<*lpdwType
) & UNICONVMASK
) {
2585 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2587 if (lpcbDataW
> *lpcbData
)
2588 ret
= ERROR_MORE_DATA
;
2590 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2592 *lpcbData
= lpcbDataW
;
2602 /* RegEnumValue [KERNEL.223] */
2603 DWORD WINAPI
RegEnumValue16(
2608 LPDWORD lpdReserved
,
2613 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2614 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2616 return RegEnumValue32A(
2629 * Close registry key
2631 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2632 DWORD WINAPI
RegCloseKey(HKEY hkey
) {
2633 TRACE(reg
,"(%x)\n",hkey
);
2634 remove_handle(hkey
);
2635 return ERROR_SUCCESS
;
2638 * Delete registry key
2641 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2643 /* RegDeleteKeyW [ADVAPI32.134] */
2644 DWORD WINAPI
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2645 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2649 TRACE(reg
,"(%x,%s)\n",
2650 hkey
,W2C(lpszSubKey
,0)
2652 lpNextKey
= lookup_hkey(hkey
);
2654 TRACE(reg
, " Badkey[1].\n");
2655 return SHELL_ERROR_BADKEY
;
2657 /* we need to know the previous key in the hier. */
2658 if (!lpszSubKey
|| !*lpszSubKey
) {
2659 TRACE(reg
, " Badkey[2].\n");
2660 return SHELL_ERROR_BADKEY
;
2662 split_keypath(lpszSubKey
,&wps
,&wpc
);
2666 lpxkey
=lpNextKey
->nextsub
;
2668 TRACE(reg
, " Scanning [%s]\n",
2669 W2C (lpxkey
->keyname
, 0));
2670 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2672 lpxkey
=lpxkey
->next
;
2676 TRACE(reg
, " Not found.\n");
2677 /* not found is success */
2678 return SHELL_ERROR_SUCCESS
;
2683 lpxkey
= lpNextKey
->nextsub
;
2684 lplpPrevKey
= &(lpNextKey
->nextsub
);
2686 TRACE(reg
, " Scanning [%s]\n",
2687 W2C (lpxkey
->keyname
, 0));
2688 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2690 lplpPrevKey
= &(lpxkey
->next
);
2691 lpxkey
= lpxkey
->next
;
2695 WARN(reg
, " Not found.\n");
2696 return SHELL_ERROR_BADKEY
;
2698 if (lpxkey
->nextsub
) {
2700 WARN(reg
, " Not empty.\n");
2701 return SHELL_ERROR_CANTWRITE
;
2703 *lplpPrevKey
= lpxkey
->next
;
2704 free(lpxkey
->keyname
);
2706 free(lpxkey
->class);
2708 free(lpxkey
->values
);
2711 TRACE(reg
, " Done.\n");
2712 return SHELL_ERROR_SUCCESS
;
2715 /* RegDeleteKeyA [ADVAPI32.133] */
2716 DWORD WINAPI
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2720 TRACE(reg
,"(%x,%s)\n",
2723 lpszSubKeyW
=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey
);
2724 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2725 HeapFree(GetProcessHeap(),0,lpszSubKeyW
);
2729 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2730 DWORD WINAPI
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2731 TRACE(reg
,"(%x,%s)\n",
2734 return RegDeleteKey32A(hkey
,lpszSubKey
);
2738 * Delete registry value
2741 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2743 /* RegDeleteValueW [ADVAPI32.136] */
2744 DWORD WINAPI
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
)
2750 TRACE(reg
,"(%x,%s)\n",
2751 hkey
,W2C(lpszValue
,0)
2753 lpkey
=lookup_hkey(hkey
);
2755 return SHELL_ERROR_BADKEY
;
2757 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2758 if ( lpkey
->values
[i
].name
&&
2759 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
2763 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2764 if (lpkey
->values
[i
].name
==NULL
)
2767 if (i
==lpkey
->nrofvalues
)
2768 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2769 val
= lpkey
->values
+i
;
2770 if (val
->name
) free(val
->name
);
2771 if (val
->data
) free(val
->data
);
2775 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2777 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2779 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2781 lpkey
->nrofvalues
--;
2782 return SHELL_ERROR_SUCCESS
;
2785 /* RegDeleteValueA [ADVAPI32.135] */
2786 DWORD WINAPI
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
)
2791 TRACE(reg
, "(%x,%s)\n", hkey
,lpszValue
);
2792 lpszValueW
=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue
);
2793 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2794 HeapFree(GetProcessHeap(),0,lpszValueW
);
2798 /* RegDeleteValue [KERNEL.222] */
2799 DWORD WINAPI
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
)
2801 TRACE(reg
,"(%x,%s)\n", hkey
,lpszValue
);
2802 return RegDeleteValue32A(hkey
,lpszValue
);
2805 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2806 DWORD WINAPI
RegFlushKey(HKEY hkey
)
2808 FIXME(reg
, "(%x), STUB.\n", hkey
);
2809 return SHELL_ERROR_SUCCESS
;
2812 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2814 /* RegQueryInfoKeyW [ADVAPI32.153] */
2815 DWORD WINAPI
RegQueryInfoKey32W(
2819 LPDWORD lpdwReserved
,
2821 LPDWORD lpcchMaxSubkey
,
2822 LPDWORD lpcchMaxClass
,
2824 LPDWORD lpcchMaxValueName
,
2825 LPDWORD lpccbMaxValueData
,
2826 LPDWORD lpcbSecurityDescriptor
,
2829 LPKEYSTRUCT lpkey
,lpxkey
;
2830 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2833 TRACE(reg
,"(%x,......)\n",hkey
);
2834 lpkey
=lookup_hkey(hkey
);
2836 return SHELL_ERROR_BADKEY
;
2839 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2840 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2841 return ERROR_MORE_DATA
;
2843 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2844 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2851 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2853 lpxkey
=lpkey
->nextsub
;
2854 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2857 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2858 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2859 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2860 maxclass
=lstrlen32W(lpxkey
->class);
2861 if (lpxkey
->nrofvalues
>maxvalues
)
2862 maxvalues
=lpxkey
->nrofvalues
;
2863 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2864 LPKEYVALUE val
=lpxkey
->values
+i
;
2866 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2867 maxvname
=lstrlen32W(val
->name
);
2868 if (val
->len
>maxvdata
)
2871 lpxkey
=lpxkey
->next
;
2873 if (!maxclass
) maxclass
= 1;
2874 if (!maxvname
) maxvname
= 1;
2876 *lpcSubKeys
= nrofkeys
;
2878 *lpcchMaxSubkey
= maxsubkey
*2;
2880 *lpcchMaxClass
= maxclass
*2;
2882 *lpcValues
= maxvalues
;
2883 if (lpcchMaxValueName
)
2884 *lpcchMaxValueName
= maxvname
;
2885 if (lpccbMaxValueData
)
2886 *lpccbMaxValueData
= maxvdata
;
2887 return SHELL_ERROR_SUCCESS
;
2890 /* RegQueryInfoKeyA [ADVAPI32.152] */
2891 DWORD WINAPI
RegQueryInfoKey32A(
2895 LPDWORD lpdwReserved
,
2897 LPDWORD lpcchMaxSubkey
,
2898 LPDWORD lpcchMaxClass
,
2900 LPDWORD lpcchMaxValueName
,
2901 LPDWORD lpccbMaxValueData
,
2902 LPDWORD lpcbSecurityDescriptor
,
2908 TRACE(reg
,"(%x,......)\n",hkey
);
2911 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2915 ret
=RegQueryInfoKey32W(
2926 lpcbSecurityDescriptor
,
2929 if (ret
==ERROR_SUCCESS
&& lpszClass
)
2930 lstrcpyWtoA(lpszClass
,lpszClassW
);
2937 if (lpcchMaxValueName
)
2938 *lpcchMaxValueName
/=2;
2943 /* RegConnectRegistryA [ADVAPI32.127] */
2944 DWORD WINAPI
RegConnectRegistry32A(LPCSTR machine
,HKEY hkey
,LPHKEY reskey
)
2946 fprintf(stderr
,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
2949 return ERROR_FILE_NOT_FOUND
; /* FIXME */