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 return get_handle(hkey
);
208 * splits the unicode string 'wp' into an array of strings.
209 * the array is allocated by this function.
210 * the number of components will be stored in 'wpc'
211 * Free the array using FREE_KEY_PATH
214 split_keypath(LPCWSTR wp
,LPWSTR
**wpv
,int *wpc
) {
218 ws
= HEAP_strdupW( SystemHeap
, 0, wp
);
220 for (i
=0;ws
[i
];i
++) {
227 *wpv
= (LPWSTR
*)HeapAlloc( SystemHeap
, 0, sizeof(LPWSTR
)*(*wpc
+2));
235 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
238 * Shell initialisation, allocates keys.
240 void SHELL_StartupRegistry();
245 HKEY cl_r_hkey
,c_u_hkey
;
246 #define ADD_ROOT_KEY(xx) \
247 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
248 memset(xx,'\0',sizeof(KEYSTRUCT));\
249 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
251 ADD_ROOT_KEY(key_local_machine
);
252 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&cl_r_hkey
)!=ERROR_SUCCESS
) {
253 ERR(reg
,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
256 key_classes_root
= lookup_hkey(cl_r_hkey
);
258 ADD_ROOT_KEY(key_users
);
261 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
262 * (later, when a win32 registry editing tool becomes avail.)
264 while (pwd
=getpwent()) {
265 if (pwd
->pw_name
== NULL
)
267 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
268 RegCloseKey(c_u_hkey
);
271 pwd
=getpwuid(getuid());
272 if (pwd
&& pwd
->pw_name
) {
273 RegCreateKey16(HKEY_USERS
,pwd
->pw_name
,&c_u_hkey
);
274 key_current_user
= lookup_hkey(c_u_hkey
);
276 ADD_ROOT_KEY(key_current_user
);
278 ADD_ROOT_KEY(key_performance_data
);
279 ADD_ROOT_KEY(key_current_config
);
280 ADD_ROOT_KEY(key_dyn_data
);
282 SHELL_StartupRegistry();
287 SHELL_StartupRegistry() {
291 RegCreateKey16(HKEY_DYN_DATA
,"\\PerfStats\\StatData",&hkey
);
294 RegOpenKey16(HKEY_LOCAL_MACHINE
,"\\HARDWARE\\DESCRIPTION\\System",&hkey
);
295 RegSetValueEx32A(hkey
,"Identifier",0,REG_SZ
,"SystemType WINE",strlen("SystemType WINE"));
297 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
301 * string RegisteredOwner
302 * string RegisteredOrganization
305 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
310 if (-1!=gethostname(buf
,200)) {
311 RegCreateKey16(HKEY_LOCAL_MACHINE
,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey
);
312 RegSetValueEx16(hkey
,"ComputerName",0,REG_SZ
,buf
,strlen(buf
)+1);
316 /************************ SAVE Registry Function ****************************/
318 #define REGISTRY_SAVE_VERSION 0x00000001
320 /* Registry saveformat:
321 * If you change it, increase above number by 1, which will flush
322 * old registry database files.
325 * "WINE REGISTRY Version %d"
329 * valuename=lastmodified,type,data
333 * keyname,valuename,stringdata:
334 * the usual ascii characters from 0x00-0xff (well, not 0x00)
335 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
336 * ( "=\\\t" escaped in \uXXXX form.)
340 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
342 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
343 * SaveOnlyUpdatedKeys=yes
346 _save_check_tainted(LPKEYSTRUCT lpkey
) {
351 if (lpkey
->flags
& REG_OPTION_TAINTED
)
356 if (_save_check_tainted(lpkey
->nextsub
)) {
357 lpkey
->flags
|= REG_OPTION_TAINTED
;
366 _save_USTRING(FILE *F
,LPWSTR wstr
,int escapeeq
) {
379 if (escapeeq
&& *s
=='=')
382 fputc(*s
,F
); /* if \\ then put it twice. */
384 fprintf(F
,"\\u%04x",*((unsigned short*)s
));
392 _savesubkey(FILE *F
,LPKEYSTRUCT lpkey
,int level
,int all
) {
398 if ( !(lpxkey
->flags
& REG_OPTION_VOLATILE
) &&
399 (all
|| (lpxkey
->flags
& REG_OPTION_TAINTED
))
401 for (tabs
=level
;tabs
--;)
403 _save_USTRING(F
,lpxkey
->keyname
,1);
405 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
406 LPKEYVALUE val
=lpxkey
->values
+i
;
408 for (tabs
=level
+1;tabs
--;)
410 _save_USTRING(F
,val
->name
,0);
412 fprintf(F
,"%ld,%ld,",val
->type
,val
->lastmodified
);
413 if ((1<<val
->type
) & UNICONVMASK
)
414 _save_USTRING(F
,(LPWSTR
)val
->data
,0);
416 for (j
=0;j
<val
->len
;j
++)
417 fprintf(F
,"%02x",*((unsigned char*)val
->data
+j
));
420 /* descend recursively */
421 if (!_savesubkey(F
,lpxkey
->nextsub
,level
+1,all
))
430 _savesubreg(FILE *F
,LPKEYSTRUCT lpkey
,int all
) {
431 fprintf(F
,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION
);
432 _save_check_tainted(lpkey
->nextsub
);
433 return _savesubkey(F
,lpkey
->nextsub
,0,all
);
437 _savereg(LPKEYSTRUCT lpkey
,char *fn
,int all
) {
442 WARN(reg
,"Couldn't open %s for writing: %s\n",
447 if (!_savesubreg(F
,lpkey
,all
)) {
450 WARN(reg
,"Failed to save keys, perhaps no more diskspace for %s?\n",fn
);
458 SHELL_SaveRegistry() {
466 if (RegOpenKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)!=ERROR_SUCCESS
) {
472 if ( (ERROR_SUCCESS
!=RegQueryValueEx32A(
484 if (lstrcmpi32A(buf
,"yes"))
486 pwd
=getpwuid(getuid());
487 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
)
491 fn
=(char*)xmalloc( strlen(pwd
->pw_dir
) + strlen(WINE_PREFIX
) +
492 strlen(SAVE_CURRENT_USER
) + 2 );
493 strcpy(fn
,pwd
->pw_dir
);
494 strcat(fn
,WINE_PREFIX
);
495 /* create the directory. don't care about errorcodes. */
496 mkdir(fn
,0755); /* drwxr-xr-x */
497 strcat(fn
,"/"SAVE_CURRENT_USER
);
498 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
499 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
500 if (_savereg(key_current_user
,tmp
,all
)) {
501 if (-1==rename(tmp
,fn
)) {
502 perror("rename tmp registry");
508 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
509 strcpy(fn
,pwd
->pw_dir
);
510 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
511 tmp
= (char*)xmalloc(strlen(fn
)+strlen(".tmp")+1);
512 strcpy(tmp
,fn
);strcat(tmp
,".tmp");
513 if (_savereg(key_local_machine
,tmp
,all
)) {
514 if (-1==rename(tmp
,fn
)) {
515 perror("rename tmp registry");
522 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
525 /************************ LOAD Registry Function ****************************/
528 _find_or_add_key(LPKEYSTRUCT lpkey
,LPWSTR keyname
) {
529 LPKEYSTRUCT lpxkey
,*lplpkey
;
535 lplpkey
= &(lpkey
->nextsub
);
538 if (!lstrcmpi32W(lpxkey
->keyname
,keyname
))
540 lplpkey
= &(lpxkey
->next
);
544 *lplpkey
= (LPKEYSTRUCT
)xmalloc(sizeof(KEYSTRUCT
));
546 memset(lpxkey
,'\0',sizeof(KEYSTRUCT
));
547 lpxkey
->keyname
= keyname
;
555 LPKEYSTRUCT lpkey
,LPWSTR name
,DWORD type
,LPBYTE data
,DWORD len
,
561 if (name
&& !*name
) {/* empty string equals default (NULL) value */
566 for (i
=0;i
<lpkey
->nrofvalues
;i
++) {
572 if ( val
->name
!=NULL
&&
573 !lstrcmpi32W(val
->name
,name
)
578 if (i
==lpkey
->nrofvalues
) {
579 lpkey
->values
= xrealloc(
581 (++lpkey
->nrofvalues
)*sizeof(KEYVALUE
)
584 memset(val
,'\0',sizeof(KEYVALUE
));
590 if (val
->lastmodified
<lastmodified
) {
591 val
->lastmodified
=lastmodified
;
602 /* reads a line including dynamically enlarging the readbuffer and throwing
606 _wine_read_line(FILE *F
,char **buf
,int *len
) {
615 s
=fgets(curread
,mylen
,F
);
618 if (NULL
==(s
=strchr(curread
,'\n'))) {
619 /* buffer wasn't large enough */
620 curoff
= strlen(*buf
);
621 *buf
= xrealloc(*buf
,*len
*2);
622 curread
= *buf
+ curoff
;
623 mylen
= *len
; /* we filled up the buffer and
624 * got new '*len' bytes to fill
632 /* throw away comments */
633 if (**buf
=='#' || **buf
==';') {
638 if (s
) /* got end of line */
644 /* converts a char* into a UNICODE string (up to a special char)
645 * and returns the position exactly after that string
648 _wine_read_USTRING(char *buf
,LPWSTR
*str
) {
652 /* read up to "=" or "\0" or "\n" */
655 /* empty string is the win3.1 default value(NULL)*/
659 *str
= (LPWSTR
)xmalloc(2*strlen(buf
)+2);
661 while (*s
&& (*s
!='\n') && (*s
!='=')) {
663 *ws
++=*((unsigned char*)s
++);
672 WARN(reg
,"Non unicode escape sequence \\%c found in |%s|\n",*s
,buf
);
680 memcpy(xbuf
,s
,4);xbuf
[4]='\0';
681 if (!sscanf(xbuf
,"%x",&wc
))
682 WARN(reg
,"Strange escape sequence %s found in |%s|\n",xbuf
,buf
);
684 *ws
++ =(unsigned short)wc
;
691 *str
= strdupW(*str
);
700 FILE *F
,LPKEYSTRUCT lpkey
,int level
,char **buf
,int *buflen
,int optflag
707 lpkey
->flags
|= optflag
;
709 /* good. we already got a line here ... so parse it */
719 WARN(reg
,"Got a subhierarchy without resp. key?\n");
722 _wine_loadsubkey(F
,lpxkey
,level
+1,buf
,buflen
,optflag
);
725 /* let the caller handle this line */
726 if (i
<level
|| **buf
=='\0')
729 /* it can be: a value or a keyname. Parse the name first */
730 s
=_wine_read_USTRING(s
,&name
);
732 /* switch() default: hack to avoid gotos */
736 lpxkey
=_find_or_add_key(lpkey
,name
);
739 int len
,lastmodified
,type
;
742 WARN(reg
,"Unexpected character: %c\n",*s
);
746 if (2!=sscanf(s
,"%d,%d,",&type
,&lastmodified
)) {
747 WARN(reg
,"Haven't understood possible value in |%s|, skipping.\n",*buf
);
753 if ((1<<type
) & UNICONVMASK
) {
754 s
=_wine_read_USTRING(s
,(LPWSTR
*)&data
);
756 len
= lstrlen32W((LPWSTR
)data
)*2+2;
761 data
= (LPBYTE
)xmalloc(len
+1);
762 for (i
=0;i
<len
;i
++) {
764 if (*s
>='0' && *s
<='9')
766 if (*s
>='a' && *s
<='f')
767 data
[i
]=(*s
-'a'+'\xa')<<4;
768 if (*s
>='A' && *s
<='F')
769 data
[i
]=(*s
-'A'+'\xa')<<4;
771 if (*s
>='0' && *s
<='9')
773 if (*s
>='a' && *s
<='f')
774 data
[i
]|=*s
-'a'+'\xa';
775 if (*s
>='A' && *s
<='F')
776 data
[i
]|=*s
-'A'+'\xa';
780 _find_or_add_value(lpkey
,name
,type
,data
,len
,lastmodified
);
783 /* read the next line */
784 if (!_wine_read_line(F
,buf
,buflen
))
791 _wine_loadsubreg(FILE *F
,LPKEYSTRUCT lpkey
,int optflag
) {
796 buf
=xmalloc(10);buflen
=10;
797 if (!_wine_read_line(F
,&buf
,&buflen
)) {
801 if (!sscanf(buf
,"WINE REGISTRY Version %d",&ver
)) {
805 if (ver
!=REGISTRY_SAVE_VERSION
) {
806 TRACE(reg
,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver
,buf
);
810 if (!_wine_read_line(F
,&buf
,&buflen
)) {
814 if (!_wine_loadsubkey(F
,lpkey
,0,&buf
,&buflen
,optflag
)) {
823 _wine_loadreg(LPKEYSTRUCT lpkey
,char *fn
,int optflag
) {
828 WARN(reg
,"Couldn't open %s for reading: %s\n",
833 if (!_wine_loadsubreg(F
,lpkey
,optflag
)) {
842 _copy_registry(LPKEYSTRUCT from
,LPKEYSTRUCT to
) {
849 lpxkey
= _find_or_add_key(to
,strdupW(from
->keyname
));
851 for (j
=0;j
<from
->nrofvalues
;j
++) {
855 valfrom
= from
->values
+j
;
857 if (name
) name
=strdupW(name
);
858 data
=(LPBYTE
)xmalloc(valfrom
->len
);
859 memcpy(data
,valfrom
->data
,valfrom
->len
);
867 valfrom
->lastmodified
870 _copy_registry(from
,lpxkey
);
875 /* WINDOWS 95 REGISTRY LOADER */
877 * Structure of a win95 registry database.
881 * 8 : DWORD offset_of_RGDB_part
882 * 0C..0F: ? (someone fill in please)
883 * 10: WORD number of RGDB blocks
885 * 14: WORD always 0000?
886 * 16: WORD always 0001?
887 * 18..1F: ? (someone fill in please)
892 * 4 : DWORD offset to first RGDB section
893 * 8 : DWORD offset to ?
894 * C..0x1B: ? (fill in)
895 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
897 * Disk Key Entry Structure:
898 * 00: DWORD - Free entry indicator(?)
899 * 04: DWORD - Hash = sum of bytes of keyname
900 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
901 * 0C: DWORD - disk address of PreviousLevel Key.
902 * 10: DWORD - disk address of Next Sublevel Key.
903 * 14: DWORD - disk address of Next Key (on same level).
904 * DKEP>18: WORD - Nr, Low Significant part.
905 * 1A: WORD - Nr, High Significant part.
907 * The disk address always points to the nr part of the previous key entry
908 * of the referenced key. Don't ask me why, or even if I got this correct
909 * from staring at 1kg of hexdumps. (DKEP)
911 * The High significant part of the structure seems to equal the number
912 * of the RGDB section. The low significant part is a unique ID within
915 * There are two minor corrections to the position of that structure.
916 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
917 * the DKE reread from there.
918 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
919 * CPS - I have not experienced the above phenomenon in my registry files
923 * 04: DWORD offset to next RGDB section
925 * 0C: WORD always 000d?
926 * 0E: WORD RGDB block number
927 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
932 * 00: DWORD nextkeyoffset - offset to the next disk key structure
933 * 08: WORD nrLS - low significant part of NR
934 * 0A: WORD nrHS - high significant part of NR
935 * 0C: DWORD bytesused - bytes used in this structure.
936 * 10: WORD name_len - length of name in bytes. without \0
937 * 12: WORD nr_of_values - number of values.
938 * 14: char name[name_len] - name string. No \0.
939 * 14+name_len: disk values
940 * nextkeyoffset: ... next disk key
943 * 00: DWORD type - value type (hmm, could be WORD too)
944 * 04: DWORD - unknown, usually 0
945 * 08: WORD namelen - length of Name. 0 means name=NULL
946 * 0C: WORD datalen - length of Data.
947 * 10: char name[namelen] - name, no \0
948 * 10+namelen: BYTE data[datalen] - data, without \0 if string
949 * 10+namelen+datalen: next values or disk key
951 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
952 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
953 * structure) and reading another RGDB_section.
954 * repeat until end of file.
956 * An interesting relationship exists in RGDB_section. The value at offset
957 * 10 equals the value at offset 4 minus the value at offset 8. I have no
958 * idea at the moment what this means. (Kevin Cozens)
960 * FIXME: this description needs some serious help, yes.
963 struct _w95keyvalue
{
965 unsigned short datalen
;
975 struct _w95keyvalue
*values
;
976 struct _w95key
*prevlvl
;
977 struct _w95key
*nextsub
;
978 struct _w95key
*next
;
991 LPWSTR
strcvtA2W(LPCSTR src
, int nchars
)
994 LPWSTR dest
= xmalloc (2 * nchars
+ 2);
996 lstrcpynAtoW(dest
,src
,nchars
+1);
1001 static LPKEYSTRUCT
_w95_processKey ( LPKEYSTRUCT lpkey
,
1002 int nrLS
, int nrMS
, struct _w95_info
*info
)
1005 /* Disk Key Header structure (RGDB part) */
1007 unsigned long nextkeyoff
;
1008 unsigned short nrLS
;
1009 unsigned short nrMS
;
1010 unsigned long bytesused
;
1011 unsigned short keynamelen
;
1012 unsigned short values
;
1015 /* disk key values or nothing */
1017 /* Disk Key Value structure */
1021 unsigned short valnamelen
;
1022 unsigned short valdatalen
;
1023 /* valname, valdata */
1029 char *rgdbdata
= info
->rgdbbuffer
;
1030 int nbytes
= info
->rgdbsize
;
1031 char *curdata
= rgdbdata
;
1032 char *end
= rgdbdata
+ nbytes
;
1034 char *next
= rgdbdata
;
1040 if (strncmp(curdata
, "RGDB", 4)) return (NULL
);
1042 memcpy(&off_next_rgdb
,curdata
+4,4);
1043 next
= curdata
+ off_next_rgdb
;
1044 nrgdb
= (int) *((short *)curdata
+ 7);
1046 } while (nrgdb
!= nrMS
&& (next
< end
));
1048 /* curdata now points to the start of the right RGDB section */
1051 #define XREAD(whereto,len) \
1052 if ((curdata + len) <end) {\
1053 memcpy(whereto,curdata,len);\
1059 XREAD(&dkh
, sizeof (dkh
));
1060 if (dkh
.nrLS
== nrLS
) break;
1062 curdata
+= dkh
.nextkeyoff
- sizeof(dkh
);
1063 } while (curdata
< next
);
1065 if (dkh
.nrLS
!= nrLS
) return (NULL
);
1067 if (nrgdb
!= dkh
.nrMS
) {
1071 assert((dkh
.keynamelen
<2) || curdata
[0]);
1072 lpxkey
=_find_or_add_key(lpkey
,strcvtA2W(curdata
, dkh
.keynamelen
));
1073 curdata
+= dkh
.keynamelen
;
1075 for (i
=0;i
< dkh
.values
; i
++) {
1081 XREAD(&dkv
,sizeof(dkv
));
1083 name
= strcvtA2W(curdata
, dkv
.valnamelen
);
1084 curdata
+= dkv
.valnamelen
;
1086 if ((1 << dkv
.type
) & UNICONVMASK
) {
1087 data
= (LPBYTE
) strcvtA2W(curdata
, dkv
.valdatalen
);
1088 len
= 2*(dkv
.valdatalen
+ 1);
1090 /* I don't think we want to NULL terminate all data */
1091 data
= xmalloc(dkv
.valdatalen
);
1092 memcpy (data
, curdata
, dkv
.valdatalen
);
1093 len
= dkv
.valdatalen
;
1096 curdata
+= dkv
.valdatalen
;
1113 _w95_walkrgkn(LPKEYSTRUCT prevkey
, char *off
, struct _w95_info
*info
)
1116 /* Disk Key Entry structure (RGKN part) */
1120 unsigned long x3
;/*usually 0xFFFFFFFF */
1121 unsigned long prevlvl
;
1122 unsigned long nextsub
;
1124 unsigned short nrLS
;
1125 unsigned short nrMS
;
1126 } *dke
= (struct dke
*)off
;
1130 dke
= (struct dke
*) ((char *)info
->rgknbuffer
);
1133 lpxkey
= _w95_processKey(prevkey
, dke
->nrLS
, dke
->nrMS
, info
);
1134 /* XXX <-- This is a hack*/
1139 if (dke
->nextsub
!= -1 &&
1140 ((dke
->nextsub
- 0x20) < info
->rgknsize
)
1141 && (dke
->nextsub
> 0x20)) {
1143 _w95_walkrgkn(lpxkey
,
1144 info
->rgknbuffer
+ dke
->nextsub
- 0x20,
1148 if (dke
->next
!= -1 &&
1149 ((dke
->next
- 0x20) < info
->rgknsize
) &&
1150 (dke
->next
> 0x20)) {
1151 _w95_walkrgkn(prevkey
,
1152 info
->rgknbuffer
+ dke
->next
- 0x20,
1160 _w95_loadreg(char* fn
,LPKEYSTRUCT lpkey
) {
1163 unsigned long where
,version
,rgdbsection
,end
;
1164 struct _w95_info info
;
1166 BY_HANDLE_FILE_INFORMATION hfdinfo
;
1168 TRACE(reg
,"Loading Win95 registry database '%s'\n",fn
);
1169 hfd
=OpenFile32(fn
,&ofs
,OF_READ
);
1170 if (hfd
==HFILE_ERROR32
)
1173 if (4!=_lread32(hfd
,magic
,4))
1175 if (strcmp(magic
,"CREG")) {
1176 WARN(reg
,"%s is not a w95 registry.\n",fn
);
1179 if (4!=_lread32(hfd
,&version
,4))
1181 if (4!=_lread32(hfd
,&rgdbsection
,4))
1183 if (-1==_llseek32(hfd
,0x20,SEEK_SET
))
1185 if (4!=_lread32(hfd
,magic
,4))
1187 if (strcmp(magic
,"RGKN")) {
1188 WARN(reg
, "second IFF header not RGKN, but %s\n", magic
);
1192 /* STEP 1: Keylink structures */
1193 if (-1==_llseek32(hfd
,0x40,SEEK_SET
))
1198 info
.rgknsize
= end
- where
;
1199 info
.rgknbuffer
= (char*)xmalloc(info
.rgknsize
);
1200 if (info
.rgknsize
!= _lread32(hfd
,info
.rgknbuffer
,info
.rgknsize
))
1203 if (!GetFileInformationByHandle(hfd
,&hfdinfo
))
1206 end
= hfdinfo
.nFileSizeLow
;
1207 info
.lastmodified
= DOSFS_FileTimeToUnixTime(&hfdinfo
.ftLastWriteTime
,NULL
);
1209 if (-1==_llseek32(hfd
,rgdbsection
,SEEK_SET
))
1212 info
.rgdbbuffer
= (char*)xmalloc(end
-rgdbsection
);
1213 info
.rgdbsize
= end
- rgdbsection
;
1215 if (info
.rgdbsize
!=_lread32(hfd
,info
.rgdbbuffer
,info
.rgdbsize
))
1219 _w95_walkrgkn(lpkey
, NULL
, &info
);
1221 free (info
.rgdbbuffer
);
1222 free (info
.rgknbuffer
);
1225 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1228 reghack - windows 3.11 registry data format demo program.
1230 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1231 a combined hash table and tree description, and finally a text table.
1233 The header is obvious from the struct header. The taboff1 and taboff2
1234 fields are always 0x20, and their usage is unknown.
1236 The 8-byte entry table has various entry types.
1238 tabent[0] is a root index. The second word has the index of the root of
1240 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1241 the index of the key/value that has that hash. Data with the same
1242 hash value are on a circular list. The other three words in the
1243 hash entry are always zero.
1244 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1245 entry: dirent and keyent/valent. They are identified by context.
1246 tabent[freeidx] is the first free entry. The first word in a free entry
1247 is the index of the next free entry. The last has 0 as a link.
1248 The other three words in the free list are probably irrelevant.
1250 Entries in text table are preceeded by a word at offset-2. This word
1251 has the value (2*index)+1, where index is the referring keyent/valent
1252 entry in the table. I have no suggestion for the 2* and the +1.
1253 Following the word, there are N bytes of data, as per the keyent/valent
1254 entry length. The offset of the keyent/valent entry is from the start
1255 of the text table to the first data byte.
1257 This information is not available from Microsoft. The data format is
1258 deduced from the reg.dat file by me. Mistakes may
1259 have been made. I claim no rights and give no guarantees for this program.
1261 Tor Sjøwall, tor@sn.no
1264 /* reg.dat header format */
1265 struct _w31_header
{
1266 char cookie
[8]; /* 'SHCC3.10' */
1267 unsigned long taboff1
; /* offset of hash table (??) = 0x20 */
1268 unsigned long taboff2
; /* offset of index table (??) = 0x20 */
1269 unsigned long tabcnt
; /* number of entries in index table */
1270 unsigned long textoff
; /* offset of text part */
1271 unsigned long textsize
; /* byte size of text part */
1272 unsigned short hashsize
; /* hash size */
1273 unsigned short freeidx
; /* free index */
1276 /* generic format of table entries */
1277 struct _w31_tabent
{
1278 unsigned short w0
, w1
, w2
, w3
;
1281 /* directory tabent: */
1282 struct _w31_dirent
{
1283 unsigned short sibling_idx
; /* table index of sibling dirent */
1284 unsigned short child_idx
; /* table index of child dirent */
1285 unsigned short key_idx
; /* table index of key keyent */
1286 unsigned short value_idx
; /* table index of value valent */
1290 struct _w31_keyent
{
1291 unsigned short hash_idx
; /* hash chain index for string */
1292 unsigned short refcnt
; /* reference count */
1293 unsigned short length
; /* length of string */
1294 unsigned short string_off
; /* offset of string in text table */
1298 struct _w31_valent
{
1299 unsigned short hash_idx
; /* hash chain index for string */
1300 unsigned short refcnt
; /* reference count */
1301 unsigned short length
; /* length of string */
1302 unsigned short string_off
; /* offset of string in text table */
1305 /* recursive helper function to display a directory tree */
1307 __w31_dumptree( unsigned short idx
,
1309 struct _w31_tabent
*tab
,
1310 struct _w31_header
*head
,
1312 time_t lastmodified
,
1315 struct _w31_dirent
*dir
;
1316 struct _w31_keyent
*key
;
1317 struct _w31_valent
*val
;
1318 LPKEYSTRUCT xlpkey
= NULL
;
1320 static char tail
[400];
1323 dir
=(struct _w31_dirent
*)&tab
[idx
];
1326 key
= (struct _w31_keyent
*)&tab
[dir
->key_idx
];
1328 memcpy(tail
,&txt
[key
->string_off
],key
->length
);
1329 tail
[key
->length
]='\0';
1330 /* all toplevel entries AND the entries in the
1331 * toplevel subdirectory belong to \SOFTWARE\Classes
1333 if (!level
&& !lstrcmp32A(tail
,".classes")) {
1334 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,lpkey
,lastmodified
,level
+1);
1335 idx
=dir
->sibling_idx
;
1338 name
=strdupA2W(tail
);
1340 xlpkey
=_find_or_add_key(lpkey
,name
);
1342 /* only add if leaf node or valued node */
1343 if (dir
->value_idx
!=0||dir
->child_idx
==0) {
1344 if (dir
->value_idx
) {
1345 val
=(struct _w31_valent
*)&tab
[dir
->value_idx
];
1346 memcpy(tail
,&txt
[val
->string_off
],val
->length
);
1347 tail
[val
->length
]='\0';
1348 value
=strdupA2W(tail
);
1349 _find_or_add_value(xlpkey
,NULL
,REG_SZ
,(LPBYTE
)value
,lstrlen32W(value
)*2+2,lastmodified
);
1353 TRACE(reg
,"strange: no directory key name, idx=%04x\n", idx
);
1355 __w31_dumptree(dir
->child_idx
,txt
,tab
,head
,xlpkey
,lastmodified
,level
+1);
1356 idx
=dir
->sibling_idx
;
1363 struct _w31_header head
;
1364 struct _w31_tabent
*tab
;
1368 BY_HANDLE_FILE_INFORMATION hfinfo
;
1369 time_t lastmodified
;
1373 hf
= OpenFile32("reg.dat",&ofs
,OF_READ
);
1374 if (hf
==HFILE_ERROR32
)
1377 /* read & dump header */
1378 if (sizeof(head
)!=_lread32(hf
,&head
,sizeof(head
))) {
1379 ERR(reg
, "reg.dat is too short.\n");
1383 if (memcmp(head
.cookie
, "SHCC3.10", sizeof(head
.cookie
))!=0) {
1384 ERR(reg
, "reg.dat has bad signature.\n");
1389 len
= head
.tabcnt
* sizeof(struct _w31_tabent
);
1390 /* read and dump index table */
1392 if (len
!=_lread32(hf
,tab
,len
)) {
1393 ERR(reg
,"couldn't read %d bytes.\n",len
);
1400 txt
= xmalloc(head
.textsize
);
1401 if (-1==_llseek32(hf
,head
.textoff
,SEEK_SET
)) {
1402 ERR(reg
,"couldn't seek to textblock.\n");
1408 if (head
.textsize
!=_lread32(hf
,txt
,head
.textsize
)) {
1409 ERR(reg
,"textblock too short (%d instead of %ld).\n",len
,head
.textsize
);
1416 if (!GetFileInformationByHandle(hf
,&hfinfo
)) {
1417 ERR(reg
,"GetFileInformationByHandle failed?.\n");
1423 lastmodified
= DOSFS_FileTimeToUnixTime(&hfinfo
.ftLastWriteTime
,NULL
);
1425 if (RegCreateKey16(HKEY_LOCAL_MACHINE
,"\\SOFTWARE\\Classes",&hkey
)!=ERROR_SUCCESS
)
1427 lpkey
= lookup_hkey(hkey
);
1428 __w31_dumptree(tab
[0].w1
,txt
,tab
,&head
,lpkey
,lastmodified
,0);
1436 SHELL_LoadRegistry() {
1443 if (key_classes_root
==NULL
)
1446 /* Load windows 3.1 entries */
1448 /* Load windows 95 entries */
1449 _w95_loadreg("C:\\system.1st", key_local_machine
);
1450 _w95_loadreg("system.dat", key_local_machine
);
1451 _w95_loadreg("user.dat", key_users
);
1453 /* the global user default is loaded under HKEY_USERS\\.Default */
1454 RegCreateKey16(HKEY_USERS
,".Default",&hkey
);
1455 lpkey
= lookup_hkey(hkey
);
1456 _wine_loadreg(lpkey
,SAVE_USERS_DEFAULT
,0);
1458 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1459 _copy_registry(lpkey
,key_current_user
);
1462 /* the global machine defaults */
1463 _wine_loadreg(key_local_machine
,SAVE_LOCAL_MACHINE_DEFAULT
,0);
1465 /* load the user saved registries */
1467 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1469 pwd
=getpwuid(getuid());
1470 if (pwd
!=NULL
&& pwd
->pw_dir
!=NULL
) {
1471 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_CURRENT_USER
)+2);
1472 strcpy(fn
,pwd
->pw_dir
);
1473 strcat(fn
,WINE_PREFIX
"/"SAVE_CURRENT_USER
);
1474 _wine_loadreg(key_current_user
,fn
,REG_OPTION_TAINTED
);
1476 fn
=(char*)xmalloc(strlen(pwd
->pw_dir
)+strlen(WINE_PREFIX
)+strlen(SAVE_LOCAL_MACHINE
)+2);
1477 strcpy(fn
,pwd
->pw_dir
);
1478 strcat(fn
,WINE_PREFIX
"/"SAVE_LOCAL_MACHINE
);
1479 _wine_loadreg(key_local_machine
,fn
,REG_OPTION_TAINTED
);
1482 WARN(reg
,"Failed to get homedirectory of UID %d.\n",getuid());
1483 if (ERROR_SUCCESS
==RegCreateKey16(HKEY_CURRENT_USER
,KEY_REGISTRY
,&hkey
)) {
1484 DWORD junk
,type
,len
;
1488 if (( RegQueryValueEx32A(
1495 )!=ERROR_SUCCESS
) ||
1498 RegSetValueEx32A(hkey
,VAL_SAVEUPDATED
,0,REG_SZ
,"yes",4);
1504 /********************* API FUNCTIONS ***************************************/
1508 * All functions are stubs to RegOpenKeyEx32W where all the
1511 * FIXME: security,options,desiredaccess,...
1514 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1515 * RegOpenKey32W -> RegOpenKeyEx32W
1518 /* RegOpenKeyExW [ADVAPI32.150] */
1519 DWORD WINAPI
RegOpenKeyEx32W(
1526 LPKEYSTRUCT lpNextKey
,lpxkey
;
1529 TRACE(reg
,"(%lx,%s,%ld,%lx,%p)\n",
1530 (LONG
)hkey
,W2C(lpszSubKey
,0),dwReserved
,samDesired
,retkey
1533 lpNextKey
= lookup_hkey(hkey
);
1535 return SHELL_ERROR_BADKEY
;
1536 if (!lpszSubKey
|| !*lpszSubKey
) {
1537 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1538 *retkey
=currenthandle
;
1539 return SHELL_ERROR_SUCCESS
;
1541 split_keypath(lpszSubKey
,&wps
,&wpc
);
1543 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1546 lpxkey
=lpNextKey
->nextsub
;
1548 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1550 lpxkey
=lpxkey
->next
;
1554 return SHELL_ERROR_BADKEY
;
1559 add_handle(++currenthandle
,lpxkey
,samDesired
);
1560 *retkey
= currenthandle
;
1562 return SHELL_ERROR_SUCCESS
;
1565 /* RegOpenKeyW [ADVAPI32.151] */
1566 DWORD WINAPI
RegOpenKey32W(
1571 TRACE(reg
,"(%lx,%s,%p)\n",
1572 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1574 return RegOpenKeyEx32W(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1578 /* RegOpenKeyExA [ADVAPI32.149] */
1579 DWORD WINAPI
RegOpenKeyEx32A(
1589 TRACE(reg
,"(%lx,%s,%ld,%lx,%p)\n",
1590 (LONG
)hkey
,lpszSubKey
,dwReserved
,samDesired
,retkey
1593 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1596 ret
=RegOpenKeyEx32W(hkey
,lpszSubKeyW
,dwReserved
,samDesired
,retkey
);
1602 /* RegOpenKeyA [ADVAPI32.148] */
1603 DWORD WINAPI
RegOpenKey32A(
1608 TRACE(reg
,"(%lx,%s,%p)\n",
1609 (LONG
)hkey
,lpszSubKey
,retkey
1611 return RegOpenKeyEx32A(hkey
,lpszSubKey
,0,KEY_ALL_ACCESS
,retkey
);
1614 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1615 DWORD WINAPI
RegOpenKey16(
1620 TRACE(reg
,"(%lx,%s,%p)\n",
1621 (LONG
)hkey
,lpszSubKey
,retkey
1623 return RegOpenKey32A(hkey
,lpszSubKey
,retkey
);
1629 * All those functions convert their respective
1630 * arguments and call RegCreateKeyExW at the end.
1632 * FIXME: no security,no access attrib,no optionhandling yet.
1635 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1636 * RegCreateKey32W -> RegCreateKeyEx32W
1639 /* RegCreateKeyExW [ADVAPI32.131] */
1640 DWORD WINAPI
RegCreateKeyEx32W(
1647 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1651 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
1655 /*FIXME: handle security/access/whatever */
1656 TRACE(reg
,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1668 lpNextKey
= lookup_hkey(hkey
);
1670 return SHELL_ERROR_BADKEY
;
1671 if (!lpszSubKey
|| !*lpszSubKey
) {
1672 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1673 *retkey
=currenthandle
;
1674 lpNextKey
->flags
|=REG_OPTION_TAINTED
;
1675 return SHELL_ERROR_SUCCESS
;
1677 split_keypath(lpszSubKey
,&wps
,&wpc
);
1679 while ((i
<wpc
) && (wps
[i
][0]=='\0')) i
++;
1682 lpxkey
=lpNextKey
->nextsub
;
1684 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
1686 lpxkey
=lpxkey
->next
;
1694 add_handle(++currenthandle
,lpxkey
,samDesired
);
1695 lpxkey
->flags
|= REG_OPTION_TAINTED
;
1696 *retkey
= currenthandle
;
1698 *lpDispos
= REG_OPENED_EXISTING_KEY
;
1700 return SHELL_ERROR_SUCCESS
;
1702 /* good. now the hard part */
1704 lplpPrevKey
= &(lpNextKey
->nextsub
);
1705 lpxkey
= *lplpPrevKey
;
1707 lplpPrevKey
= &(lpxkey
->next
);
1708 lpxkey
= *lplpPrevKey
;
1710 *lplpPrevKey
=malloc(sizeof(KEYSTRUCT
));
1711 if (!*lplpPrevKey
) {
1713 return SHELL_ERROR_OUTOFMEMORY
;
1715 memset(*lplpPrevKey
,'\0',sizeof(KEYSTRUCT
));
1716 (*lplpPrevKey
)->keyname
= strdupW(wps
[i
]);
1717 (*lplpPrevKey
)->next
= NULL
;
1718 (*lplpPrevKey
)->nextsub
= NULL
;
1719 (*lplpPrevKey
)->values
= NULL
;
1720 (*lplpPrevKey
)->nrofvalues
= 0;
1721 (*lplpPrevKey
)->flags
= REG_OPTION_TAINTED
;
1723 (*lplpPrevKey
)->class = strdupW(lpszClass
);
1725 (*lplpPrevKey
)->class = NULL
;
1726 lpNextKey
= *lplpPrevKey
;
1729 add_handle(++currenthandle
,lpNextKey
,samDesired
);
1731 /*FIXME: flag handling correct? */
1732 lpNextKey
->flags
= fdwOptions
|REG_OPTION_TAINTED
;
1734 lpNextKey
->class = strdupW(lpszClass
);
1736 lpNextKey
->class = NULL
;
1737 *retkey
= currenthandle
;
1739 *lpDispos
= REG_CREATED_NEW_KEY
;
1741 return SHELL_ERROR_SUCCESS
;
1744 /* RegCreateKeyW [ADVAPI32.132] */
1745 DWORD WINAPI
RegCreateKey32W(
1752 TRACE(reg
,"(%lx,%s,%p)\n",
1753 (LONG
)hkey
,W2C(lpszSubKey
,0),retkey
1755 ret
=RegCreateKeyEx32W(
1756 hkey
, /* key handle */
1757 lpszSubKey
, /* subkey name */
1758 0, /* reserved = 0 */
1759 NULL
, /* lpszClass? FIXME: ? */
1760 REG_OPTION_NON_VOLATILE
, /* options */
1761 KEY_ALL_ACCESS
, /* desired access attribs */
1762 NULL
, /* lpsecurity attributes */
1763 retkey
, /* lpretkey */
1764 &junk
/* disposition value */
1769 /* RegCreateKeyExA [ADVAPI32.130] */
1770 DWORD WINAPI
RegCreateKeyEx32A(
1777 LPSECURITY_ATTRIBUTES lpSecAttribs
,
1781 LPWSTR lpszSubKeyW
,lpszClassW
;
1784 TRACE(reg
,"(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1796 lpszSubKeyW
=strdupA2W(lpszSubKey
);
1800 lpszClassW
=strdupA2W(lpszClass
);
1803 ret
=RegCreateKeyEx32W(
1821 /* RegCreateKeyA [ADVAPI32.129] */
1822 DWORD WINAPI
RegCreateKey32A(
1829 TRACE(reg
,"(%lx,%s,%p)\n",
1830 (LONG
)hkey
,lpszSubKey
,retkey
1832 return RegCreateKeyEx32A(
1833 hkey
, /* key handle */
1834 lpszSubKey
, /* subkey name */
1835 0, /* reserved = 0 */
1836 NULL
, /* lpszClass? FIXME: ? */
1837 REG_OPTION_NON_VOLATILE
,/* options */
1838 KEY_ALL_ACCESS
, /* desired access attribs */
1839 NULL
, /* lpsecurity attributes */
1840 retkey
, /* lpretkey */
1841 &junk
/* disposition value */
1845 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1846 DWORD WINAPI
RegCreateKey16(
1851 TRACE(reg
,"(%lx,%s,%p)\n",
1852 (LONG
)hkey
,lpszSubKey
,retkey
1854 return RegCreateKey32A(hkey
,lpszSubKey
,retkey
);
1858 * Query Value Functions
1859 * Win32 differs between keynames and valuenames.
1860 * multiple values may belong to one key, the special value
1861 * with name NULL is the default value used by the win31
1865 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1866 * RegQueryValue32W -> RegQueryValueEx32W
1869 /* RegQueryValueExW [ADVAPI32.158] */
1870 DWORD WINAPI
RegQueryValueEx32W(
1872 LPWSTR lpszValueName
,
1873 LPDWORD lpdwReserved
,
1881 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
1882 hkey
,W2C(lpszValueName
,0),lpdwReserved
,lpdwType
,lpbData
,
1883 lpcbData
?*lpcbData
:0);
1885 lpkey
= lookup_hkey(hkey
);
1887 return SHELL_ERROR_BADKEY
;
1888 if (lpszValueName
&& !*lpszValueName
)
1889 lpszValueName
= NULL
;
1890 if (lpszValueName
==NULL
) {
1891 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1892 if (lpkey
->values
[i
].name
==NULL
)
1895 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
1896 if ( lpkey
->values
[i
].name
&&
1897 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
1901 if (i
==lpkey
->nrofvalues
) {
1902 if (lpszValueName
==NULL
) {
1904 *(WCHAR
*)lpbData
= 0;
1909 return SHELL_ERROR_SUCCESS
;
1911 return SHELL_ERROR_BADKEY
;/*FIXME: correct return? */
1914 *lpdwType
= lpkey
->values
[i
].type
;
1915 if (lpbData
==NULL
) {
1917 return SHELL_ERROR_SUCCESS
;
1918 *lpcbData
= lpkey
->values
[i
].len
;
1919 return SHELL_ERROR_SUCCESS
;
1921 if (*lpcbData
<lpkey
->values
[i
].len
) {
1922 *(WCHAR
*)lpbData
= 0;
1923 *lpcbData
= lpkey
->values
[i
].len
;
1924 return ERROR_MORE_DATA
;
1926 memcpy(lpbData
,lpkey
->values
[i
].data
,lpkey
->values
[i
].len
);
1927 *lpcbData
= lpkey
->values
[i
].len
;
1928 return SHELL_ERROR_SUCCESS
;
1931 /* RegQueryValueW [ADVAPI32.159] */
1932 DWORD WINAPI
RegQueryValue32W(
1941 TRACE(reg
,"(%x,%s,%p,%ld)\n",
1942 hkey
,W2C(lpszSubKey
,0),lpszData
,
1943 lpcbData
?*lpcbData
:0);
1945 /* only open subkey, if we really do descend */
1946 if (lpszSubKey
&& *lpszSubKey
) {
1947 ret
= RegOpenKey32W(hkey
,lpszSubKey
,&xhkey
);
1948 if (ret
!=ERROR_SUCCESS
)
1954 ret
= RegQueryValueEx32W(
1956 NULL
, /* varname NULL -> compat */
1957 NULL
, /* lpdwReserved, must be NULL */
1967 /* RegQueryValueExA [ADVAPI32.157] */
1968 DWORD WINAPI
RegQueryValueEx32A(
1970 LPSTR lpszValueName
,
1971 LPDWORD lpdwReserved
,
1976 LPWSTR lpszValueNameW
;
1982 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
1983 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
1984 lpcbData
?*lpcbData
:0);
1987 lpszValueNameW
=strdupA2W(lpszValueName
);
1989 lpszValueNameW
=NULL
;
1998 ret
=RegQueryValueEx32W(
2007 if (ret
==ERROR_MORE_DATA
) {
2008 buf
= (LPBYTE
)xmalloc(*mylen
);
2010 buf
= (LPBYTE
)xmalloc(2*(*lpcbData
));
2011 myxlen
= 2*(*lpcbData
);
2016 myxlen
= *lpcbData
*2;
2021 ret
=RegQueryValueEx32W(
2031 if (ret
==ERROR_SUCCESS
) {
2033 if (UNICONVMASK
& (1<<(type
))) {
2034 /* convert UNICODE to ASCII */
2035 lstrcpyWtoA(lpbData
,(LPWSTR
)buf
);
2036 *lpcbData
= myxlen
/2;
2038 if (myxlen
>*lpcbData
)
2039 ret
= ERROR_MORE_DATA
;
2041 memcpy(lpbData
,buf
,myxlen
);
2046 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2047 *lpcbData
= myxlen
/2;
2050 if ((UNICONVMASK
& (1<<(type
))) && lpcbData
)
2051 *lpcbData
= myxlen
/2;
2058 /* RegQueryValueEx [KERNEL.225] */
2059 DWORD WINAPI
RegQueryValueEx16(
2061 LPSTR lpszValueName
,
2062 LPDWORD lpdwReserved
,
2067 TRACE(reg
,"(%x,%s,%p,%p,%p,%ld)\n",
2068 hkey
,lpszValueName
,lpdwReserved
,lpdwType
,lpbData
,
2069 lpcbData
?*lpcbData
:0);
2071 return RegQueryValueEx32A(
2081 /* RegQueryValueA [ADVAPI32.156] */
2082 DWORD WINAPI
RegQueryValue32A(
2091 TRACE(reg
,"(%x,%s,%p,%ld)\n",
2092 hkey
,lpszSubKey
,lpszData
,
2093 lpcbData
?*lpcbData
:0);
2095 /* only open subkey, if we really do descend */
2096 if (lpszSubKey
&& *lpszSubKey
) {
2097 ret
= RegOpenKey16(hkey
,lpszSubKey
,&xhkey
);
2098 if (ret
!=ERROR_SUCCESS
)
2104 ret
= RegQueryValueEx32A(
2106 NULL
, /* lpszValueName NULL -> compat */
2107 NULL
, /* lpdwReserved, must be NULL */
2117 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2118 DWORD WINAPI
RegQueryValue16(
2124 TRACE(reg
,"(%x,%s,%p,%ld)\n",
2125 hkey
,lpszSubKey
,lpszData
,lpcbData
?*lpcbData
:0);
2127 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2128 * anyway, so we just mask out the high 16 bit.
2129 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2132 *lpcbData
&= 0xFFFF;
2133 return RegQueryValue32A(hkey
,lpszSubKey
,lpszData
,lpcbData
);
2137 * Setting values of Registry keys
2140 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2141 * RegSetValue32W -> RegSetValueEx32W
2144 /* RegSetValueExW [ADVAPI32.170] */
2145 DWORD WINAPI
RegSetValueEx32W(
2147 LPWSTR lpszValueName
,
2156 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2157 hkey
,W2C(lpszValueName
,0),dwReserved
,dwType
,lpbData
,cbData
2159 /* we no longer care about the lpbData type here... */
2160 lpkey
= lookup_hkey(hkey
);
2162 return SHELL_ERROR_BADKEY
;
2164 lpkey
->flags
|= REG_OPTION_TAINTED
;
2166 if (lpszValueName
==NULL
) {
2167 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2168 if (lpkey
->values
[i
].name
==NULL
)
2171 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2172 if ( lpkey
->values
[i
].name
&&
2173 !lstrcmpi32W(lpszValueName
,lpkey
->values
[i
].name
)
2177 if (i
==lpkey
->nrofvalues
) {
2178 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2180 (lpkey
->nrofvalues
+1)*sizeof(KEYVALUE
)
2182 lpkey
->nrofvalues
++;
2183 memset(lpkey
->values
+i
,'\0',sizeof(KEYVALUE
));
2185 if (lpkey
->values
[i
].name
==NULL
)
2187 lpkey
->values
[i
].name
= strdupW(lpszValueName
);
2189 lpkey
->values
[i
].name
= NULL
;
2190 lpkey
->values
[i
].len
= cbData
;
2191 lpkey
->values
[i
].type
= dwType
;
2192 if (lpkey
->values
[i
].data
!=NULL
)
2193 free(lpkey
->values
[i
].data
);
2194 lpkey
->values
[i
].data
= (LPBYTE
)xmalloc(cbData
);
2195 lpkey
->values
[i
].lastmodified
= time(NULL
);
2196 memcpy(lpkey
->values
[i
].data
,lpbData
,cbData
);
2197 return SHELL_ERROR_SUCCESS
;
2200 /* RegSetValueExA [ADVAPI32.169] */
2201 DWORD WINAPI
RegSetValueEx32A(
2203 LPSTR lpszValueName
,
2210 LPWSTR lpszValueNameW
;
2213 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2214 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2216 if ((1<<dwType
) & UNICONVMASK
) {
2217 buf
=(LPBYTE
)strdupA2W(lpbData
);
2218 cbData
=2*strlen(lpbData
)+2;
2222 lpszValueNameW
= strdupA2W(lpszValueName
);
2224 lpszValueNameW
= NULL
;
2225 ret
=RegSetValueEx32W(hkey
,lpszValueNameW
,dwReserved
,dwType
,buf
,cbData
);
2227 free(lpszValueNameW
);
2233 /* RegSetValueEx [KERNEL.226] */
2234 DWORD WINAPI
RegSetValueEx16(
2236 LPSTR lpszValueName
,
2242 TRACE(reg
,"(%x,%s,%ld,%ld,%p,%ld)\n",
2243 hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
2245 return RegSetValueEx32A(hkey
,lpszValueName
,dwReserved
,dwType
,lpbData
,cbData
);
2248 /* RegSetValueW [ADVAPI32.171] */
2249 DWORD WINAPI
RegSetValue32W(
2259 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2260 hkey
,W2C(lpszSubKey
,0),dwType
,W2C(lpszData
,0),cbData
2262 if (lpszSubKey
&& *lpszSubKey
) {
2263 ret
=RegCreateKey32W(hkey
,lpszSubKey
,&xhkey
);
2264 if (ret
!=ERROR_SUCCESS
)
2268 if (dwType
!=REG_SZ
) {
2269 TRACE(reg
,"RegSetValueX called with dwType=%ld!\n",dwType
);
2272 if (cbData
!=2*lstrlen32W(lpszData
)+2) {
2273 TRACE(reg
,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2274 cbData
,W2C(lpszData
,0),2*lstrlen32W(lpszData
)+2
2276 cbData
=2*lstrlen32W(lpszData
)+2;
2278 ret
=RegSetValueEx32W(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2284 /* RegSetValueA [ADVAPI32.168] */
2285 DWORD WINAPI
RegSetValue32A(
2295 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2296 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2298 if (lpszSubKey
&& *lpszSubKey
) {
2299 ret
=RegCreateKey16(hkey
,lpszSubKey
,&xhkey
);
2300 if (ret
!=ERROR_SUCCESS
)
2305 if (dwType
!=REG_SZ
) {
2306 TRACE(reg
,"RegSetValueA called with dwType=%ld!\n",dwType
);
2309 if (cbData
!=strlen(lpszData
)+1)
2310 cbData
=strlen(lpszData
)+1;
2311 ret
=RegSetValueEx32A(xhkey
,NULL
,0,dwType
,(LPBYTE
)lpszData
,cbData
);
2317 /* RegSetValue [KERNEL.221] [SHELL.5] */
2318 DWORD WINAPI
RegSetValue16(
2326 TRACE(reg
,"(%x,%s,%ld,%s,%ld)\n",
2327 hkey
,lpszSubKey
,dwType
,lpszData
,cbData
2329 ret
=RegSetValue32A(hkey
,lpszSubKey
,dwType
,lpszData
,cbData
);
2337 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2338 * RegEnumKey32W -> RegEnumKeyEx32W
2341 /* RegEnumKeyExW [ADVAPI32.139] */
2342 DWORD WINAPI
RegEnumKeyEx32W(
2347 LPDWORD lpdwReserved
,
2352 LPKEYSTRUCT lpkey
,lpxkey
;
2354 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2355 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2357 lpkey
=lookup_hkey(hkey
);
2359 return SHELL_ERROR_BADKEY
;
2360 if (!lpkey
->nextsub
)
2361 return ERROR_NO_MORE_ITEMS
;
2362 lpxkey
=lpkey
->nextsub
;
2363 while (iSubkey
&& lpxkey
) {
2365 lpxkey
=lpxkey
->next
;
2367 if (iSubkey
|| !lpxkey
)
2368 return ERROR_NO_MORE_ITEMS
;
2369 if (2*lstrlen32W(lpxkey
->keyname
)+2>*lpcchName
)
2370 return ERROR_MORE_DATA
;
2371 memcpy(lpszName
,lpxkey
->keyname
,lstrlen32W(lpxkey
->keyname
)*2+2);
2373 /* what should we write into it? */
2377 return ERROR_SUCCESS
;
2381 /* RegEnumKeyW [ADVAPI32.140] */
2382 DWORD WINAPI
RegEnumKey32W(
2390 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2391 hkey
,iSubkey
,lpszName
,lpcchName
2393 return RegEnumKeyEx32W(hkey
,iSubkey
,lpszName
,&lpcchName
,NULL
,NULL
,NULL
,&ft
);
2395 /* RegEnumKeyExA [ADVAPI32.138] */
2396 DWORD WINAPI
RegEnumKeyEx32A(
2401 LPDWORD lpdwReserved
,
2406 DWORD ret
,lpcchNameW
,lpcchClassW
;
2407 LPWSTR lpszNameW
,lpszClassW
;
2410 TRACE(reg
,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2411 hkey
,iSubkey
,lpszName
,*lpcchName
,lpdwReserved
,lpszClass
,lpcchClass
,ft
2414 lpszNameW
= (LPWSTR
)xmalloc(*lpcchName
*2);
2415 lpcchNameW
= *lpcchName
*2;
2421 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
*2);
2422 lpcchClassW
= *lpcchClass
*2;
2427 ret
=RegEnumKeyEx32W(
2437 if (ret
==ERROR_SUCCESS
) {
2438 lstrcpyWtoA(lpszName
,lpszNameW
);
2439 *lpcchName
=strlen(lpszName
);
2441 lstrcpyWtoA(lpszClass
,lpszClassW
);
2442 *lpcchClass
=strlen(lpszClass
);
2452 /* RegEnumKeyA [ADVAPI32.137] */
2453 DWORD WINAPI
RegEnumKey32A(
2461 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2462 hkey
,iSubkey
,lpszName
,lpcchName
2464 return RegEnumKeyEx32A(
2476 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2477 DWORD WINAPI
RegEnumKey16(
2483 TRACE(reg
,"(%x,%ld,%p,%ld)\n",
2484 hkey
,iSubkey
,lpszName
,lpcchName
2486 return RegEnumKey32A(hkey
,iSubkey
,lpszName
,lpcchName
);
2490 * Enumerate Registry Values
2493 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2496 /* RegEnumValueW [ADVAPI32.142] */
2497 DWORD WINAPI
RegEnumValue32W(
2502 LPDWORD lpdReserved
,
2510 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2511 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2513 lpkey
= lookup_hkey(hkey
);
2515 return SHELL_ERROR_BADKEY
;
2516 if (lpkey
->nrofvalues
<=iValue
)
2517 return ERROR_NO_MORE_ITEMS
;
2518 val
= lpkey
->values
+iValue
;
2521 if (lstrlen32W(val
->name
)*2+2>*lpcchValue
) {
2522 *lpcchValue
= lstrlen32W(val
->name
)*2+2;
2523 return ERROR_MORE_DATA
;
2525 memcpy(lpszValue
,val
->name
,2*lstrlen32W(val
->name
)+2);
2526 *lpcchValue
=lstrlen32W(val
->name
)*2+2;
2532 *lpdwType
=val
->type
;
2534 if (val
->len
>*lpcbData
)
2535 return ERROR_MORE_DATA
;
2536 memcpy(lpbData
,val
->data
,val
->len
);
2537 *lpcbData
= val
->len
;
2539 return SHELL_ERROR_SUCCESS
;
2542 /* RegEnumValueA [ADVAPI32.141] */
2543 DWORD WINAPI
RegEnumValue32A(
2548 LPDWORD lpdReserved
,
2555 DWORD ret
,lpcbDataW
;
2557 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2558 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2561 lpszValueW
= (LPWSTR
)xmalloc(*lpcchValue
*2);
2563 lpbDataW
= (LPBYTE
)xmalloc(*lpcbData
*2);
2564 lpcbDataW
= *lpcbData
*2;
2567 ret
=RegEnumValue32W(
2578 if (ret
==ERROR_SUCCESS
) {
2579 lstrcpyWtoA(lpszValue
,lpszValueW
);
2581 if ((1<<*lpdwType
) & UNICONVMASK
) {
2582 lstrcpyWtoA(lpbData
,(LPWSTR
)lpbDataW
);
2584 if (lpcbDataW
> *lpcbData
)
2585 ret
= ERROR_MORE_DATA
;
2587 memcpy(lpbData
,lpbDataW
,lpcbDataW
);
2589 *lpcbData
= lpcbDataW
;
2599 /* RegEnumValue [KERNEL.223] */
2600 DWORD WINAPI
RegEnumValue16(
2605 LPDWORD lpdReserved
,
2610 TRACE(reg
,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2611 hkey
,iValue
,lpszValue
,lpcchValue
,lpdReserved
,lpdwType
,lpbData
,lpcbData
2613 return RegEnumValue32A(
2626 * Close registry key
2628 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2629 DWORD WINAPI
RegCloseKey(HKEY hkey
) {
2630 TRACE(reg
,"(%x)\n",hkey
);
2631 remove_handle(hkey
);
2632 return ERROR_SUCCESS
;
2635 * Delete registry key
2638 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2640 /* RegDeleteKeyW [ADVAPI32.134] */
2641 DWORD WINAPI
RegDeleteKey32W(HKEY hkey
,LPWSTR lpszSubKey
) {
2642 LPKEYSTRUCT
*lplpPrevKey
,lpNextKey
,lpxkey
;
2646 TRACE(reg
,"(%x,%s)\n",
2647 hkey
,W2C(lpszSubKey
,0)
2649 lpNextKey
= lookup_hkey(hkey
);
2651 TRACE(reg
, " Badkey[1].\n");
2652 return SHELL_ERROR_BADKEY
;
2654 /* we need to know the previous key in the hier. */
2655 if (!lpszSubKey
|| !*lpszSubKey
) {
2656 TRACE(reg
, " Badkey[2].\n");
2657 return SHELL_ERROR_BADKEY
;
2659 split_keypath(lpszSubKey
,&wps
,&wpc
);
2663 lpxkey
=lpNextKey
->nextsub
;
2665 TRACE(reg
, " Scanning [%s]\n",
2666 W2C (lpxkey
->keyname
, 0));
2667 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2669 lpxkey
=lpxkey
->next
;
2673 TRACE(reg
, " Not found.\n");
2674 /* not found is success */
2675 return SHELL_ERROR_SUCCESS
;
2680 lpxkey
= lpNextKey
->nextsub
;
2681 lplpPrevKey
= &(lpNextKey
->nextsub
);
2683 TRACE(reg
, " Scanning [%s]\n",
2684 W2C (lpxkey
->keyname
, 0));
2685 if (!lstrcmpi32W(wps
[i
],lpxkey
->keyname
))
2687 lplpPrevKey
= &(lpxkey
->next
);
2688 lpxkey
= lpxkey
->next
;
2692 WARN(reg
, " Not found.\n");
2693 return SHELL_ERROR_BADKEY
;
2695 if (lpxkey
->nextsub
) {
2697 WARN(reg
, " Not empty.\n");
2698 return SHELL_ERROR_CANTWRITE
;
2700 *lplpPrevKey
= lpxkey
->next
;
2701 free(lpxkey
->keyname
);
2703 free(lpxkey
->class);
2705 free(lpxkey
->values
);
2708 TRACE(reg
, " Done.\n");
2709 return SHELL_ERROR_SUCCESS
;
2712 /* RegDeleteKeyA [ADVAPI32.133] */
2713 DWORD WINAPI
RegDeleteKey32A(HKEY hkey
,LPCSTR lpszSubKey
) {
2717 TRACE(reg
,"(%x,%s)\n",
2720 lpszSubKeyW
=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey
);
2721 ret
=RegDeleteKey32W(hkey
,lpszSubKeyW
);
2722 HeapFree(GetProcessHeap(),0,lpszSubKeyW
);
2726 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2727 DWORD WINAPI
RegDeleteKey16(HKEY hkey
,LPCSTR lpszSubKey
) {
2728 TRACE(reg
,"(%x,%s)\n",
2731 return RegDeleteKey32A(hkey
,lpszSubKey
);
2735 * Delete registry value
2738 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2740 /* RegDeleteValueW [ADVAPI32.136] */
2741 DWORD WINAPI
RegDeleteValue32W(HKEY hkey
,LPWSTR lpszValue
)
2747 TRACE(reg
,"(%x,%s)\n",
2748 hkey
,W2C(lpszValue
,0)
2750 lpkey
=lookup_hkey(hkey
);
2752 return SHELL_ERROR_BADKEY
;
2754 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2755 if ( lpkey
->values
[i
].name
&&
2756 !lstrcmpi32W(lpkey
->values
[i
].name
,lpszValue
)
2760 for (i
=0;i
<lpkey
->nrofvalues
;i
++)
2761 if (lpkey
->values
[i
].name
==NULL
)
2764 if (i
==lpkey
->nrofvalues
)
2765 return SHELL_ERROR_BADKEY
;/*FIXME: correct errorcode? */
2766 val
= lpkey
->values
+i
;
2767 if (val
->name
) free(val
->name
);
2768 if (val
->data
) free(val
->data
);
2772 sizeof(KEYVALUE
)*(lpkey
->nrofvalues
-i
-1)
2774 lpkey
->values
= (LPKEYVALUE
)xrealloc(
2776 (lpkey
->nrofvalues
-1)*sizeof(KEYVALUE
)
2778 lpkey
->nrofvalues
--;
2779 return SHELL_ERROR_SUCCESS
;
2782 /* RegDeleteValueA [ADVAPI32.135] */
2783 DWORD WINAPI
RegDeleteValue32A(HKEY hkey
,LPSTR lpszValue
)
2788 TRACE(reg
, "(%x,%s)\n", hkey
,lpszValue
);
2789 lpszValueW
=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue
);
2790 ret
=RegDeleteValue32W(hkey
,lpszValueW
);
2791 HeapFree(GetProcessHeap(),0,lpszValueW
);
2795 /* RegDeleteValue [KERNEL.222] */
2796 DWORD WINAPI
RegDeleteValue16(HKEY hkey
,LPSTR lpszValue
)
2798 TRACE(reg
,"(%x,%s)\n", hkey
,lpszValue
);
2799 return RegDeleteValue32A(hkey
,lpszValue
);
2803 /******************************************************************************
2804 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
2805 * Writes key to registry
2808 * hkey [I] Handle of key to write
2811 * Success: ERROR_SUCCESS
2812 * Failure: Error code
2814 DWORD WINAPI
RegFlushKey( HKEY hkey
)
2816 FIXME(reg
, "(%x): stub\n", hkey
);
2817 return ERROR_SUCCESS
;
2821 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2823 /* RegQueryInfoKeyW [ADVAPI32.153] */
2824 DWORD WINAPI
RegQueryInfoKey32W(
2828 LPDWORD lpdwReserved
,
2830 LPDWORD lpcchMaxSubkey
,
2831 LPDWORD lpcchMaxClass
,
2833 LPDWORD lpcchMaxValueName
,
2834 LPDWORD lpccbMaxValueData
,
2835 LPDWORD lpcbSecurityDescriptor
,
2838 LPKEYSTRUCT lpkey
,lpxkey
;
2839 int nrofkeys
,maxsubkey
,maxclass
,maxvalues
,maxvname
,maxvdata
;
2842 TRACE(reg
,"(%x,......)\n",hkey
);
2843 lpkey
=lookup_hkey(hkey
);
2845 return SHELL_ERROR_BADKEY
;
2848 if (lstrlen32W(lpkey
->class)*2+2>*lpcchClass
) {
2849 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2850 return ERROR_MORE_DATA
;
2852 *lpcchClass
=lstrlen32W(lpkey
->class)*2;
2853 memcpy(lpszClass
,lpkey
->class,lstrlen32W(lpkey
->class));
2860 *lpcchClass
= lstrlen32W(lpkey
->class)*2;
2862 lpxkey
=lpkey
->nextsub
;
2863 nrofkeys
=maxsubkey
=maxclass
=maxvalues
=maxvname
=maxvdata
=0;
2866 if (lstrlen32W(lpxkey
->keyname
)>maxsubkey
)
2867 maxsubkey
=lstrlen32W(lpxkey
->keyname
);
2868 if (lpxkey
->class && lstrlen32W(lpxkey
->class)>maxclass
)
2869 maxclass
=lstrlen32W(lpxkey
->class);
2870 if (lpxkey
->nrofvalues
>maxvalues
)
2871 maxvalues
=lpxkey
->nrofvalues
;
2872 for (i
=0;i
<lpxkey
->nrofvalues
;i
++) {
2873 LPKEYVALUE val
=lpxkey
->values
+i
;
2875 if (val
->name
&& lstrlen32W(val
->name
)>maxvname
)
2876 maxvname
=lstrlen32W(val
->name
);
2877 if (val
->len
>maxvdata
)
2880 lpxkey
=lpxkey
->next
;
2882 if (!maxclass
) maxclass
= 1;
2883 if (!maxvname
) maxvname
= 1;
2885 *lpcSubKeys
= nrofkeys
;
2887 *lpcchMaxSubkey
= maxsubkey
*2;
2889 *lpcchMaxClass
= maxclass
*2;
2891 *lpcValues
= maxvalues
;
2892 if (lpcchMaxValueName
)
2893 *lpcchMaxValueName
= maxvname
;
2894 if (lpccbMaxValueData
)
2895 *lpccbMaxValueData
= maxvdata
;
2896 return SHELL_ERROR_SUCCESS
;
2899 /* RegQueryInfoKeyA [ADVAPI32.152] */
2900 DWORD WINAPI
RegQueryInfoKey32A(
2904 LPDWORD lpdwReserved
,
2906 LPDWORD lpcchMaxSubkey
,
2907 LPDWORD lpcchMaxClass
,
2909 LPDWORD lpcchMaxValueName
,
2910 LPDWORD lpccbMaxValueData
,
2911 LPDWORD lpcbSecurityDescriptor
,
2917 TRACE(reg
,"(%x,......)\n",hkey
);
2920 lpszClassW
= (LPWSTR
)xmalloc(*lpcchClass
);
2924 ret
=RegQueryInfoKey32W(
2935 lpcbSecurityDescriptor
,
2938 if (ret
==ERROR_SUCCESS
&& lpszClass
)
2939 lstrcpyWtoA(lpszClass
,lpszClassW
);
2946 if (lpcchMaxValueName
)
2947 *lpcchMaxValueName
/=2;
2952 /* RegConnectRegistryA [ADVAPI32.127] */
2953 DWORD WINAPI
RegConnectRegistry32A(LPCSTR machine
,HKEY hkey
,LPHKEY reskey
)
2955 FIXME(reg
,"(%s,%08x,%p):stub.\n",machine
,hkey
,reskey
);
2956 return ERROR_FILE_NOT_FOUND
; /* FIXME */
2960 /******************************************************************************
2961 * RegGetKeySecurity [ADVAPI32.144]
2962 * Retrieves a copy of security descriptor protecting the registry key
2965 * pSecurityDescriptor should be PSECURITY_DESCRIPTOR
2968 * Success: ERROR_SUCCESS
2969 * Failure: Error code
2971 LONG WINAPI
RegGetKeySecurity( HKEY hKey
,
2972 SECURITY_INFORMATION SecurityInformation
,
2973 LPVOID pSecurityDescriptor
,
2974 LPDWORD lpcbSecurityDescriptor
)
2976 FIXME(reg
, "(%d,%ld,%p,%p): stub\n", hKey
, SecurityInformation
,
2977 pSecurityDescriptor
, lpcbSecurityDescriptor
);
2978 return ERROR_SUCCESS
;