4 * Copyright 1996 Marcus Meissner
14 #include <sys/types.h>
15 #include <sys/fcntl.h>
30 #define MAKE_DWORD(x,y) ((DWORD)MAKELONG(x,y))
32 /* FIXME: following defines should be configured global ... */
34 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
35 #define WINE_PREFIX "/.wine"
36 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
37 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
39 /* relative in ~user/.wine/ : */
40 #define SAVE_CURRENT_USER "user.reg"
41 #define SAVE_LOCAL_MACHINE "system.reg"
43 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
44 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
46 /* one value of a key */
47 typedef struct tagKEYVALUE
49 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
50 DWORD type; /* type of value */
51 DWORD len; /* length of data */
52 DWORD lastmodified; /* time of seconds since 1.1.1970 */
53 LPBYTE data; /* content, may be strings, binaries, etc. */
54 } KEYVALUE,*LPKEYVALUE;
57 typedef struct tagKEYSTRUCT
59 LPWSTR keyname; /* name of THIS key (UNICODE) */
60 DWORD flags; /* flags. */
63 DWORD nrofvalues; /* nr of values in THIS key */
64 LPKEYVALUE values; /* values in THIS key */
65 /* key management pointers */
66 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
67 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
68 } KEYSTRUCT, *LPKEYSTRUCT;
71 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
72 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
73 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
74 static KEYSTRUCT *key_users=NULL; /* all users? */
76 /* dynamic, not saved */
77 static KEYSTRUCT *key_performance_data=NULL;
78 static KEYSTRUCT *key_current_config=NULL;
79 static KEYSTRUCT *key_dyn_data=NULL;
81 /* what valuetypes do we need to convert? */
82 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
84 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
85 #define strdupW(x) STRING32_strdupW(x)
86 #define strchrW(a,c) STRING32_lstrchrW(a,c)
88 static struct openhandle {
93 static int nrofopenhandles=0;
94 static int currenthandle=1;
97 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
100 for (i=0;i<nrofopenhandles;i++) {
101 if (openhandles[i].lpkey==lpkey) {
102 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
104 if (openhandles[i].hkey==hkey) {
105 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
108 openhandles=xrealloc( openhandles,
109 sizeof(struct openhandle)*(nrofopenhandles+1)
111 openhandles[i].lpkey = lpkey;
112 openhandles[i].hkey = hkey;
113 openhandles[i].accessmask= accessmask;
118 get_handle(HKEY hkey) {
121 for (i=0;i<nrofopenhandles;i++)
122 if (openhandles[i].hkey==hkey)
123 return openhandles[i].lpkey;
124 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
129 remove_handle(HKEY hkey) {
132 for (i=0;i<nrofopenhandles;i++)
133 if (openhandles[i].hkey==hkey)
135 if (i==nrofopenhandles) {
136 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
139 memcpy( openhandles+i,
141 sizeof(struct openhandle)*(nrofopenhandles-i-1)
143 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
149 /* debug function, converts a unicode into a static memory area
150 * (sub for using two static strings, in case we need them in a single call)
153 W2C(LPCWSTR x,int sub) {
154 static LPSTR unicodedebug[2]={NULL,NULL};
157 if (sub!=0 && sub!=1)
158 return "<W2C:bad sub>";
159 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
160 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
161 return unicodedebug[sub];
165 lookup_hkey(HKEY hkey) {
169 case HKEY_CLASSES_ROOT:
170 return key_classes_root;
171 case HKEY_CURRENT_USER:
172 return key_current_user;
173 case HKEY_LOCAL_MACHINE:
174 return key_local_machine;
177 case HKEY_PERFORMANCE_DATA:
178 return key_performance_data;
181 case HKEY_CURRENT_CONFIG:
182 return key_current_config;
184 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
187 return get_handle(hkey);
193 * splits the unicode string 'wp' into an array of strings.
194 * the array is allocated by this function.
195 * the number of components will be stored in 'wpc'
196 * Free the array using FREE_KEY_PATH
199 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
203 ws = HEAP_strdupW( SystemHeap, 0, wp );
205 for (i=0;ws[i];i++) {
212 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
220 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
223 * Shell initialisation, allocates keys.
225 void SHELL_StartupRegistry();
230 HKEY cl_r_hkey,c_u_hkey;
231 #define ADD_ROOT_KEY(xx) \
232 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
233 memset(xx,'\0',sizeof(KEYSTRUCT));\
234 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
236 ADD_ROOT_KEY(key_local_machine);
237 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
238 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
241 key_classes_root = lookup_hkey(cl_r_hkey);
243 ADD_ROOT_KEY(key_users);
246 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
247 * (later, when a win32 registry editing tool becomes avail.)
249 while (pwd=getpwent()) {
250 if (pwd->pw_name == NULL)
252 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
253 RegCloseKey(c_u_hkey);
256 pwd=getpwuid(getuid());
257 if (pwd && pwd->pw_name) {
258 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
259 key_current_user = lookup_hkey(c_u_hkey);
261 ADD_ROOT_KEY(key_current_user);
263 ADD_ROOT_KEY(key_performance_data);
264 ADD_ROOT_KEY(key_current_config);
265 ADD_ROOT_KEY(key_dyn_data);
267 SHELL_StartupRegistry();
272 SHELL_StartupRegistry() {
275 char buf[200],cpubuf[200];
277 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
279 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
281 F=fopen("/proc/cpuinfo","r");
284 while (NULL!=fgets(buf,200,F)) {
285 if (sscanf(buf,"processor\t: %d",&x)) {
290 RegCreateKey16(hkey,buf,&xhkey);
292 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
293 sprintf(buf,"CPU %s",cpubuf);
295 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
305 RegCreateKey16(hkey,"0",&xhkey);
306 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
308 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
309 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
311 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
315 * string RegisteredOwner
316 * string RegisteredOrganization
319 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
324 if (-1!=gethostname(buf,200)) {
325 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
326 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
330 /************************ SAVE Registry Function ****************************/
332 #define REGISTRY_SAVE_VERSION 0x00000001
334 /* Registry saveformat:
335 * If you change it, increase above number by 1, which will flush
336 * old registry database files.
339 * "WINE REGISTRY Version %d"
343 * valuename=lastmodified,type,data
347 * keyname,valuename,stringdata:
348 * the usual ascii characters from 0x00-0xff (well, not 0x00)
349 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
350 * ( "=\\\t" escaped in \uXXXX form.)
354 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
356 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
357 * SaveOnlyUpdatedKeys=yes
360 _save_check_tainted(LPKEYSTRUCT lpkey) {
365 if (lpkey->flags & REG_OPTION_TAINTED)
370 if (_save_check_tainted(lpkey->nextsub)) {
371 lpkey->flags |= REG_OPTION_TAINTED;
380 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
393 if (escapeeq && *s=='=')
396 fputc(*s,F); /* if \\ than put it twice. */
398 fprintf(F,"\\u%04x",*((unsigned short*)s));
406 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
412 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
413 (all || (lpxkey->flags & REG_OPTION_TAINTED))
415 for (tabs=level;tabs--;)
417 _save_USTRING(F,lpxkey->keyname,1);
419 for (i=0;i<lpxkey->nrofvalues;i++) {
420 LPKEYVALUE val=lpxkey->values+i;
422 for (tabs=level+1;tabs--;)
424 _save_USTRING(F,val->name,0);
426 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
427 if ((1<<val->type) & UNICONVMASK)
428 _save_USTRING(F,(LPWSTR)val->data,0);
430 for (j=0;j<val->len;j++)
431 fprintf(F,"%02x",*((unsigned char*)val->data+j));
434 /* descend recursively */
435 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
444 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
445 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
446 _save_check_tainted(lpkey->nextsub);
447 return _savesubkey(F,lpkey->nextsub,0,all);
451 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
456 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
461 if (!_savesubreg(F,lpkey,all)) {
464 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
472 SHELL_SaveRegistry() {
480 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
486 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
498 if (lstrcmpi32A(buf,"yes"))
500 pwd=getpwuid(getuid());
501 if (pwd!=NULL && pwd->pw_dir!=NULL)
505 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
506 strlen(SAVE_CURRENT_USER) + 2 );
507 strcpy(fn,pwd->pw_dir);
508 strcat(fn,WINE_PREFIX);
509 /* create the directory. don't care about errorcodes. */
510 mkdir(fn,0755); /* drwxr-xr-x */
511 strcat(fn,"/"SAVE_CURRENT_USER);
512 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
513 strcpy(tmp,fn);strcat(tmp,".tmp");
514 if (_savereg(key_current_user,tmp,all)) {
515 if (-1==rename(tmp,fn)) {
516 perror("rename tmp registry");
522 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
523 strcpy(fn,pwd->pw_dir);
524 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
525 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
526 strcpy(tmp,fn);strcat(tmp,".tmp");
527 if (_savereg(key_local_machine,tmp,all)) {
528 if (-1==rename(tmp,fn)) {
529 perror("rename tmp registry");
536 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
539 /************************ LOAD Registry Function ****************************/
542 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
543 LPKEYSTRUCT lpxkey,*lplpkey;
545 lplpkey= &(lpkey->nextsub);
548 if (!lstrcmp32W(lpxkey->keyname,keyname))
550 lplpkey = &(lpxkey->next);
554 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
556 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
557 lpxkey->keyname = keyname;
565 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
571 for (i=0;i<lpkey->nrofvalues;i++) {
577 if ( val->name!=NULL &&
578 !lstrcmp32W(val->name,name)
583 if (i==lpkey->nrofvalues) {
584 lpkey->values = xrealloc(
586 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
589 memset(val,'\0',sizeof(KEYVALUE));
595 if (val->lastmodified<lastmodified) {
596 val->lastmodified=lastmodified;
607 /* reads a line including dynamically enlarging the readbuffer and throwing
611 _wine_read_line(FILE *F,char **buf,int *len) {
620 s=fgets(curread,mylen,F);
623 if (NULL==(s=strchr(curread,'\n'))) {
624 /* buffer wasn't large enough */
625 curoff = strlen(*buf);
626 *buf = xrealloc(*buf,*len*2);
627 curread = *buf + curoff;
628 mylen = *len; /* we filled up the buffer and
629 * got new '*len' bytes to fill
637 /* throw away comments */
638 if (**buf=='#' || **buf==';') {
643 if (s) /* got end of line */
649 /* converts a char* into a UNICODE string (up to a special char)
650 * and returns the position exactly after that string
653 _wine_read_USTRING(char *buf,LPWSTR *str) {
657 /* read up to "=" or "\0" or "\n" */
660 /* empty string is the win3.1 default value(NULL)*/
664 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
666 while (*s && (*s!='\n') && (*s!='=')) {
668 *ws++=*((unsigned char*)s++);
677 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
685 memcpy(xbuf,s,4);xbuf[4]='\0';
686 if (!sscanf(xbuf,"%x",&wc))
687 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
689 *ws++ =(unsigned short)wc;
695 *str = strdupW(*str);
702 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
709 lpkey->flags |= optflag;
711 /* good. we already got a line here ... so parse it */
721 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
724 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
727 /* let the caller handle this line */
728 if (i<level || **buf=='\0')
731 /* it can be: a value or a keyname. Parse the name first */
732 s=_wine_read_USTRING(s,&name);
734 /* switch() default: hack to avoid gotos */
738 lpxkey=_find_or_add_key(lpkey,name);
741 int len,lastmodified,type;
744 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
748 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
749 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
755 if ((1<<type) & UNICONVMASK) {
756 s=_wine_read_USTRING(s,(LPWSTR*)&data);
758 len = lstrlen32W((LPWSTR)data)*2+2;
763 data = (LPBYTE)xmalloc(len+1);
764 for (i=0;i<len;i++) {
766 if (*s>='0' && *s<='9')
768 if (*s>='a' && *s<='f')
770 if (*s>='A' && *s<='F')
773 if (*s>='0' && *s<='9')
775 if (*s>='a' && *s<='f')
777 if (*s>='A' && *s<='F')
782 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
785 /* read the next line */
786 if (!_wine_read_line(F,buf,buflen))
793 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
798 buf=xmalloc(10);buflen=10;
799 if (!_wine_read_line(F,&buf,&buflen)) {
803 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
807 if (ver!=REGISTRY_SAVE_VERSION) {
808 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
812 if (!_wine_read_line(F,&buf,&buflen)) {
816 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
825 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
830 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
835 if (!_wine_loadsubreg(F,lpkey,optflag)) {
844 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
851 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
853 for (j=0;j<from->nrofvalues;j++) {
857 valfrom = from->values+j;
859 if (name) name=strdupW(name);
860 data=(LPBYTE)malloc(valfrom->len);
861 memcpy(data,valfrom->data,valfrom->len);
869 valfrom->lastmodified
872 _copy_registry(from,lpxkey);
877 /* WINDOWS 95 REGISTRY LOADER */
879 * Structure of a win95 registry database.
883 * 8 : DWORD offset_of_RGDB_part
884 * 0C..1F: ? (someone fill in please)
889 * 4..0x1B: ? (fill in)
890 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
892 * Disk Key Entry Structure:
893 * 00: DWORD - unknown
894 * 04: DWORD - unknown
895 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
896 * 0C: DWORD - disk address of PreviousLevel Key.
897 * 10: DWORD - disk address of Next Sublevel Key.
898 * 14: DWORD - disk address of Next Key (on same level).
899 * DKEP>18: WORD - Nr, Low Significant part.
900 * 1A: WORD - Nr, High Significant part.
902 * The disk address always points to the nr part of the previous key entry
903 * of the referenced key. Don't ask me why, or even if I got this correct
904 * from staring at 1kg of hexdumps. (DKEP)
906 * The number of the entry is the low byte of the Low Significant Part ored
907 * with 0x100 * (low byte of the High Significant part)
908 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
910 * There are two minor corrections to the position of that structure.
911 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
912 * the DKE reread from there.
913 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
914 * (FIXME: slightly better explanation needed here)
918 * 04: DWORD offset to next RGDB section (perhaps WORD)
923 * 00: DWORD nextkeyoffset - offset to the next disk key structure
924 * 08: WORD nrLS - low significant part of NR
925 * 0A: WORD nrHS - high significant part of NR
926 * 0C: DWORD bytesused - bytes used in this structure.
927 * 10: WORD name_len - length of name in bytes. without \0
928 * 12: WORD nr_of_values - number of values.
929 * 14: char name[name_len] - name string. No \0.
930 * 14+name_len: disk values
931 * nextkeyoffset: ... next disk key
934 * 00: DWORD type - value type (hmm, could be WORD too)
935 * 04: DWORD - unknown, usually 0
936 * 08: WORD namelen - length of Name. 0 means name=NULL
937 * 0C: WORD datalen - length of Data.
938 * 10: char name[namelen] - name, no \0
939 * 10+namelen: BYTE data[datalen] - data, without \0 if string
940 * 10+namelen+datalen: next values or disk key
942 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
943 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
944 * structure) and reading another RGDB_section.
945 * repeat until end of file.
947 * FIXME: this description needs some serious help, yes.
950 struct _w95keyvalue {
952 unsigned short datalen;
962 struct _w95keyvalue *values;
963 unsigned long dkeaddr;
968 struct _w95key *prevlvl;
969 struct _w95key *nextsub;
970 struct _w95key *next;
973 /* fast lookup table dkeaddr->nr */
975 unsigned long dkeaddr;
981 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
987 if (key->name == NULL) {
988 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
993 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
995 if (key->nrofvals<0) {
996 /* shouldn't happen */
997 fprintf(stderr,"key %s already processed!\n",key->name);
1001 for (i=0;i<key->nrofvals;i++) {
1005 name = strdupA2W(key->values[i].name);
1006 if (!*name) name = NULL;
1007 free(key->values[i].name);
1009 len = key->values[i].datalen;
1010 data = key->values[i].data;
1011 if ((1<<key->values[i].type) & UNICONVMASK) {
1012 data = (BYTE*)strdupA2W(data);
1013 len = lstrlen32W((LPWSTR)data)*2+2;
1014 free(key->values[i].data);
1019 key->values[i].type,
1022 key->values[i].lastmodified
1029 key->nrofvals=-key->nrofvals-1;
1030 _w95_walk_tree(lpxkey,key->nextsub);
1035 /* small helper function to adjust address offset (dkeaddrs) */
1036 static unsigned long
1037 _w95_adj_da(unsigned long dkeaddr) {
1038 if ((dkeaddr&0xFFF)<0x018) {
1041 diff=0x1C-(dkeaddr&0xFFF);
1042 return dkeaddr+diff;
1044 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1045 /* readjust to 0x000,
1046 * but ONLY if we are >0x1000 already
1048 if (dkeaddr & ~0xFFF)
1049 return dkeaddr & ~0xFFF;
1055 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1057 static struct _w95key*
1058 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1061 if (dkeaddr == 0xFFFFFFFF)
1065 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1066 off = (dkeaddr-0x3c)/0x1c;
1068 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1069 return keys+nr2da[(i+off)%n].nr;
1070 /* 0x3C happens often, just report unusual values */
1072 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1077 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1078 /* Disk Key Entry structure (RGKN part) */
1082 unsigned long x3;/*usually 0xFFFFFFFF */
1083 unsigned long prevlvl;
1084 unsigned long nextsub;
1086 unsigned short nrLS;
1087 unsigned short nrMS;
1089 /* Disk Key Header structure (RGDB part) */
1091 unsigned long nextkeyoff;
1092 unsigned short nrLS;
1093 unsigned short nrMS;
1094 unsigned long bytesused;
1095 unsigned short keynamelen;
1096 unsigned short values;
1099 /* disk key values or nothing */
1101 /* Disk Key Value structure */
1105 unsigned short valnamelen;
1106 unsigned short valdatalen;
1107 /* valname, valdata */
1109 struct _w95nr2da *nr2da;
1114 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1115 struct _w95key *keys;
1117 unsigned char *data,*curdata,*nextrgdb;
1119 BY_HANDLE_FILE_INFORMATION hfdinfo;
1121 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1122 hfd=OpenFile32(fn,&ofs,OF_READ);
1123 if (hfd==HFILE_ERROR32)
1126 if (4!=_lread32(hfd,magic,4))
1128 if (strcmp(magic,"CREG")) {
1129 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1132 if (4!=_lread32(hfd,&version,4))
1134 if (4!=_lread32(hfd,&rgdbsection,4))
1136 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1138 if (4!=_lread32(hfd,magic,4))
1140 if (strcmp(magic,"RGKN")) {
1141 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1145 /* STEP 1: Keylink structures */
1146 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1151 nrofdkes = (end-where)/sizeof(struct dke)+100;
1152 data = (char*)xmalloc(end-where);
1153 if ((end-where)!=_lread32(hfd,data,end-where))
1157 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1158 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1159 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1160 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1162 for (i=0;i<nrofdkes;i++) {
1164 unsigned long dkeaddr;
1166 pos=curdata-data+0x40;
1167 memcpy(&dke,curdata,sizeof(dke));
1168 curdata+=sizeof(dke);
1169 nr = dke.nrLS + (dke.nrMS<<8);
1171 if ((dkeaddr&0xFFF)<0x018) {
1174 diff=0x1C-(dkeaddr&0xFFF);
1176 curdata+=diff-sizeof(dke);
1177 memcpy(&dke,curdata,sizeof(dke));
1178 nr = dke.nrLS + (dke.nrMS<<8);
1179 curdata+=sizeof(dke);
1181 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1182 /* readjust to 0x000,
1183 * but ONLY if we are >0x1000 already
1185 if (dkeaddr & ~0xFFF)
1186 dkeaddr = dkeaddr & ~0xFFF;
1189 /* 0xFFFFFFFF happens often, just report unusual values */
1191 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1194 if (keys[nr].dkeaddr) {
1197 for (x=sizeof(dke);x--;)
1198 if (((char*)&dke)[x])
1201 break; /* finished reading if we got only 0 */
1203 if ( (dke.next!=(long)keys[nr].next) ||
1204 (dke.nextsub!=(long)keys[nr].nextsub) ||
1205 (dke.prevlvl!=(long)keys[nr].prevlvl)
1207 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1212 nr2da[i].dkeaddr = dkeaddr;
1214 keys[nr].dkeaddr = dkeaddr;
1215 keys[nr].x1 = dke.x1;
1216 keys[nr].x2 = dke.x2;
1217 keys[nr].x3 = dke.x3;
1218 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1219 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1220 keys[nr].next = (struct _w95key*)dke.next;
1224 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1225 (int(*)(const void *,const void*))_w95dkecomp);
1227 /* STEP 2: keydata & values */
1228 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1230 end = hfdinfo.nFileSizeLow;
1231 lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1233 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1235 data = (char*)xmalloc(end-rgdbsection);
1236 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1240 memcpy(magic,curdata,4);
1241 memcpy(&off_next_rgdb,curdata+4,4);
1242 nextrgdb = curdata+off_next_rgdb;
1243 if (strcmp(magic,"RGDB")) {
1244 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1251 struct _w95key *key,xkey;
1254 if (curdata>=nextrgdb) {
1256 if (!strncmp(curdata,"RGDB",4)) {
1257 memcpy(&off_next_rgdb,curdata+4,4);
1258 nextrgdb = curdata+off_next_rgdb;
1261 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1265 #define XREAD(whereto,len) \
1266 if ((curdata-data+len)<end) {\
1267 memcpy(whereto,curdata,len);\
1272 XREAD(&dkh,sizeof(dkh));
1273 nr = dkh.nrLS + (dkh.nrMS<<8);
1274 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1275 if (dkh.nrLS == 0xFFFF) {
1276 /* skip over key using nextkeyoff */
1277 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1280 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1282 memset(key,'\0',sizeof(xkey));
1286 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1288 key->nrofvals = dkh.values;
1289 key->name = (char*)xmalloc(dkh.keynamelen+1);
1291 XREAD(key->name,dkh.keynamelen);
1292 key->name[dkh.keynamelen]=0;
1293 if (key->nrofvals) {
1294 key->values = (struct _w95keyvalue*)xmalloc(
1295 sizeof(struct _w95keyvalue)*key->nrofvals
1297 for (i=0;i<key->nrofvals;i++) {
1300 XREAD(&dkv,sizeof(dkv));
1301 key->values[i].type = dkv.type;
1302 key->values[i].name = (char*)xmalloc(
1305 key->values[i].datalen = dkv.valdatalen;
1306 key->values[i].data = (unsigned char*)xmalloc(
1309 key->values[i].x1 = dkv.x1;
1310 XREAD(key->values[i].name,dkv.valnamelen);
1311 XREAD(key->values[i].data,dkv.valdatalen);
1312 key->values[i].data[dkv.valdatalen]=0;
1313 key->values[i].name[dkv.valnamelen]=0;
1314 key->values[i].lastmodified=lastmodified;
1317 if (bytesread != dkh.nextkeyoff) {
1318 if (dkh.bytesused != bytesread)
1320 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1323 curdata += dkh.nextkeyoff-bytesread;
1325 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1326 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1327 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1332 _w95_walk_tree(lpkey,keys);
1336 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1339 reghack - windows 3.11 registry data format demo program.
1341 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1342 a combined hash table and tree description, and finally a text table.
1344 The header is obvious from the struct header. The taboff1 and taboff2
1345 fields are always 0x20, and their usage is unknown.
1347 The 8-byte entry table has various entry types.
1349 tabent[0] is a root index. The second word has the index of the root of
1351 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1352 the index of the key/value that has that hash. Data with the same
1353 hash value are on a circular list. The other three words in the
1354 hash entry are always zero.
1355 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1356 entry: dirent and keyent/valent. They are identified by context.
1357 tabent[freeidx] is the first free entry. The first word in a free entry
1358 is the index of the next free entry. The last has 0 as a link.
1359 The other three words in the free list are probably irrelevant.
1361 Entries in text table are preceeded by a word at offset-2. This word
1362 has the value (2*index)+1, where index is the referring keyent/valent
1363 entry in the table. I have no suggestion for the 2* and the +1.
1364 Following the word, there are N bytes of data, as per the keyent/valent
1365 entry length. The offset of the keyent/valent entry is from the start
1366 of the text table to the first data byte.
1368 This information is not available from Microsoft. The data format is
1369 deduced from the reg.dat file by me. Mistakes may
1370 have been made. I claim no rights and give no guarantees for this program.
1372 Tor Sjøwall, tor@sn.no
1375 /* reg.dat header format */
1376 struct _w31_header {
1377 char cookie[8]; /* 'SHCC3.10' */
1378 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1379 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1380 unsigned long tabcnt; /* number of entries in index table */
1381 unsigned long textoff; /* offset of text part */
1382 unsigned long textsize; /* byte size of text part */
1383 unsigned short hashsize; /* hash size */
1384 unsigned short freeidx; /* free index */
1387 /* generic format of table entries */
1388 struct _w31_tabent {
1389 unsigned short w0, w1, w2, w3;
1392 /* directory tabent: */
1393 struct _w31_dirent {
1394 unsigned short sibling_idx; /* table index of sibling dirent */
1395 unsigned short child_idx; /* table index of child dirent */
1396 unsigned short key_idx; /* table index of key keyent */
1397 unsigned short value_idx; /* table index of value valent */
1401 struct _w31_keyent {
1402 unsigned short hash_idx; /* hash chain index for string */
1403 unsigned short refcnt; /* reference count */
1404 unsigned short length; /* length of string */
1405 unsigned short string_off; /* offset of string in text table */
1409 struct _w31_valent {
1410 unsigned short hash_idx; /* hash chain index for string */
1411 unsigned short refcnt; /* reference count */
1412 unsigned short length; /* length of string */
1413 unsigned short string_off; /* offset of string in text table */
1416 /* recursive helper function to display a directory tree */
1418 __w31_dumptree( unsigned short idx,
1420 struct _w31_tabent *tab,
1421 struct _w31_header *head,
1423 time_t lastmodified,
1426 struct _w31_dirent *dir;
1427 struct _w31_keyent *key;
1428 struct _w31_valent *val;
1429 LPKEYSTRUCT xlpkey = NULL;
1431 static char tail[400];
1434 dir=(struct _w31_dirent*)&tab[idx];
1437 key = (struct _w31_keyent*)&tab[dir->key_idx];
1439 memcpy(tail,&txt[key->string_off],key->length);
1440 tail[key->length]='\0';
1441 /* all toplevel entries AND the entries in the
1442 * toplevel subdirectory belong to \SOFTWARE\Classes
1444 if (!level && !lstrcmp32A(tail,".classes")) {
1445 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1446 idx=dir->sibling_idx;
1449 name=STRING32_DupAnsiToUni(tail);
1451 xlpkey=_find_or_add_key(lpkey,name);
1453 /* only add if leaf node or valued node */
1454 if (dir->value_idx!=0||dir->child_idx==0) {
1455 if (dir->value_idx) {
1456 val=(struct _w31_valent*)&tab[dir->value_idx];
1457 memcpy(tail,&txt[val->string_off],val->length);
1458 tail[val->length]='\0';
1459 value=STRING32_DupAnsiToUni(tail);
1460 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1464 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1466 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1467 idx=dir->sibling_idx;
1474 struct _w31_header head;
1475 struct _w31_tabent *tab;
1479 BY_HANDLE_FILE_INFORMATION hfinfo;
1480 time_t lastmodified;
1484 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1485 if (hf==HFILE_ERROR32)
1488 /* read & dump header */
1489 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1490 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1494 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1495 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1500 len = head.tabcnt * sizeof(struct _w31_tabent);
1501 /* read and dump index table */
1503 if (len!=_lread32(hf,tab,len)) {
1504 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1511 txt = xmalloc(head.textsize);
1512 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1513 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1519 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1520 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1527 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1528 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1534 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1536 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1538 lpkey = lookup_hkey(hkey);
1539 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1547 SHELL_LoadRegistry() {
1554 if (key_classes_root==NULL)
1557 /* Load windows 3.1 entries */
1559 /* Load windows 95 entries */
1560 _w95_loadreg("C:\\system.1st", key_local_machine);
1561 _w95_loadreg("system.dat", key_local_machine);
1562 _w95_loadreg("user.dat", key_users);
1564 /* the global user default is loaded under HKEY_USERS\\.Default */
1565 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1566 lpkey = lookup_hkey(hkey);
1567 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1569 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1570 _copy_registry(lpkey,key_current_user);
1573 /* the global machine defaults */
1574 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1576 /* load the user saved registries */
1578 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1580 pwd=getpwuid(getuid());
1581 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1582 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1583 strcpy(fn,pwd->pw_dir);
1584 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1585 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1587 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1588 strcpy(fn,pwd->pw_dir);
1589 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1590 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1593 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1594 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1595 DWORD junk,type,len;
1599 if (( RegQueryValueEx32A(
1606 )!=ERROR_SUCCESS) ||
1609 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1615 /********************* API FUNCTIONS ***************************************/
1619 * All functions are stubs to RegOpenKeyEx32W where all the
1622 * FIXME: security,options,desiredaccess,...
1625 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1626 * RegOpenKey32W -> RegOpenKeyEx32W
1629 /* RegOpenKeyExW [ADVAPI32.150] */
1630 DWORD RegOpenKeyEx32W(
1637 LPKEYSTRUCT lpNextKey,lpxkey;
1640 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1641 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1644 lpNextKey = lookup_hkey(hkey);
1646 return SHELL_ERROR_BADKEY;
1647 if (!lpszSubKey || !*lpszSubKey) {
1648 add_handle(++currenthandle,lpNextKey,samDesired);
1649 *retkey=currenthandle;
1650 return SHELL_ERROR_SUCCESS;
1652 split_keypath(lpszSubKey,&wps,&wpc);
1654 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1657 lpxkey=lpNextKey->nextsub;
1659 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1661 lpxkey=lpxkey->next;
1665 return SHELL_ERROR_BADKEY;
1670 add_handle(++currenthandle,lpxkey,samDesired);
1671 *retkey = currenthandle;
1673 return SHELL_ERROR_SUCCESS;
1676 /* RegOpenKeyW [ADVAPI32.151] */
1677 DWORD RegOpenKey32W(
1682 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1683 (LONG)hkey,W2C(lpszSubKey,0),retkey
1685 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1689 /* RegOpenKeyExA [ADVAPI32.149] */
1690 DWORD RegOpenKeyEx32A(
1700 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1701 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1704 lpszSubKeyW=strdupA2W(lpszSubKey);
1707 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1713 /* RegOpenKeyA [ADVAPI32.148] */
1714 DWORD RegOpenKey32A(
1719 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1720 (LONG)hkey,lpszSubKey,retkey
1722 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1725 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1731 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1732 (LONG)hkey,lpszSubKey,retkey
1734 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1740 * All those functions convert their respective
1741 * arguments and call RegCreateKeyExW at the end.
1743 * FIXME: no security,no access attrib,no optionhandling yet.
1746 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1747 * RegCreateKey32W -> RegCreateKeyEx32W
1750 /* RegCreateKeyExW [ADVAPI32.131] */
1751 DWORD RegCreateKeyEx32W(
1758 LPSECURITY_ATTRIBUTES lpSecAttribs,
1762 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1766 /*FIXME: handle security/access/whatever */
1767 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1779 lpNextKey = lookup_hkey(hkey);
1781 return SHELL_ERROR_BADKEY;
1782 if (!lpszSubKey || !*lpszSubKey) {
1783 add_handle(++currenthandle,lpNextKey,samDesired);
1784 *retkey=currenthandle;
1785 lpNextKey->flags|=REG_OPTION_TAINTED;
1786 return SHELL_ERROR_SUCCESS;
1788 split_keypath(lpszSubKey,&wps,&wpc);
1790 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1793 lpxkey=lpNextKey->nextsub;
1795 if (!lstrcmp32W(wps[i],lpxkey->keyname))
1797 lpxkey=lpxkey->next;
1805 add_handle(++currenthandle,lpxkey,samDesired);
1806 lpxkey->flags |= REG_OPTION_TAINTED;
1807 *retkey = currenthandle;
1809 *lpDispos = REG_OPENED_EXISTING_KEY;
1811 return SHELL_ERROR_SUCCESS;
1813 /* good. now the hard part */
1815 lplpPrevKey = &(lpNextKey->nextsub);
1816 lpxkey = *lplpPrevKey;
1818 lplpPrevKey = &(lpxkey->next);
1819 lpxkey = *lplpPrevKey;
1821 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1822 if (!*lplpPrevKey) {
1824 return SHELL_ERROR_OUTOFMEMORY;
1826 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1827 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1828 (*lplpPrevKey)->next = NULL;
1829 (*lplpPrevKey)->nextsub = NULL;
1830 (*lplpPrevKey)->values = NULL;
1831 (*lplpPrevKey)->nrofvalues = 0;
1832 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1834 (*lplpPrevKey)->class = strdupW(lpszClass);
1836 (*lplpPrevKey)->class = NULL;
1837 lpNextKey = *lplpPrevKey;
1840 add_handle(++currenthandle,lpNextKey,samDesired);
1842 /*FIXME: flag handling correct? */
1843 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1845 lpNextKey->class = strdupW(lpszClass);
1847 lpNextKey->class = NULL;
1848 *retkey = currenthandle;
1850 *lpDispos = REG_CREATED_NEW_KEY;
1852 return SHELL_ERROR_SUCCESS;
1855 /* RegCreateKeyW [ADVAPI32.132] */
1856 DWORD RegCreateKey32W(
1863 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1864 (LONG)hkey,W2C(lpszSubKey,0),retkey
1866 ret=RegCreateKeyEx32W(
1867 hkey, /* key handle */
1868 lpszSubKey, /* subkey name */
1869 0, /* reserved = 0 */
1870 NULL, /* lpszClass? FIXME: ? */
1871 REG_OPTION_NON_VOLATILE, /* options */
1872 KEY_ALL_ACCESS, /* desired access attribs */
1873 NULL, /* lpsecurity attributes */
1874 retkey, /* lpretkey */
1875 &junk /* disposition value */
1880 /* RegCreateKeyExA [ADVAPI32.130] */
1881 DWORD RegCreateKeyEx32A(
1888 LPSECURITY_ATTRIBUTES lpSecAttribs,
1892 LPWSTR lpszSubKeyW,lpszClassW;
1895 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1907 lpszSubKeyW=strdupA2W(lpszSubKey);
1911 lpszClassW=strdupA2W(lpszClass);
1914 ret=RegCreateKeyEx32W(
1932 /* RegCreateKeyA [ADVAPI32.129] */
1933 DWORD RegCreateKey32A(
1940 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1941 (LONG)hkey,lpszSubKey,retkey
1943 return RegCreateKeyEx32A(
1944 hkey, /* key handle */
1945 lpszSubKey, /* subkey name */
1946 0, /* reserved = 0 */
1947 NULL, /* lpszClass? FIXME: ? */
1948 REG_OPTION_NON_VOLATILE,/* options */
1949 KEY_ALL_ACCESS, /* desired access attribs */
1950 NULL, /* lpsecurity attributes */
1951 retkey, /* lpretkey */
1952 &junk /* disposition value */
1956 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1957 DWORD RegCreateKey16(
1962 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1963 (LONG)hkey,lpszSubKey,retkey
1965 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1969 * Query Value Functions
1970 * Win32 differs between keynames and valuenames.
1971 * multiple values may belong to one key, the special value
1972 * with name NULL is the default value used by the win31
1976 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1977 * RegQueryValue32W -> RegQueryValueEx32W
1980 /* RegQueryValueExW [ADVAPI32.158] */
1981 DWORD RegQueryValueEx32W(
1983 LPWSTR lpszValueName,
1984 LPDWORD lpdwReserved,
1992 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1993 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1994 lpcbData?*lpcbData:0
1997 lpkey = lookup_hkey(hkey);
1999 return SHELL_ERROR_BADKEY;
2000 if (lpszValueName==NULL) {
2001 for (i=0;i<lpkey->nrofvalues;i++)
2002 if (lpkey->values[i].name==NULL)
2005 for (i=0;i<lpkey->nrofvalues;i++)
2006 if ( lpkey->values[i].name &&
2007 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2011 if (i==lpkey->nrofvalues) {
2012 if (lpszValueName==NULL) {
2014 *(WCHAR*)lpbData = 0;
2019 return SHELL_ERROR_SUCCESS;
2021 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2024 *lpdwType = lpkey->values[i].type;
2025 if (lpbData==NULL) {
2027 return SHELL_ERROR_SUCCESS;
2028 *lpcbData = lpkey->values[i].len;
2029 return SHELL_ERROR_SUCCESS;
2031 if (*lpcbData<lpkey->values[i].len) {
2034 *lpcbData = lpkey->values[i].len;
2035 return ERROR_MORE_DATA;
2037 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2038 *lpcbData = lpkey->values[i].len;
2039 return SHELL_ERROR_SUCCESS;
2042 /* RegQueryValueW [ADVAPI32.159] */
2043 DWORD RegQueryValue32W(
2052 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2053 hkey,W2C(lpszSubKey,0),lpszData,
2054 lpcbData?*lpcbData:0
2057 /* only open subkey, if we really do descend */
2058 if (lpszSubKey && *lpszSubKey) {
2059 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2060 if (ret!=ERROR_SUCCESS)
2066 ret = RegQueryValueEx32W(
2068 NULL, /* varname NULL -> compat */
2069 NULL, /* lpdwReserved, must be NULL */
2079 /* RegQueryValueExA [ADVAPI32.157] */
2080 DWORD RegQueryValueEx32A(
2082 LPSTR lpszValueName,
2083 LPDWORD lpdwReserved,
2088 LPWSTR lpszValueNameW;
2094 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2095 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2096 lpcbData?*lpcbData:0
2100 buf = (LPBYTE)xmalloc((*lpcbData)*2);
2101 myxlen = *lpcbData*2;
2106 myxlen = *lpcbData*2;
2112 lpszValueNameW=strdupA2W(lpszValueName);
2114 lpszValueNameW=NULL;
2118 ret=RegQueryValueEx32W(
2128 if (ret==ERROR_SUCCESS) {
2130 if (UNICONVMASK & (1<<(type))) {
2131 /* convert UNICODE to ASCII */
2132 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2133 *lpcbData = myxlen/2;
2135 if (myxlen>*lpcbData)
2136 ret = ERROR_MORE_DATA;
2138 memcpy(lpbData,buf,myxlen);
2143 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2144 *lpcbData = myxlen/2;
2147 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2148 *lpcbData = myxlen/2;
2155 /* RegQueryValueEx [KERNEL.225] */
2156 DWORD RegQueryValueEx16(
2158 LPSTR lpszValueName,
2159 LPDWORD lpdwReserved,
2164 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2165 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2166 lpcbData?*lpcbData:0
2168 return RegQueryValueEx32A(
2178 /* RegQueryValueA [ADVAPI32.156] */
2179 DWORD RegQueryValue32A(
2188 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2189 hkey,lpszSubKey,lpszData,
2190 lpcbData?*lpcbData:0
2193 /* only open subkey, if we really do descend */
2194 if (lpszSubKey && *lpszSubKey) {
2195 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2196 if (ret!=ERROR_SUCCESS)
2202 ret = RegQueryValueEx32A(
2204 NULL, /* lpszValueName NULL -> compat */
2205 NULL, /* lpdwReserved, must be NULL */
2215 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2216 DWORD RegQueryValue16(
2222 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2223 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2225 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2226 * anyway, so we just mask out the high 16 bit.
2227 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2230 *lpcbData &= 0xFFFF;
2231 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2235 * Setting values of Registry keys
2238 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2239 * RegSetValue32W -> RegSetValueEx32W
2242 /* RegSetValueExW [ADVAPI32.170] */
2243 DWORD RegSetValueEx32W(
2245 LPWSTR lpszValueName,
2254 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2255 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2257 /* we no longer care about the lpbData type here... */
2258 lpkey = lookup_hkey(hkey);
2260 return SHELL_ERROR_BADKEY;
2262 lpkey->flags |= REG_OPTION_TAINTED;
2264 if (lpszValueName==NULL) {
2265 for (i=0;i<lpkey->nrofvalues;i++)
2266 if (lpkey->values[i].name==NULL)
2269 for (i=0;i<lpkey->nrofvalues;i++)
2270 if ( lpkey->values[i].name &&
2271 !lstrcmp32W(lpszValueName,lpkey->values[i].name)
2275 if (i==lpkey->nrofvalues) {
2276 lpkey->values = (LPKEYVALUE)xrealloc(
2278 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2280 lpkey->nrofvalues++;
2281 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2283 if (lpkey->values[i].name==NULL)
2285 lpkey->values[i].name = strdupW(lpszValueName);
2287 lpkey->values[i].name = NULL;
2288 lpkey->values[i].len = cbData;
2289 lpkey->values[i].type = dwType;
2290 if (lpkey->values[i].data !=NULL)
2291 free(lpkey->values[i].data);
2292 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2293 lpkey->values[i].lastmodified = time(NULL);
2294 memcpy(lpkey->values[i].data,lpbData,cbData);
2295 return SHELL_ERROR_SUCCESS;
2298 /* RegSetValueExA [ADVAPI32.169] */
2299 DWORD RegSetValueEx32A(
2301 LPSTR lpszValueName,
2308 LPWSTR lpszValueNameW;
2311 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2312 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2314 if ((1<<dwType) & UNICONVMASK) {
2315 buf=(LPBYTE)strdupA2W(lpbData);
2316 cbData=2*strlen(lpbData)+2;
2320 lpszValueNameW = strdupA2W(lpszValueName);
2322 lpszValueNameW = NULL;
2323 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2325 free(lpszValueNameW);
2331 /* RegSetValueEx [KERNEL.226] */
2332 DWORD RegSetValueEx16(
2334 LPSTR lpszValueName,
2340 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2341 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2343 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2346 /* RegSetValueW [ADVAPI32.171] */
2347 DWORD RegSetValue32W(
2357 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2358 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2360 if (lpszSubKey && *lpszSubKey) {
2361 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2362 if (ret!=ERROR_SUCCESS)
2366 if (dwType!=REG_SZ) {
2367 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2370 if (cbData!=2*lstrlen32W(lpszData)+2) {
2371 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2372 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2374 cbData=2*lstrlen32W(lpszData)+2;
2376 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2382 /* RegSetValueA [ADVAPI32.168] */
2383 DWORD RegSetValue32A(
2393 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2394 hkey,lpszSubKey,dwType,lpszData,cbData
2396 if (lpszSubKey && *lpszSubKey) {
2397 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2398 if (ret!=ERROR_SUCCESS)
2403 if (dwType!=REG_SZ) {
2404 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2407 if (cbData!=strlen(lpszData)+1)
2408 cbData=strlen(lpszData)+1;
2409 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2415 /* RegSetValue [KERNEL.221] [SHELL.5] */
2416 DWORD RegSetValue16(
2424 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2425 hkey,lpszSubKey,dwType,lpszData,cbData
2427 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2435 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2436 * RegEnumKey32W -> RegEnumKeyEx32W
2439 /* RegEnumKeyExW [ADVAPI32.139] */
2440 DWORD RegEnumKeyEx32W(
2445 LPDWORD lpdwReserved,
2450 LPKEYSTRUCT lpkey,lpxkey;
2452 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2453 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2455 lpkey=lookup_hkey(hkey);
2457 return SHELL_ERROR_BADKEY;
2458 if (!lpkey->nextsub)
2459 return ERROR_NO_MORE_ITEMS;
2460 lpxkey=lpkey->nextsub;
2461 while (iSubkey && lpxkey) {
2463 lpxkey=lpxkey->next;
2465 if (iSubkey || !lpxkey)
2466 return ERROR_NO_MORE_ITEMS;
2467 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2468 return ERROR_MORE_DATA;
2469 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2471 /* what should we write into it? */
2475 return ERROR_SUCCESS;
2479 /* RegEnumKeyW [ADVAPI32.140] */
2480 DWORD RegEnumKey32W(
2488 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2489 hkey,iSubkey,lpszName,lpcchName
2491 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2493 /* RegEnumKeyExA [ADVAPI32.138] */
2494 DWORD RegEnumKeyEx32A(
2499 LPDWORD lpdwReserved,
2504 DWORD ret,lpcchNameW,lpcchClassW;
2505 LPWSTR lpszNameW,lpszClassW;
2508 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2509 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2512 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2513 lpcchNameW = *lpcchName*2;
2519 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2520 lpcchClassW = *lpcchClass*2;
2525 ret=RegEnumKeyEx32W(
2535 if (ret==ERROR_SUCCESS) {
2536 lstrcpyWtoA(lpszName,lpszNameW);
2537 *lpcchName=strlen(lpszName);
2539 lstrcpyWtoA(lpszClass,lpszClassW);
2540 *lpcchClass=strlen(lpszClass);
2550 /* RegEnumKeyA [ADVAPI32.137] */
2551 DWORD RegEnumKey32A(
2559 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2560 hkey,iSubkey,lpszName,lpcchName
2562 return RegEnumKeyEx32A(
2574 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2581 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2582 hkey,iSubkey,lpszName,lpcchName
2584 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2588 * Enumerate Registry Values
2591 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2594 /* RegEnumValueW [ADVAPI32.142] */
2595 DWORD RegEnumValue32W(
2600 LPDWORD lpdReserved,
2608 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2609 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2611 lpkey = lookup_hkey(hkey);
2613 return SHELL_ERROR_BADKEY;
2614 if (lpkey->nrofvalues<=iValue)
2615 return ERROR_NO_MORE_ITEMS;
2616 val = lpkey->values+iValue;
2619 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2620 *lpcchValue = lstrlen32W(val->name)*2+2;
2621 return ERROR_MORE_DATA;
2623 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2624 *lpcchValue=lstrlen32W(val->name)*2+2;
2626 /* how to handle NULL value? */
2630 *lpdwType=val->type;
2632 if (val->len>*lpcbData)
2633 return ERROR_MORE_DATA;
2634 memcpy(lpbData,val->data,val->len);
2635 *lpcbData = val->len;
2637 return SHELL_ERROR_SUCCESS;
2640 /* RegEnumValueA [ADVAPI32.141] */
2641 DWORD RegEnumValue32A(
2646 LPDWORD lpdReserved,
2653 DWORD ret,lpcbDataW;
2655 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2656 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2659 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2661 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2662 lpcbDataW = *lpcbData*2;
2665 ret=RegEnumValue32W(
2676 if (ret==ERROR_SUCCESS) {
2677 lstrcpyWtoA(lpszValue,lpszValueW);
2679 if ((1<<*lpdwType) & UNICONVMASK) {
2680 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2682 if (lpcbDataW > *lpcbData)
2683 ret = ERROR_MORE_DATA;
2685 memcpy(lpbData,lpbDataW,lpcbDataW);
2687 *lpcbData = lpcbDataW;
2697 /* RegEnumValue [KERNEL.223] */
2698 DWORD RegEnumValue16(
2703 LPDWORD lpdReserved,
2708 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2709 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2711 return RegEnumValue32A(
2724 * Close registry key
2726 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2727 DWORD RegCloseKey(HKEY hkey) {
2728 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2729 remove_handle(hkey);
2730 return ERROR_SUCCESS;
2733 * Delete registry key
2736 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2738 /* RegDeleteKeyW [ADVAPI32.134] */
2739 DWORD RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2740 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2744 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2745 hkey,W2C(lpszSubKey,0)
2747 lpNextKey = lookup_hkey(hkey);
2749 return SHELL_ERROR_BADKEY;
2750 /* we need to know the previous key in the hier. */
2751 if (!lpszSubKey || !*lpszSubKey)
2752 return SHELL_ERROR_BADKEY;
2753 split_keypath(lpszSubKey,&wps,&wpc);
2757 lpxkey=lpNextKey->nextsub;
2759 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2761 lpxkey=lpxkey->next;
2765 /* not found is success */
2766 return SHELL_ERROR_SUCCESS;
2771 lpxkey = lpNextKey->nextsub;
2772 lplpPrevKey = &(lpNextKey->nextsub);
2774 if (!lstrcmp32W(wps[i],lpxkey->keyname))
2776 lplpPrevKey = &(lpxkey->next);
2777 lpxkey = lpxkey->next;
2780 return SHELL_ERROR_SUCCESS;
2781 if (lpxkey->nextsub)
2782 return SHELL_ERROR_CANTWRITE;
2783 *lplpPrevKey = lpxkey->next;
2784 free(lpxkey->keyname);
2786 free(lpxkey->class);
2788 free(lpxkey->values);
2791 return SHELL_ERROR_SUCCESS;
2794 /* RegDeleteKeyA [ADVAPI32.133] */
2795 DWORD RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2799 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2802 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2803 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2804 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2808 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2809 DWORD RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2810 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2813 return RegDeleteKey32A(hkey,lpszSubKey);
2817 * Delete registry value
2820 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2822 /* RegDeleteValueW [ADVAPI32.136] */
2823 DWORD RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue) {
2828 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2829 hkey,W2C(lpszValue,0)
2831 lpkey=lookup_hkey(hkey);
2833 return SHELL_ERROR_BADKEY;
2835 for (i=0;i<lpkey->nrofvalues;i++)
2836 if ( lpkey->values[i].name &&
2837 !lstrcmp32W(lpkey->values[i].name,lpszValue)
2841 for (i=0;i<lpkey->nrofvalues;i++)
2842 if (lpkey->values[i].name==NULL)
2845 if (i==lpkey->nrofvalues)
2846 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2847 val = lpkey->values+i;
2848 if (val->name) free(val->name);
2849 if (val->data) free(val->data);
2853 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2855 lpkey->values = (LPKEYVALUE)xrealloc(
2857 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2859 lpkey->nrofvalues--;
2860 return SHELL_ERROR_SUCCESS;
2863 /* RegDeleteValueA [ADVAPI32.135] */
2864 DWORD RegDeleteValue32A(HKEY hkey,LPSTR lpszValue) {
2868 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2869 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2870 ret=RegDeleteValue32W(hkey,lpszValueW);
2871 HeapFree(GetProcessHeap(),0,lpszValueW);
2875 /* RegDeleteValue [KERNEL.222] */
2876 DWORD RegDeleteValue16(HKEY hkey,LPSTR lpszValue) {
2877 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2878 return RegDeleteValue32A(hkey,lpszValue);
2881 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2882 DWORD RegFlushKey(HKEY hkey) {
2883 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2884 return SHELL_ERROR_SUCCESS;
2887 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2889 /* RegQueryInfoKeyW [ADVAPI32.153] */
2890 DWORD RegQueryInfoKey32W(
2894 LPDWORD lpdwReserved,
2896 LPDWORD lpcchMaxSubkey,
2897 LPDWORD lpcchMaxClass,
2899 LPDWORD lpcchMaxValueName,
2900 LPDWORD lpccbMaxValueData,
2901 LPDWORD lpcbSecurityDescriptor,
2904 LPKEYSTRUCT lpkey,lpxkey;
2905 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2908 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2909 lpkey=lookup_hkey(hkey);
2911 return SHELL_ERROR_BADKEY;
2914 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2915 *lpcchClass=lstrlen32W(lpkey->class)*2;
2916 return ERROR_MORE_DATA;
2918 *lpcchClass=lstrlen32W(lpkey->class)*2;
2919 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2926 *lpcchClass = lstrlen32W(lpkey->class)*2;
2928 lpxkey=lpkey->nextsub;
2929 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2932 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2933 maxsubkey=lstrlen32W(lpxkey->keyname);
2934 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2935 maxclass=lstrlen32W(lpxkey->class);
2936 if (lpxkey->nrofvalues>maxvalues)
2937 maxvalues=lpxkey->nrofvalues;
2938 for (i=0;i<lpxkey->nrofvalues;i++) {
2939 LPKEYVALUE val=lpxkey->values+i;
2941 if (val->name && lstrlen32W(val->name)>maxvname)
2942 maxvname=lstrlen32W(val->name);
2943 if (val->len>maxvdata)
2946 lpxkey=lpxkey->next;
2948 if (!maxclass) maxclass = 1;
2949 if (!maxvname) maxvname = 1;
2951 *lpcSubKeys = nrofkeys;
2953 *lpcchMaxSubkey = maxsubkey*2;
2955 *lpcchMaxClass = maxclass*2;
2957 *lpcValues = maxvalues;
2958 if (lpcchMaxValueName)
2959 *lpcchMaxValueName= maxvname;
2960 if (lpccbMaxValueData)
2961 *lpccbMaxValueData= maxvdata;
2962 return SHELL_ERROR_SUCCESS;
2965 /* RegQueryInfoKeyA [ADVAPI32.152] */
2966 DWORD RegQueryInfoKey32A(
2970 LPDWORD lpdwReserved,
2972 LPDWORD lpcchMaxSubkey,
2973 LPDWORD lpcchMaxClass,
2975 LPDWORD lpcchMaxValueName,
2976 LPDWORD lpccbMaxValueData,
2977 LPDWORD lpcbSecurityDescriptor,
2983 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2986 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2990 ret=RegQueryInfoKey32W(
3001 lpcbSecurityDescriptor,
3004 if (ret==ERROR_SUCCESS)
3005 lstrcpyWtoA(lpszClass,lpszClassW);
3012 if (lpcchMaxValueName)
3013 *lpcchMaxValueName/=2;
3018 /* RegConnectRegistryA [ADVAPI32.127] */
3019 DWORD RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey) {
3020 fprintf(stderr,"RegConnectRegistry32A(%s,%08lx,%p), STUB.\n",
3023 return ERROR_FILE_NOT_FOUND; /* FIXME */