4 * Copyright 1996 Marcus Meissner
13 #include <sys/types.h>
14 #include <sys/fcntl.h>
29 /* FIXME: following defines should be configured global ... */
31 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
32 #define WINE_PREFIX "/.wine"
33 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
34 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
36 /* relative in ~user/.wine/ : */
37 #define SAVE_CURRENT_USER "user.reg"
38 #define SAVE_LOCAL_MACHINE "system.reg"
40 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
41 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
43 /* one value of a key */
44 typedef struct tagKEYVALUE
46 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
47 DWORD type; /* type of value */
48 DWORD len; /* length of data */
49 DWORD lastmodified; /* time of seconds since 1.1.1970 */
50 LPBYTE data; /* content, may be strings, binaries, etc. */
51 } KEYVALUE,*LPKEYVALUE;
54 typedef struct tagKEYSTRUCT
56 LPWSTR keyname; /* name of THIS key (UNICODE) */
57 DWORD flags; /* flags. */
60 DWORD nrofvalues; /* nr of values in THIS key */
61 LPKEYVALUE values; /* values in THIS key */
62 /* key management pointers */
63 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
64 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
65 } KEYSTRUCT, *LPKEYSTRUCT;
68 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
69 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
70 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
71 static KEYSTRUCT *key_users=NULL; /* all users? */
73 /* dynamic, not saved */
74 static KEYSTRUCT *key_performance_data=NULL;
75 static KEYSTRUCT *key_current_config=NULL;
76 static KEYSTRUCT *key_dyn_data=NULL;
78 /* what valuetypes do we need to convert? */
79 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
81 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
82 #define strdupW(x) STRING32_strdupW(x)
83 #define strchrW(a,c) STRING32_lstrchrW(a,c)
85 static struct openhandle {
90 static int nrofopenhandles=0;
91 static int currenthandle=1;
94 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
97 for (i=0;i<nrofopenhandles;i++) {
98 if (openhandles[i].lpkey==lpkey) {
99 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
101 if (openhandles[i].hkey==hkey) {
102 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
105 openhandles=xrealloc( openhandles,
106 sizeof(struct openhandle)*(nrofopenhandles+1)
108 openhandles[i].lpkey = lpkey;
109 openhandles[i].hkey = hkey;
110 openhandles[i].accessmask= accessmask;
115 get_handle(HKEY hkey) {
118 for (i=0;i<nrofopenhandles;i++)
119 if (openhandles[i].hkey==hkey)
120 return openhandles[i].lpkey;
121 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
126 remove_handle(HKEY hkey) {
129 for (i=0;i<nrofopenhandles;i++)
130 if (openhandles[i].hkey==hkey)
132 if (i==nrofopenhandles) {
133 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
136 memcpy( openhandles+i,
138 sizeof(struct openhandle)*(nrofopenhandles-i-1)
140 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
146 /* debug function, converts a unicode into a static memory area
147 * (sub for using two static strings, in case we need them in a single call)
150 W2C(LPCWSTR x,int sub) {
151 static LPSTR unicodedebug[2]={NULL,NULL};
154 if (sub!=0 && sub!=1)
155 return "<W2C:bad sub>";
156 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
157 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
158 return unicodedebug[sub];
162 lookup_hkey(HKEY hkey) {
166 case HKEY_CLASSES_ROOT:
167 return key_classes_root;
168 case HKEY_CURRENT_USER:
169 return key_current_user;
170 case HKEY_LOCAL_MACHINE:
171 return key_local_machine;
174 case HKEY_PERFORMANCE_DATA:
175 return key_performance_data;
178 case HKEY_CURRENT_CONFIG:
179 return key_current_config;
181 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
184 return get_handle(hkey);
190 * splits the unicode string 'wp' into an array of strings.
191 * the array is allocated by this function.
192 * the number of components will be stored in 'wpc'
193 * Free the array using FREE_KEY_PATH
196 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
200 ws = HEAP_strdupW( SystemHeap, 0, wp );
202 for (i=0;ws[i];i++) {
209 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
217 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
220 * Shell initialisation, allocates keys.
222 void SHELL_StartupRegistry();
227 HKEY cl_r_hkey,c_u_hkey;
228 #define ADD_ROOT_KEY(xx) \
229 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
230 memset(xx,'\0',sizeof(KEYSTRUCT));\
231 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
233 ADD_ROOT_KEY(key_local_machine);
234 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
235 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
238 key_classes_root = lookup_hkey(cl_r_hkey);
240 ADD_ROOT_KEY(key_users);
243 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
244 * (later, when a win32 registry editing tool becomes avail.)
246 while (pwd=getpwent()) {
247 if (pwd->pw_name == NULL)
249 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
250 RegCloseKey(c_u_hkey);
253 pwd=getpwuid(getuid());
254 if (pwd && pwd->pw_name) {
255 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
256 key_current_user = lookup_hkey(c_u_hkey);
258 ADD_ROOT_KEY(key_current_user);
260 ADD_ROOT_KEY(key_performance_data);
261 ADD_ROOT_KEY(key_current_config);
262 ADD_ROOT_KEY(key_dyn_data);
264 SHELL_StartupRegistry();
269 SHELL_StartupRegistry() {
272 char buf[200],cpubuf[200];
274 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
277 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
279 F=fopen("/proc/cpuinfo","r");
282 while (NULL!=fgets(buf,200,F)) {
283 if (sscanf(buf,"processor\t: %d",&x)) {
288 RegCreateKey16(hkey,buf,&xhkey);
290 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
291 sprintf(buf,"CPU %s",cpubuf);
293 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
303 RegCreateKey16(hkey,"0",&xhkey);
304 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
306 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
307 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
309 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
313 * string RegisteredOwner
314 * string RegisteredOrganization
317 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
322 if (-1!=gethostname(buf,200)) {
323 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
324 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
328 /************************ SAVE Registry Function ****************************/
330 #define REGISTRY_SAVE_VERSION 0x00000001
332 /* Registry saveformat:
333 * If you change it, increase above number by 1, which will flush
334 * old registry database files.
337 * "WINE REGISTRY Version %d"
341 * valuename=lastmodified,type,data
345 * keyname,valuename,stringdata:
346 * the usual ascii characters from 0x00-0xff (well, not 0x00)
347 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
348 * ( "=\\\t" escaped in \uXXXX form.)
352 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
354 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
355 * SaveOnlyUpdatedKeys=yes
358 _save_check_tainted(LPKEYSTRUCT lpkey) {
363 if (lpkey->flags & REG_OPTION_TAINTED)
368 if (_save_check_tainted(lpkey->nextsub)) {
369 lpkey->flags |= REG_OPTION_TAINTED;
378 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
391 if (escapeeq && *s=='=')
394 fputc(*s,F); /* if \\ then put it twice. */
396 fprintf(F,"\\u%04x",*((unsigned short*)s));
404 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
410 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
411 (all || (lpxkey->flags & REG_OPTION_TAINTED))
413 for (tabs=level;tabs--;)
415 _save_USTRING(F,lpxkey->keyname,1);
417 for (i=0;i<lpxkey->nrofvalues;i++) {
418 LPKEYVALUE val=lpxkey->values+i;
420 for (tabs=level+1;tabs--;)
422 _save_USTRING(F,val->name,0);
424 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
425 if ((1<<val->type) & UNICONVMASK)
426 _save_USTRING(F,(LPWSTR)val->data,0);
428 for (j=0;j<val->len;j++)
429 fprintf(F,"%02x",*((unsigned char*)val->data+j));
432 /* descend recursively */
433 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
442 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
443 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
444 _save_check_tainted(lpkey->nextsub);
445 return _savesubkey(F,lpkey->nextsub,0,all);
449 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
454 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
459 if (!_savesubreg(F,lpkey,all)) {
462 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
470 SHELL_SaveRegistry() {
478 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
484 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
496 if (lstrcmpi32A(buf,"yes"))
498 pwd=getpwuid(getuid());
499 if (pwd!=NULL && pwd->pw_dir!=NULL)
503 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
504 strlen(SAVE_CURRENT_USER) + 2 );
505 strcpy(fn,pwd->pw_dir);
506 strcat(fn,WINE_PREFIX);
507 /* create the directory. don't care about errorcodes. */
508 mkdir(fn,0755); /* drwxr-xr-x */
509 strcat(fn,"/"SAVE_CURRENT_USER);
510 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
511 strcpy(tmp,fn);strcat(tmp,".tmp");
512 if (_savereg(key_current_user,tmp,all)) {
513 if (-1==rename(tmp,fn)) {
514 perror("rename tmp registry");
520 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
521 strcpy(fn,pwd->pw_dir);
522 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
523 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
524 strcpy(tmp,fn);strcat(tmp,".tmp");
525 if (_savereg(key_local_machine,tmp,all)) {
526 if (-1==rename(tmp,fn)) {
527 perror("rename tmp registry");
534 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
537 /************************ LOAD Registry Function ****************************/
540 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
541 LPKEYSTRUCT lpxkey,*lplpkey;
543 lplpkey= &(lpkey->nextsub);
546 if (!lstrcmpi32W(lpxkey->keyname,keyname))
548 lplpkey = &(lpxkey->next);
552 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
554 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
555 lpxkey->keyname = keyname;
563 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
569 for (i=0;i<lpkey->nrofvalues;i++) {
575 if ( val->name!=NULL &&
576 !lstrcmpi32W(val->name,name)
581 if (i==lpkey->nrofvalues) {
582 lpkey->values = xrealloc(
584 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
587 memset(val,'\0',sizeof(KEYVALUE));
593 if (val->lastmodified<lastmodified) {
594 val->lastmodified=lastmodified;
605 /* reads a line including dynamically enlarging the readbuffer and throwing
609 _wine_read_line(FILE *F,char **buf,int *len) {
618 s=fgets(curread,mylen,F);
621 if (NULL==(s=strchr(curread,'\n'))) {
622 /* buffer wasn't large enough */
623 curoff = strlen(*buf);
624 *buf = xrealloc(*buf,*len*2);
625 curread = *buf + curoff;
626 mylen = *len; /* we filled up the buffer and
627 * got new '*len' bytes to fill
635 /* throw away comments */
636 if (**buf=='#' || **buf==';') {
641 if (s) /* got end of line */
647 /* converts a char* into a UNICODE string (up to a special char)
648 * and returns the position exactly after that string
651 _wine_read_USTRING(char *buf,LPWSTR *str) {
655 /* read up to "=" or "\0" or "\n" */
658 /* empty string is the win3.1 default value(NULL)*/
662 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
664 while (*s && (*s!='\n') && (*s!='=')) {
666 *ws++=*((unsigned char*)s++);
675 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
683 memcpy(xbuf,s,4);xbuf[4]='\0';
684 if (!sscanf(xbuf,"%x",&wc))
685 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
687 *ws++ =(unsigned short)wc;
693 *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 fprintf(stderr,"_load_subkey: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 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
746 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
747 fprintf(stderr,"_wine_load_subkey: 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')
768 if (*s>='A' && *s<='F')
771 if (*s>='0' && *s<='9')
773 if (*s>='a' && *s<='f')
775 if (*s>='A' && *s<='F')
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 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg: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 dprintf_reg(stddeb,__FILE__":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)malloc(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..1F: ? (someone fill in please)
887 * 4..0x1B: ? (fill in)
888 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
890 * Disk Key Entry Structure:
891 * 00: DWORD - unknown
892 * 04: DWORD - unknown
893 * 08: DWORD - unknown, but usually 0xFFFFFFFF on win95 systems
894 * 0C: DWORD - disk address of PreviousLevel Key.
895 * 10: DWORD - disk address of Next Sublevel Key.
896 * 14: DWORD - disk address of Next Key (on same level).
897 * DKEP>18: WORD - Nr, Low Significant part.
898 * 1A: WORD - Nr, High Significant part.
900 * The disk address always points to the nr part of the previous key entry
901 * of the referenced key. Don't ask me why, or even if I got this correct
902 * from staring at 1kg of hexdumps. (DKEP)
904 * The number of the entry is the low byte of the Low Significant Part ored
905 * with 0x100 * (low byte of the High Significant part)
906 * (C expression : nr = (nrLS & 0xFF) | ((nrHS &0xFF)<<8))
908 * There are two minor corrections to the position of that structure.
909 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
910 * the DKE reread from there.
911 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
912 * (FIXME: slightly better explanation needed here)
916 * 04: DWORD offset to next RGDB section (perhaps WORD)
921 * 00: DWORD nextkeyoffset - offset to the next disk key structure
922 * 08: WORD nrLS - low significant part of NR
923 * 0A: WORD nrHS - high significant part of NR
924 * 0C: DWORD bytesused - bytes used in this structure.
925 * 10: WORD name_len - length of name in bytes. without \0
926 * 12: WORD nr_of_values - number of values.
927 * 14: char name[name_len] - name string. No \0.
928 * 14+name_len: disk values
929 * nextkeyoffset: ... next disk key
932 * 00: DWORD type - value type (hmm, could be WORD too)
933 * 04: DWORD - unknown, usually 0
934 * 08: WORD namelen - length of Name. 0 means name=NULL
935 * 0C: WORD datalen - length of Data.
936 * 10: char name[namelen] - name, no \0
937 * 10+namelen: BYTE data[datalen] - data, without \0 if string
938 * 10+namelen+datalen: next values or disk key
940 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
941 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
942 * structure) and reading another RGDB_section.
943 * repeat until end of file.
945 * FIXME: this description needs some serious help, yes.
948 struct _w95keyvalue {
950 unsigned short datalen;
960 struct _w95keyvalue *values;
961 unsigned long dkeaddr;
966 struct _w95key *prevlvl;
967 struct _w95key *nextsub;
968 struct _w95key *next;
971 /* fast lookup table dkeaddr->nr */
973 unsigned long dkeaddr;
979 _w95_walk_tree(LPKEYSTRUCT lpkey,struct _w95key *key) {
985 if (key->name == NULL) {
986 fprintf(stderr,"_w95_walk_tree:Please report: key with dkeaddr %lx not loaded, skipping hierarchy\n",
991 lpxkey=_find_or_add_key(lpkey,strdupA2W(key->name));
993 if (key->nrofvals<0) {
994 /* shouldn't happen */
995 fprintf(stderr,"key %s already processed!\n",key->name);
999 for (i=0;i<key->nrofvals;i++) {
1003 name = strdupA2W(key->values[i].name);
1004 if (!*name) name = NULL;
1005 free(key->values[i].name);
1007 len = key->values[i].datalen;
1008 data = key->values[i].data;
1009 if ((1<<key->values[i].type) & UNICONVMASK) {
1010 data = (BYTE*)strdupA2W(data);
1011 len = lstrlen32W((LPWSTR)data)*2+2;
1012 free(key->values[i].data);
1017 key->values[i].type,
1020 key->values[i].lastmodified
1027 key->nrofvals=-key->nrofvals-1;
1028 _w95_walk_tree(lpxkey,key->nextsub);
1033 /* small helper function to adjust address offset (dkeaddrs) */
1034 static unsigned long
1035 _w95_adj_da(unsigned long dkeaddr) {
1036 if ((dkeaddr&0xFFF)<0x018) {
1039 diff=0x1C-(dkeaddr&0xFFF);
1040 return dkeaddr+diff;
1042 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1043 /* readjust to 0x000,
1044 * but ONLY if we are >0x1000 already
1046 if (dkeaddr & ~0xFFF)
1047 return dkeaddr & ~0xFFF;
1053 _w95dkecomp(struct _w95nr2da *a,struct _w95nr2da *b){return a->dkeaddr-b->dkeaddr;}
1055 static struct _w95key*
1056 _w95dkelookup(unsigned long dkeaddr,int n,struct _w95nr2da *nr2da,struct _w95key *keys) {
1059 if (dkeaddr == 0xFFFFFFFF)
1063 dkeaddr=_w95_adj_da(dkeaddr+0x1c);
1064 off = (dkeaddr-0x3c)/0x1c;
1066 if (nr2da[(i+off)%n].dkeaddr == dkeaddr)
1067 return keys+nr2da[(i+off)%n].nr;
1068 /* 0x3C happens often, just report unusual values */
1070 dprintf_reg(stddeb,"search hasn't found dkeaddr %lx?\n",dkeaddr);
1075 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1076 /* Disk Key Entry structure (RGKN part) */
1080 unsigned long x3;/*usually 0xFFFFFFFF */
1081 unsigned long prevlvl;
1082 unsigned long nextsub;
1084 unsigned short nrLS;
1085 unsigned short nrMS;
1087 /* Disk Key Header structure (RGDB part) */
1089 unsigned long nextkeyoff;
1090 unsigned short nrLS;
1091 unsigned short nrMS;
1092 unsigned long bytesused;
1093 unsigned short keynamelen;
1094 unsigned short values;
1097 /* disk key values or nothing */
1099 /* Disk Key Value structure */
1103 unsigned short valnamelen;
1104 unsigned short valdatalen;
1105 /* valname, valdata */
1107 struct _w95nr2da *nr2da;
1112 unsigned long nr,pos,i,where,version,rgdbsection,end,off_next_rgdb;
1113 struct _w95key *keys;
1115 unsigned char *data,*curdata,*nextrgdb;
1117 BY_HANDLE_FILE_INFORMATION hfdinfo;
1119 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1120 hfd=OpenFile32(fn,&ofs,OF_READ);
1121 if (hfd==HFILE_ERROR32)
1124 if (4!=_lread32(hfd,magic,4))
1126 if (strcmp(magic,"CREG")) {
1127 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1130 if (4!=_lread32(hfd,&version,4))
1132 if (4!=_lread32(hfd,&rgdbsection,4))
1134 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1136 if (4!=_lread32(hfd,magic,4))
1138 if (strcmp(magic,"RGKN")) {
1139 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1143 /* STEP 1: Keylink structures */
1144 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1149 nrofdkes = (end-where)/sizeof(struct dke)+100;
1150 data = (char*)xmalloc(end-where);
1151 if ((end-where)!=_lread32(hfd,data,end-where))
1155 keys = (struct _w95key*)xmalloc(nrofdkes * sizeof(struct _w95key));
1156 memset(keys,'\0',nrofdkes*sizeof(struct _w95key));
1157 nr2da= (struct _w95nr2da*)xmalloc(nrofdkes * sizeof(struct _w95nr2da));
1158 memset(nr2da,'\0',nrofdkes*sizeof(struct _w95nr2da));
1160 for (i=0;i<nrofdkes;i++) {
1162 unsigned long dkeaddr;
1164 pos=curdata-data+0x40;
1165 memcpy(&dke,curdata,sizeof(dke));
1166 curdata+=sizeof(dke);
1167 nr = dke.nrLS + (dke.nrMS<<8);
1169 if ((dkeaddr&0xFFF)<0x018) {
1172 diff=0x1C-(dkeaddr&0xFFF);
1174 curdata+=diff-sizeof(dke);
1175 memcpy(&dke,curdata,sizeof(dke));
1176 nr = dke.nrLS + (dke.nrMS<<8);
1177 curdata+=sizeof(dke);
1179 if (((dkeaddr+0x1C)&0xFFF)<0x1C) {
1180 /* readjust to 0x000,
1181 * but ONLY if we are >0x1000 already
1183 if (dkeaddr & ~0xFFF)
1184 dkeaddr = dkeaddr & ~0xFFF;
1187 /* 0xFFFFFFFF happens often, just report unusual values */
1189 dprintf_reg(stddeb,"nr %ld exceeds nrofdkes %d, skipping.\n",nr,nrofdkes);
1192 if (keys[nr].dkeaddr) {
1195 for (x=sizeof(dke);x--;)
1196 if (((char*)&dke)[x])
1199 break; /* finished reading if we got only 0 */
1201 if ( (dke.next!=(long)keys[nr].next) ||
1202 (dke.nextsub!=(long)keys[nr].nextsub) ||
1203 (dke.prevlvl!=(long)keys[nr].prevlvl)
1205 dprintf_reg(stddeb,"key doubled? nr=%ld,key->dkeaddr=%lx,dkeaddr=%lx\n",nr,keys[nr].dkeaddr,dkeaddr);
1210 nr2da[i].dkeaddr = dkeaddr;
1212 keys[nr].dkeaddr = dkeaddr;
1213 keys[nr].x1 = dke.x1;
1214 keys[nr].x2 = dke.x2;
1215 keys[nr].x3 = dke.x3;
1216 keys[nr].prevlvl= (struct _w95key*)dke.prevlvl;
1217 keys[nr].nextsub= (struct _w95key*)dke.nextsub;
1218 keys[nr].next = (struct _w95key*)dke.next;
1222 qsort(nr2da,nrofdkes,sizeof(nr2da[0]),
1223 (int(*)(const void *,const void*))_w95dkecomp);
1225 /* STEP 2: keydata & values */
1226 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1228 end = hfdinfo.nFileSizeLow;
1229 lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1231 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1233 data = (char*)xmalloc(end-rgdbsection);
1234 if ((end-rgdbsection)!=_lread32(hfd,data,end-rgdbsection))
1238 memcpy(magic,curdata,4);
1239 memcpy(&off_next_rgdb,curdata+4,4);
1240 nextrgdb = curdata+off_next_rgdb;
1241 if (strcmp(magic,"RGDB")) {
1242 dprintf_reg(stddeb,"third IFF header not RGDB, but %s\n",magic);
1249 struct _w95key *key,xkey;
1252 if (curdata>=nextrgdb) {
1254 if (!strncmp(curdata,"RGDB",4)) {
1255 memcpy(&off_next_rgdb,curdata+4,4);
1256 nextrgdb = curdata+off_next_rgdb;
1259 dprintf_reg(stddeb,"at end of RGDB section, but no next header (%x of %lx). Breaking.\n",curdata-data,end-rgdbsection);
1263 #define XREAD(whereto,len) \
1264 if ((curdata-data+len)<end) {\
1265 memcpy(whereto,curdata,len);\
1270 XREAD(&dkh,sizeof(dkh));
1271 nr = dkh.nrLS + (dkh.nrMS<<8);
1272 if ((nr>nrofdkes) || (dkh.nrLS == 0xFFFF)) {
1273 if (dkh.nrLS == 0xFFFF) {
1274 /* skip over key using nextkeyoff */
1275 curdata+=dkh.nextkeyoff-sizeof(struct dkh);
1278 dprintf_reg(stddeb,"haven't found nr %ld.\n",nr);
1280 memset(key,'\0',sizeof(xkey));
1284 dprintf_reg(stddeb,"key with nr=%ld has no dkeaddr?\n",nr);
1286 key->nrofvals = dkh.values;
1287 key->name = (char*)xmalloc(dkh.keynamelen+1);
1289 XREAD(key->name,dkh.keynamelen);
1290 key->name[dkh.keynamelen]=0;
1291 if (key->nrofvals) {
1292 key->values = (struct _w95keyvalue*)xmalloc(
1293 sizeof(struct _w95keyvalue)*key->nrofvals
1295 for (i=0;i<key->nrofvals;i++) {
1298 XREAD(&dkv,sizeof(dkv));
1299 key->values[i].type = dkv.type;
1300 key->values[i].name = (char*)xmalloc(
1303 key->values[i].datalen = dkv.valdatalen;
1304 key->values[i].data = (unsigned char*)xmalloc(
1307 key->values[i].x1 = dkv.x1;
1308 XREAD(key->values[i].name,dkv.valnamelen);
1309 XREAD(key->values[i].data,dkv.valdatalen);
1310 key->values[i].data[dkv.valdatalen]=0;
1311 key->values[i].name[dkv.valnamelen]=0;
1312 key->values[i].lastmodified=lastmodified;
1315 if (bytesread != dkh.nextkeyoff) {
1316 if (dkh.bytesused != bytesread)
1318 "read has difference in read bytes (%d) and nextoffset (%ld) (bytesused=%ld)\n",bytesread,dkh.nextkeyoff,
1321 curdata += dkh.nextkeyoff-bytesread;
1323 key->prevlvl = _w95dkelookup((long)key->prevlvl,nrofdkes,nr2da,keys);
1324 key->nextsub = _w95dkelookup((long)key->nextsub,nrofdkes,nr2da,keys);
1325 key->next = _w95dkelookup((long)key->next,nrofdkes,nr2da,keys);
1330 _w95_walk_tree(lpkey,keys);
1334 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1337 reghack - windows 3.11 registry data format demo program.
1339 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1340 a combined hash table and tree description, and finally a text table.
1342 The header is obvious from the struct header. The taboff1 and taboff2
1343 fields are always 0x20, and their usage is unknown.
1345 The 8-byte entry table has various entry types.
1347 tabent[0] is a root index. The second word has the index of the root of
1349 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1350 the index of the key/value that has that hash. Data with the same
1351 hash value are on a circular list. The other three words in the
1352 hash entry are always zero.
1353 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1354 entry: dirent and keyent/valent. They are identified by context.
1355 tabent[freeidx] is the first free entry. The first word in a free entry
1356 is the index of the next free entry. The last has 0 as a link.
1357 The other three words in the free list are probably irrelevant.
1359 Entries in text table are preceeded by a word at offset-2. This word
1360 has the value (2*index)+1, where index is the referring keyent/valent
1361 entry in the table. I have no suggestion for the 2* and the +1.
1362 Following the word, there are N bytes of data, as per the keyent/valent
1363 entry length. The offset of the keyent/valent entry is from the start
1364 of the text table to the first data byte.
1366 This information is not available from Microsoft. The data format is
1367 deduced from the reg.dat file by me. Mistakes may
1368 have been made. I claim no rights and give no guarantees for this program.
1370 Tor Sjøwall, tor@sn.no
1373 /* reg.dat header format */
1374 struct _w31_header {
1375 char cookie[8]; /* 'SHCC3.10' */
1376 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1377 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1378 unsigned long tabcnt; /* number of entries in index table */
1379 unsigned long textoff; /* offset of text part */
1380 unsigned long textsize; /* byte size of text part */
1381 unsigned short hashsize; /* hash size */
1382 unsigned short freeidx; /* free index */
1385 /* generic format of table entries */
1386 struct _w31_tabent {
1387 unsigned short w0, w1, w2, w3;
1390 /* directory tabent: */
1391 struct _w31_dirent {
1392 unsigned short sibling_idx; /* table index of sibling dirent */
1393 unsigned short child_idx; /* table index of child dirent */
1394 unsigned short key_idx; /* table index of key keyent */
1395 unsigned short value_idx; /* table index of value valent */
1399 struct _w31_keyent {
1400 unsigned short hash_idx; /* hash chain index for string */
1401 unsigned short refcnt; /* reference count */
1402 unsigned short length; /* length of string */
1403 unsigned short string_off; /* offset of string in text table */
1407 struct _w31_valent {
1408 unsigned short hash_idx; /* hash chain index for string */
1409 unsigned short refcnt; /* reference count */
1410 unsigned short length; /* length of string */
1411 unsigned short string_off; /* offset of string in text table */
1414 /* recursive helper function to display a directory tree */
1416 __w31_dumptree( unsigned short idx,
1418 struct _w31_tabent *tab,
1419 struct _w31_header *head,
1421 time_t lastmodified,
1424 struct _w31_dirent *dir;
1425 struct _w31_keyent *key;
1426 struct _w31_valent *val;
1427 LPKEYSTRUCT xlpkey = NULL;
1429 static char tail[400];
1432 dir=(struct _w31_dirent*)&tab[idx];
1435 key = (struct _w31_keyent*)&tab[dir->key_idx];
1437 memcpy(tail,&txt[key->string_off],key->length);
1438 tail[key->length]='\0';
1439 /* all toplevel entries AND the entries in the
1440 * toplevel subdirectory belong to \SOFTWARE\Classes
1442 if (!level && !lstrcmp32A(tail,".classes")) {
1443 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1444 idx=dir->sibling_idx;
1447 name=STRING32_DupAnsiToUni(tail);
1449 xlpkey=_find_or_add_key(lpkey,name);
1451 /* only add if leaf node or valued node */
1452 if (dir->value_idx!=0||dir->child_idx==0) {
1453 if (dir->value_idx) {
1454 val=(struct _w31_valent*)&tab[dir->value_idx];
1455 memcpy(tail,&txt[val->string_off],val->length);
1456 tail[val->length]='\0';
1457 value=STRING32_DupAnsiToUni(tail);
1458 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1462 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1464 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1465 idx=dir->sibling_idx;
1472 struct _w31_header head;
1473 struct _w31_tabent *tab;
1477 BY_HANDLE_FILE_INFORMATION hfinfo;
1478 time_t lastmodified;
1482 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1483 if (hf==HFILE_ERROR32)
1486 /* read & dump header */
1487 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1488 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1492 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1493 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1498 len = head.tabcnt * sizeof(struct _w31_tabent);
1499 /* read and dump index table */
1501 if (len!=_lread32(hf,tab,len)) {
1502 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1509 txt = xmalloc(head.textsize);
1510 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1511 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1517 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1518 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1525 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1526 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1532 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1534 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1536 lpkey = lookup_hkey(hkey);
1537 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1545 SHELL_LoadRegistry() {
1552 if (key_classes_root==NULL)
1555 /* Load windows 3.1 entries */
1557 /* Load windows 95 entries */
1558 _w95_loadreg("C:\\system.1st", key_local_machine);
1559 _w95_loadreg("system.dat", key_local_machine);
1560 _w95_loadreg("user.dat", key_users);
1562 /* the global user default is loaded under HKEY_USERS\\.Default */
1563 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1564 lpkey = lookup_hkey(hkey);
1565 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1567 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1568 _copy_registry(lpkey,key_current_user);
1571 /* the global machine defaults */
1572 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1574 /* load the user saved registries */
1576 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1578 pwd=getpwuid(getuid());
1579 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1580 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1581 strcpy(fn,pwd->pw_dir);
1582 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1583 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1585 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1586 strcpy(fn,pwd->pw_dir);
1587 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1588 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1591 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1592 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1593 DWORD junk,type,len;
1597 if (( RegQueryValueEx32A(
1604 )!=ERROR_SUCCESS) ||
1607 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1613 /********************* API FUNCTIONS ***************************************/
1617 * All functions are stubs to RegOpenKeyEx32W where all the
1620 * FIXME: security,options,desiredaccess,...
1623 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1624 * RegOpenKey32W -> RegOpenKeyEx32W
1627 /* RegOpenKeyExW [ADVAPI32.150] */
1628 DWORD WINAPI RegOpenKeyEx32W(
1635 LPKEYSTRUCT lpNextKey,lpxkey;
1638 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1639 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1642 lpNextKey = lookup_hkey(hkey);
1644 return SHELL_ERROR_BADKEY;
1645 if (!lpszSubKey || !*lpszSubKey) {
1646 add_handle(++currenthandle,lpNextKey,samDesired);
1647 *retkey=currenthandle;
1648 return SHELL_ERROR_SUCCESS;
1650 split_keypath(lpszSubKey,&wps,&wpc);
1652 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1655 lpxkey=lpNextKey->nextsub;
1657 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1659 lpxkey=lpxkey->next;
1663 return SHELL_ERROR_BADKEY;
1668 add_handle(++currenthandle,lpxkey,samDesired);
1669 *retkey = currenthandle;
1671 return SHELL_ERROR_SUCCESS;
1674 /* RegOpenKeyW [ADVAPI32.151] */
1675 DWORD WINAPI RegOpenKey32W(
1680 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1681 (LONG)hkey,W2C(lpszSubKey,0),retkey
1683 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1687 /* RegOpenKeyExA [ADVAPI32.149] */
1688 DWORD WINAPI RegOpenKeyEx32A(
1698 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1699 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1702 lpszSubKeyW=strdupA2W(lpszSubKey);
1705 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1711 /* RegOpenKeyA [ADVAPI32.148] */
1712 DWORD WINAPI RegOpenKey32A(
1717 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1718 (LONG)hkey,lpszSubKey,retkey
1720 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1723 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1724 DWORD WINAPI RegOpenKey16(
1729 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1730 (LONG)hkey,lpszSubKey,retkey
1732 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1738 * All those functions convert their respective
1739 * arguments and call RegCreateKeyExW at the end.
1741 * FIXME: no security,no access attrib,no optionhandling yet.
1744 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1745 * RegCreateKey32W -> RegCreateKeyEx32W
1748 /* RegCreateKeyExW [ADVAPI32.131] */
1749 DWORD WINAPI RegCreateKeyEx32W(
1756 LPSECURITY_ATTRIBUTES lpSecAttribs,
1760 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1764 /*FIXME: handle security/access/whatever */
1765 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1777 lpNextKey = lookup_hkey(hkey);
1779 return SHELL_ERROR_BADKEY;
1780 if (!lpszSubKey || !*lpszSubKey) {
1781 add_handle(++currenthandle,lpNextKey,samDesired);
1782 *retkey=currenthandle;
1783 lpNextKey->flags|=REG_OPTION_TAINTED;
1784 return SHELL_ERROR_SUCCESS;
1786 split_keypath(lpszSubKey,&wps,&wpc);
1788 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1791 lpxkey=lpNextKey->nextsub;
1793 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1795 lpxkey=lpxkey->next;
1803 add_handle(++currenthandle,lpxkey,samDesired);
1804 lpxkey->flags |= REG_OPTION_TAINTED;
1805 *retkey = currenthandle;
1807 *lpDispos = REG_OPENED_EXISTING_KEY;
1809 return SHELL_ERROR_SUCCESS;
1811 /* good. now the hard part */
1813 lplpPrevKey = &(lpNextKey->nextsub);
1814 lpxkey = *lplpPrevKey;
1816 lplpPrevKey = &(lpxkey->next);
1817 lpxkey = *lplpPrevKey;
1819 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1820 if (!*lplpPrevKey) {
1822 return SHELL_ERROR_OUTOFMEMORY;
1824 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1825 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1826 (*lplpPrevKey)->next = NULL;
1827 (*lplpPrevKey)->nextsub = NULL;
1828 (*lplpPrevKey)->values = NULL;
1829 (*lplpPrevKey)->nrofvalues = 0;
1830 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1832 (*lplpPrevKey)->class = strdupW(lpszClass);
1834 (*lplpPrevKey)->class = NULL;
1835 lpNextKey = *lplpPrevKey;
1838 add_handle(++currenthandle,lpNextKey,samDesired);
1840 /*FIXME: flag handling correct? */
1841 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1843 lpNextKey->class = strdupW(lpszClass);
1845 lpNextKey->class = NULL;
1846 *retkey = currenthandle;
1848 *lpDispos = REG_CREATED_NEW_KEY;
1850 return SHELL_ERROR_SUCCESS;
1853 /* RegCreateKeyW [ADVAPI32.132] */
1854 DWORD WINAPI RegCreateKey32W(
1861 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1862 (LONG)hkey,W2C(lpszSubKey,0),retkey
1864 ret=RegCreateKeyEx32W(
1865 hkey, /* key handle */
1866 lpszSubKey, /* subkey name */
1867 0, /* reserved = 0 */
1868 NULL, /* lpszClass? FIXME: ? */
1869 REG_OPTION_NON_VOLATILE, /* options */
1870 KEY_ALL_ACCESS, /* desired access attribs */
1871 NULL, /* lpsecurity attributes */
1872 retkey, /* lpretkey */
1873 &junk /* disposition value */
1878 /* RegCreateKeyExA [ADVAPI32.130] */
1879 DWORD WINAPI RegCreateKeyEx32A(
1886 LPSECURITY_ATTRIBUTES lpSecAttribs,
1890 LPWSTR lpszSubKeyW,lpszClassW;
1893 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1905 lpszSubKeyW=strdupA2W(lpszSubKey);
1909 lpszClassW=strdupA2W(lpszClass);
1912 ret=RegCreateKeyEx32W(
1930 /* RegCreateKeyA [ADVAPI32.129] */
1931 DWORD WINAPI RegCreateKey32A(
1938 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1939 (LONG)hkey,lpszSubKey,retkey
1941 return RegCreateKeyEx32A(
1942 hkey, /* key handle */
1943 lpszSubKey, /* subkey name */
1944 0, /* reserved = 0 */
1945 NULL, /* lpszClass? FIXME: ? */
1946 REG_OPTION_NON_VOLATILE,/* options */
1947 KEY_ALL_ACCESS, /* desired access attribs */
1948 NULL, /* lpsecurity attributes */
1949 retkey, /* lpretkey */
1950 &junk /* disposition value */
1954 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1955 DWORD WINAPI RegCreateKey16(
1960 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1961 (LONG)hkey,lpszSubKey,retkey
1963 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1967 * Query Value Functions
1968 * Win32 differs between keynames and valuenames.
1969 * multiple values may belong to one key, the special value
1970 * with name NULL is the default value used by the win31
1974 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1975 * RegQueryValue32W -> RegQueryValueEx32W
1978 /* RegQueryValueExW [ADVAPI32.158] */
1979 DWORD WINAPI RegQueryValueEx32W(
1981 LPWSTR lpszValueName,
1982 LPDWORD lpdwReserved,
1990 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1991 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1992 lpcbData?*lpcbData:0
1995 lpkey = lookup_hkey(hkey);
1997 return SHELL_ERROR_BADKEY;
1998 if (lpszValueName==NULL) {
1999 for (i=0;i<lpkey->nrofvalues;i++)
2000 if (lpkey->values[i].name==NULL)
2003 for (i=0;i<lpkey->nrofvalues;i++)
2004 if ( lpkey->values[i].name &&
2005 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2009 if (i==lpkey->nrofvalues) {
2010 if (lpszValueName==NULL) {
2012 *(WCHAR*)lpbData = 0;
2017 return SHELL_ERROR_SUCCESS;
2019 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
2022 *lpdwType = lpkey->values[i].type;
2023 if (lpbData==NULL) {
2025 return SHELL_ERROR_SUCCESS;
2026 *lpcbData = lpkey->values[i].len;
2027 return SHELL_ERROR_SUCCESS;
2029 if (*lpcbData<lpkey->values[i].len) {
2032 *lpcbData = lpkey->values[i].len;
2033 return ERROR_MORE_DATA;
2035 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2036 *lpcbData = lpkey->values[i].len;
2037 return SHELL_ERROR_SUCCESS;
2040 /* RegQueryValueW [ADVAPI32.159] */
2041 DWORD WINAPI RegQueryValue32W(
2050 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
2051 hkey,W2C(lpszSubKey,0),lpszData,
2052 lpcbData?*lpcbData:0
2055 /* only open subkey, if we really do descend */
2056 if (lpszSubKey && *lpszSubKey) {
2057 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
2058 if (ret!=ERROR_SUCCESS)
2064 ret = RegQueryValueEx32W(
2066 NULL, /* varname NULL -> compat */
2067 NULL, /* lpdwReserved, must be NULL */
2077 /* RegQueryValueExA [ADVAPI32.157] */
2078 DWORD WINAPI RegQueryValueEx32A(
2080 LPSTR lpszValueName,
2081 LPDWORD lpdwReserved,
2086 LPWSTR lpszValueNameW;
2092 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2093 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2094 lpcbData?*lpcbData:0
2097 lpszValueNameW=strdupA2W(lpszValueName);
2099 lpszValueNameW=NULL;
2108 ret=RegQueryValueEx32W(
2117 if (ret==ERROR_MORE_DATA) {
2118 buf = (LPBYTE)xmalloc(*mylen);
2120 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2121 myxlen = 2*(*lpcbData);
2126 myxlen = *lpcbData*2;
2131 ret=RegQueryValueEx32W(
2141 if (ret==ERROR_SUCCESS) {
2143 if (UNICONVMASK & (1<<(type))) {
2144 /* convert UNICODE to ASCII */
2145 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2146 *lpcbData = myxlen/2;
2148 if (myxlen>*lpcbData)
2149 ret = ERROR_MORE_DATA;
2151 memcpy(lpbData,buf,myxlen);
2156 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2157 *lpcbData = myxlen/2;
2160 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2161 *lpcbData = myxlen/2;
2168 /* RegQueryValueEx [KERNEL.225] */
2169 DWORD WINAPI RegQueryValueEx16(
2171 LPSTR lpszValueName,
2172 LPDWORD lpdwReserved,
2177 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2178 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2179 lpcbData?*lpcbData:0
2181 return RegQueryValueEx32A(
2191 /* RegQueryValueA [ADVAPI32.156] */
2192 DWORD WINAPI RegQueryValue32A(
2201 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2202 hkey,lpszSubKey,lpszData,
2203 lpcbData?*lpcbData:0
2206 /* only open subkey, if we really do descend */
2207 if (lpszSubKey && *lpszSubKey) {
2208 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2209 if (ret!=ERROR_SUCCESS)
2215 ret = RegQueryValueEx32A(
2217 NULL, /* lpszValueName NULL -> compat */
2218 NULL, /* lpdwReserved, must be NULL */
2228 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2229 DWORD WINAPI RegQueryValue16(
2235 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2236 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2238 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2239 * anyway, so we just mask out the high 16 bit.
2240 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2243 *lpcbData &= 0xFFFF;
2244 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2248 * Setting values of Registry keys
2251 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2252 * RegSetValue32W -> RegSetValueEx32W
2255 /* RegSetValueExW [ADVAPI32.170] */
2256 DWORD WINAPI RegSetValueEx32W(
2258 LPWSTR lpszValueName,
2267 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2268 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2270 /* we no longer care about the lpbData type here... */
2271 lpkey = lookup_hkey(hkey);
2273 return SHELL_ERROR_BADKEY;
2275 lpkey->flags |= REG_OPTION_TAINTED;
2277 if (lpszValueName==NULL) {
2278 for (i=0;i<lpkey->nrofvalues;i++)
2279 if (lpkey->values[i].name==NULL)
2282 for (i=0;i<lpkey->nrofvalues;i++)
2283 if ( lpkey->values[i].name &&
2284 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2288 if (i==lpkey->nrofvalues) {
2289 lpkey->values = (LPKEYVALUE)xrealloc(
2291 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2293 lpkey->nrofvalues++;
2294 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2296 if (lpkey->values[i].name==NULL)
2298 lpkey->values[i].name = strdupW(lpszValueName);
2300 lpkey->values[i].name = NULL;
2301 lpkey->values[i].len = cbData;
2302 lpkey->values[i].type = dwType;
2303 if (lpkey->values[i].data !=NULL)
2304 free(lpkey->values[i].data);
2305 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2306 lpkey->values[i].lastmodified = time(NULL);
2307 memcpy(lpkey->values[i].data,lpbData,cbData);
2308 return SHELL_ERROR_SUCCESS;
2311 /* RegSetValueExA [ADVAPI32.169] */
2312 DWORD WINAPI RegSetValueEx32A(
2314 LPSTR lpszValueName,
2321 LPWSTR lpszValueNameW;
2324 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2325 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2327 if ((1<<dwType) & UNICONVMASK) {
2328 buf=(LPBYTE)strdupA2W(lpbData);
2329 cbData=2*strlen(lpbData)+2;
2333 lpszValueNameW = strdupA2W(lpszValueName);
2335 lpszValueNameW = NULL;
2336 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2338 free(lpszValueNameW);
2344 /* RegSetValueEx [KERNEL.226] */
2345 DWORD WINAPI RegSetValueEx16(
2347 LPSTR lpszValueName,
2353 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2354 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2356 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2359 /* RegSetValueW [ADVAPI32.171] */
2360 DWORD WINAPI RegSetValue32W(
2370 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2371 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2373 if (lpszSubKey && *lpszSubKey) {
2374 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2375 if (ret!=ERROR_SUCCESS)
2379 if (dwType!=REG_SZ) {
2380 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2383 if (cbData!=2*lstrlen32W(lpszData)+2) {
2384 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2385 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2387 cbData=2*lstrlen32W(lpszData)+2;
2389 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2395 /* RegSetValueA [ADVAPI32.168] */
2396 DWORD WINAPI RegSetValue32A(
2406 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2407 hkey,lpszSubKey,dwType,lpszData,cbData
2409 if (lpszSubKey && *lpszSubKey) {
2410 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2411 if (ret!=ERROR_SUCCESS)
2416 if (dwType!=REG_SZ) {
2417 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2420 if (cbData!=strlen(lpszData)+1)
2421 cbData=strlen(lpszData)+1;
2422 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2428 /* RegSetValue [KERNEL.221] [SHELL.5] */
2429 DWORD WINAPI RegSetValue16(
2437 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2438 hkey,lpszSubKey,dwType,lpszData,cbData
2440 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2448 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2449 * RegEnumKey32W -> RegEnumKeyEx32W
2452 /* RegEnumKeyExW [ADVAPI32.139] */
2453 DWORD WINAPI RegEnumKeyEx32W(
2458 LPDWORD lpdwReserved,
2463 LPKEYSTRUCT lpkey,lpxkey;
2465 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2466 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2468 lpkey=lookup_hkey(hkey);
2470 return SHELL_ERROR_BADKEY;
2471 if (!lpkey->nextsub)
2472 return ERROR_NO_MORE_ITEMS;
2473 lpxkey=lpkey->nextsub;
2474 while (iSubkey && lpxkey) {
2476 lpxkey=lpxkey->next;
2478 if (iSubkey || !lpxkey)
2479 return ERROR_NO_MORE_ITEMS;
2480 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2481 return ERROR_MORE_DATA;
2482 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2484 /* what should we write into it? */
2488 return ERROR_SUCCESS;
2492 /* RegEnumKeyW [ADVAPI32.140] */
2493 DWORD WINAPI RegEnumKey32W(
2501 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2502 hkey,iSubkey,lpszName,lpcchName
2504 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2506 /* RegEnumKeyExA [ADVAPI32.138] */
2507 DWORD WINAPI RegEnumKeyEx32A(
2512 LPDWORD lpdwReserved,
2517 DWORD ret,lpcchNameW,lpcchClassW;
2518 LPWSTR lpszNameW,lpszClassW;
2521 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2522 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2525 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2526 lpcchNameW = *lpcchName*2;
2532 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2533 lpcchClassW = *lpcchClass*2;
2538 ret=RegEnumKeyEx32W(
2548 if (ret==ERROR_SUCCESS) {
2549 lstrcpyWtoA(lpszName,lpszNameW);
2550 *lpcchName=strlen(lpszName);
2552 lstrcpyWtoA(lpszClass,lpszClassW);
2553 *lpcchClass=strlen(lpszClass);
2563 /* RegEnumKeyA [ADVAPI32.137] */
2564 DWORD WINAPI RegEnumKey32A(
2572 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2573 hkey,iSubkey,lpszName,lpcchName
2575 return RegEnumKeyEx32A(
2587 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2588 DWORD WINAPI RegEnumKey16(
2594 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2595 hkey,iSubkey,lpszName,lpcchName
2597 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2601 * Enumerate Registry Values
2604 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2607 /* RegEnumValueW [ADVAPI32.142] */
2608 DWORD WINAPI RegEnumValue32W(
2613 LPDWORD lpdReserved,
2621 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2622 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2624 lpkey = lookup_hkey(hkey);
2626 return SHELL_ERROR_BADKEY;
2627 if (lpkey->nrofvalues<=iValue)
2628 return ERROR_NO_MORE_ITEMS;
2629 val = lpkey->values+iValue;
2632 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2633 *lpcchValue = lstrlen32W(val->name)*2+2;
2634 return ERROR_MORE_DATA;
2636 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2637 *lpcchValue=lstrlen32W(val->name)*2+2;
2639 /* how to handle NULL value? */
2643 *lpdwType=val->type;
2645 if (val->len>*lpcbData)
2646 return ERROR_MORE_DATA;
2647 memcpy(lpbData,val->data,val->len);
2648 *lpcbData = val->len;
2650 return SHELL_ERROR_SUCCESS;
2653 /* RegEnumValueA [ADVAPI32.141] */
2654 DWORD WINAPI RegEnumValue32A(
2659 LPDWORD lpdReserved,
2666 DWORD ret,lpcbDataW;
2668 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2669 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2672 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2674 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2675 lpcbDataW = *lpcbData*2;
2678 ret=RegEnumValue32W(
2689 if (ret==ERROR_SUCCESS) {
2690 lstrcpyWtoA(lpszValue,lpszValueW);
2692 if ((1<<*lpdwType) & UNICONVMASK) {
2693 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2695 if (lpcbDataW > *lpcbData)
2696 ret = ERROR_MORE_DATA;
2698 memcpy(lpbData,lpbDataW,lpcbDataW);
2700 *lpcbData = lpcbDataW;
2710 /* RegEnumValue [KERNEL.223] */
2711 DWORD WINAPI RegEnumValue16(
2716 LPDWORD lpdReserved,
2721 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2722 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2724 return RegEnumValue32A(
2737 * Close registry key
2739 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2740 DWORD WINAPI RegCloseKey(HKEY hkey) {
2741 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2742 remove_handle(hkey);
2743 return ERROR_SUCCESS;
2746 * Delete registry key
2749 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2751 /* RegDeleteKeyW [ADVAPI32.134] */
2752 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2753 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2757 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2758 hkey,W2C(lpszSubKey,0)
2760 lpNextKey = lookup_hkey(hkey);
2762 return SHELL_ERROR_BADKEY;
2763 /* we need to know the previous key in the hier. */
2764 if (!lpszSubKey || !*lpszSubKey)
2765 return SHELL_ERROR_BADKEY;
2766 split_keypath(lpszSubKey,&wps,&wpc);
2770 lpxkey=lpNextKey->nextsub;
2772 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2774 lpxkey=lpxkey->next;
2778 /* not found is success */
2779 return SHELL_ERROR_SUCCESS;
2784 lpxkey = lpNextKey->nextsub;
2785 lplpPrevKey = &(lpNextKey->nextsub);
2787 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2789 lplpPrevKey = &(lpxkey->next);
2790 lpxkey = lpxkey->next;
2793 return SHELL_ERROR_SUCCESS;
2794 if (lpxkey->nextsub)
2795 return SHELL_ERROR_CANTWRITE;
2796 *lplpPrevKey = lpxkey->next;
2797 free(lpxkey->keyname);
2799 free(lpxkey->class);
2801 free(lpxkey->values);
2804 return SHELL_ERROR_SUCCESS;
2807 /* RegDeleteKeyA [ADVAPI32.133] */
2808 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2812 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2815 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2816 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2817 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2821 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2822 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2823 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2826 return RegDeleteKey32A(hkey,lpszSubKey);
2830 * Delete registry value
2833 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2835 /* RegDeleteValueW [ADVAPI32.136] */
2836 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2842 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2843 hkey,W2C(lpszValue,0)
2845 lpkey=lookup_hkey(hkey);
2847 return SHELL_ERROR_BADKEY;
2849 for (i=0;i<lpkey->nrofvalues;i++)
2850 if ( lpkey->values[i].name &&
2851 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2855 for (i=0;i<lpkey->nrofvalues;i++)
2856 if (lpkey->values[i].name==NULL)
2859 if (i==lpkey->nrofvalues)
2860 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2861 val = lpkey->values+i;
2862 if (val->name) free(val->name);
2863 if (val->data) free(val->data);
2867 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2869 lpkey->values = (LPKEYVALUE)xrealloc(
2871 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2873 lpkey->nrofvalues--;
2874 return SHELL_ERROR_SUCCESS;
2877 /* RegDeleteValueA [ADVAPI32.135] */
2878 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2883 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2884 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2885 ret=RegDeleteValue32W(hkey,lpszValueW);
2886 HeapFree(GetProcessHeap(),0,lpszValueW);
2890 /* RegDeleteValue [KERNEL.222] */
2891 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2893 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2894 return RegDeleteValue32A(hkey,lpszValue);
2897 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2898 DWORD WINAPI RegFlushKey(HKEY hkey)
2900 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2901 return SHELL_ERROR_SUCCESS;
2904 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2906 /* RegQueryInfoKeyW [ADVAPI32.153] */
2907 DWORD WINAPI RegQueryInfoKey32W(
2911 LPDWORD lpdwReserved,
2913 LPDWORD lpcchMaxSubkey,
2914 LPDWORD lpcchMaxClass,
2916 LPDWORD lpcchMaxValueName,
2917 LPDWORD lpccbMaxValueData,
2918 LPDWORD lpcbSecurityDescriptor,
2921 LPKEYSTRUCT lpkey,lpxkey;
2922 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2925 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2926 lpkey=lookup_hkey(hkey);
2928 return SHELL_ERROR_BADKEY;
2931 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2932 *lpcchClass=lstrlen32W(lpkey->class)*2;
2933 return ERROR_MORE_DATA;
2935 *lpcchClass=lstrlen32W(lpkey->class)*2;
2936 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2943 *lpcchClass = lstrlen32W(lpkey->class)*2;
2945 lpxkey=lpkey->nextsub;
2946 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2949 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2950 maxsubkey=lstrlen32W(lpxkey->keyname);
2951 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2952 maxclass=lstrlen32W(lpxkey->class);
2953 if (lpxkey->nrofvalues>maxvalues)
2954 maxvalues=lpxkey->nrofvalues;
2955 for (i=0;i<lpxkey->nrofvalues;i++) {
2956 LPKEYVALUE val=lpxkey->values+i;
2958 if (val->name && lstrlen32W(val->name)>maxvname)
2959 maxvname=lstrlen32W(val->name);
2960 if (val->len>maxvdata)
2963 lpxkey=lpxkey->next;
2965 if (!maxclass) maxclass = 1;
2966 if (!maxvname) maxvname = 1;
2968 *lpcSubKeys = nrofkeys;
2970 *lpcchMaxSubkey = maxsubkey*2;
2972 *lpcchMaxClass = maxclass*2;
2974 *lpcValues = maxvalues;
2975 if (lpcchMaxValueName)
2976 *lpcchMaxValueName= maxvname;
2977 if (lpccbMaxValueData)
2978 *lpccbMaxValueData= maxvdata;
2979 return SHELL_ERROR_SUCCESS;
2982 /* RegQueryInfoKeyA [ADVAPI32.152] */
2983 DWORD WINAPI RegQueryInfoKey32A(
2987 LPDWORD lpdwReserved,
2989 LPDWORD lpcchMaxSubkey,
2990 LPDWORD lpcchMaxClass,
2992 LPDWORD lpcchMaxValueName,
2993 LPDWORD lpccbMaxValueData,
2994 LPDWORD lpcbSecurityDescriptor,
3000 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
3003 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
3007 ret=RegQueryInfoKey32W(
3018 lpcbSecurityDescriptor,
3021 if (ret==ERROR_SUCCESS && lpszClass)
3022 lstrcpyWtoA(lpszClass,lpszClassW);
3029 if (lpcchMaxValueName)
3030 *lpcchMaxValueName/=2;
3035 /* RegConnectRegistryA [ADVAPI32.127] */
3036 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
3038 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
3041 return ERROR_FILE_NOT_FOUND; /* FIXME */