4 * Copyright 1996 Marcus Meissner
6 * December 21, 1997 - Kevin Cozens
7 * Fixed bugs in the _w95_loadreg() function. Added extra information
8 * regarding the format of the Windows '95 registry files.
17 #include <sys/types.h>
18 #include <sys/fcntl.h>
32 #define DEBUG_W95_LOADREG 0
34 /* FIXME: following defines should be configured global ... */
36 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
37 #define WINE_PREFIX "/.wine"
38 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
39 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
41 /* relative in ~user/.wine/ : */
42 #define SAVE_CURRENT_USER "user.reg"
43 #define SAVE_LOCAL_MACHINE "system.reg"
45 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
46 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
48 /* one value of a key */
49 typedef struct tagKEYVALUE
51 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
52 DWORD type; /* type of value */
53 DWORD len; /* length of data */
54 DWORD lastmodified; /* time of seconds since 1.1.1970 */
55 LPBYTE data; /* content, may be strings, binaries, etc. */
56 } KEYVALUE,*LPKEYVALUE;
59 typedef struct tagKEYSTRUCT
61 LPWSTR keyname; /* name of THIS key (UNICODE) */
62 DWORD flags; /* flags. */
65 DWORD nrofvalues; /* nr of values in THIS key */
66 LPKEYVALUE values; /* values in THIS key */
67 /* key management pointers */
68 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
69 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
70 } KEYSTRUCT, *LPKEYSTRUCT;
73 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
74 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
75 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
76 static KEYSTRUCT *key_users=NULL; /* all users? */
78 /* dynamic, not saved */
79 static KEYSTRUCT *key_performance_data=NULL;
80 static KEYSTRUCT *key_current_config=NULL;
81 static KEYSTRUCT *key_dyn_data=NULL;
83 /* what valuetypes do we need to convert? */
84 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
86 extern LPWSTR __cdecl CRTDLL_wcschr(LPWSTR a,WCHAR c);
88 static LPWSTR strdupA2W(LPCSTR src)
90 LPWSTR dest=xmalloc(2*strlen(src)+2);
91 lstrcpyAtoW(dest,src);
95 static LPWSTR strdupW(LPCWSTR a) {
99 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
100 b=(LPWSTR)xmalloc(len);
106 static struct openhandle {
111 static int nrofopenhandles=0;
112 static int currenthandle=1;
115 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
118 for (i=0;i<nrofopenhandles;i++) {
119 if (openhandles[i].lpkey==lpkey) {
120 dprintf_warn(reg, "add_handle:Tried to add %p twice!\n",lpkey);
122 if (openhandles[i].hkey==hkey) {
123 dprintf_warn(reg, "add_handle:Tried to add %lx twice!\n",(LONG)hkey);
126 openhandles=xrealloc( openhandles,
127 sizeof(struct openhandle)*(nrofopenhandles+1)
129 openhandles[i].lpkey = lpkey;
130 openhandles[i].hkey = hkey;
131 openhandles[i].accessmask= accessmask;
136 get_handle(HKEY hkey) {
139 for (i=0;i<nrofopenhandles;i++)
140 if (openhandles[i].hkey==hkey)
141 return openhandles[i].lpkey;
142 dprintf_warn(reg, "get_handle:Didn't find handle %lx?\n",(LONG)hkey);
147 remove_handle(HKEY hkey) {
150 for (i=0;i<nrofopenhandles;i++)
151 if (openhandles[i].hkey==hkey)
153 if (i==nrofopenhandles) {
154 dprintf_warn(reg, "remove_handle:Didn't find handle %08x?\n",hkey);
157 memcpy( openhandles+i,
159 sizeof(struct openhandle)*(nrofopenhandles-i-1)
161 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
167 /* debug function, converts a unicode into a static memory area
168 * (sub for using two static strings, in case we need them in a single call)
171 W2C(LPCWSTR x,int sub) {
172 static LPSTR unicodedebug[2]={NULL,NULL};
175 if (sub!=0 && sub!=1)
176 return "<W2C:bad sub>";
177 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
178 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
179 return unicodedebug[sub];
183 lookup_hkey(HKEY hkey) {
187 case HKEY_CLASSES_ROOT:
188 return key_classes_root;
189 case HKEY_CURRENT_USER:
190 return key_current_user;
191 case HKEY_LOCAL_MACHINE:
192 return key_local_machine;
195 case HKEY_PERFORMANCE_DATA:
196 return key_performance_data;
199 case HKEY_CURRENT_CONFIG:
200 return key_current_config;
202 dprintf_warn(reg, "lookup_hkey(%lx), special key!\n",
205 return get_handle(hkey);
211 * splits the unicode string 'wp' into an array of strings.
212 * the array is allocated by this function.
213 * the number of components will be stored in 'wpc'
214 * Free the array using FREE_KEY_PATH
217 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
221 ws = HEAP_strdupW( SystemHeap, 0, wp );
223 for (i=0;ws[i];i++) {
230 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
238 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
241 * Shell initialisation, allocates keys.
243 void SHELL_StartupRegistry();
248 HKEY cl_r_hkey,c_u_hkey;
249 #define ADD_ROOT_KEY(xx) \
250 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
251 memset(xx,'\0',sizeof(KEYSTRUCT));\
252 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
254 ADD_ROOT_KEY(key_local_machine);
255 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
256 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
259 key_classes_root = lookup_hkey(cl_r_hkey);
261 ADD_ROOT_KEY(key_users);
264 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
265 * (later, when a win32 registry editing tool becomes avail.)
267 while (pwd=getpwent()) {
268 if (pwd->pw_name == NULL)
270 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
271 RegCloseKey(c_u_hkey);
274 pwd=getpwuid(getuid());
275 if (pwd && pwd->pw_name) {
276 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
277 key_current_user = lookup_hkey(c_u_hkey);
279 ADD_ROOT_KEY(key_current_user);
281 ADD_ROOT_KEY(key_performance_data);
282 ADD_ROOT_KEY(key_current_config);
283 ADD_ROOT_KEY(key_dyn_data);
285 SHELL_StartupRegistry();
290 SHELL_StartupRegistry() {
294 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&hkey);
297 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
298 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
300 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
304 * string RegisteredOwner
305 * string RegisteredOrganization
308 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
313 if (-1!=gethostname(buf,200)) {
314 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
315 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
319 /************************ SAVE Registry Function ****************************/
321 #define REGISTRY_SAVE_VERSION 0x00000001
323 /* Registry saveformat:
324 * If you change it, increase above number by 1, which will flush
325 * old registry database files.
328 * "WINE REGISTRY Version %d"
332 * valuename=lastmodified,type,data
336 * keyname,valuename,stringdata:
337 * the usual ascii characters from 0x00-0xff (well, not 0x00)
338 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
339 * ( "=\\\t" escaped in \uXXXX form.)
343 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
345 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
346 * SaveOnlyUpdatedKeys=yes
349 _save_check_tainted(LPKEYSTRUCT lpkey) {
354 if (lpkey->flags & REG_OPTION_TAINTED)
359 if (_save_check_tainted(lpkey->nextsub)) {
360 lpkey->flags |= REG_OPTION_TAINTED;
369 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
382 if (escapeeq && *s=='=')
385 fputc(*s,F); /* if \\ then put it twice. */
387 fprintf(F,"\\u%04x",*((unsigned short*)s));
395 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
401 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
402 (all || (lpxkey->flags & REG_OPTION_TAINTED))
404 for (tabs=level;tabs--;)
406 _save_USTRING(F,lpxkey->keyname,1);
408 for (i=0;i<lpxkey->nrofvalues;i++) {
409 LPKEYVALUE val=lpxkey->values+i;
411 for (tabs=level+1;tabs--;)
413 _save_USTRING(F,val->name,0);
415 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
416 if ((1<<val->type) & UNICONVMASK)
417 _save_USTRING(F,(LPWSTR)val->data,0);
419 for (j=0;j<val->len;j++)
420 fprintf(F,"%02x",*((unsigned char*)val->data+j));
423 /* descend recursively */
424 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
433 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
434 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
435 _save_check_tainted(lpkey->nextsub);
436 return _savesubkey(F,lpkey->nextsub,0,all);
440 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
445 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
450 if (!_savesubreg(F,lpkey,all)) {
453 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
461 SHELL_SaveRegistry() {
469 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
475 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
487 if (lstrcmpi32A(buf,"yes"))
489 pwd=getpwuid(getuid());
490 if (pwd!=NULL && pwd->pw_dir!=NULL)
494 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
495 strlen(SAVE_CURRENT_USER) + 2 );
496 strcpy(fn,pwd->pw_dir);
497 strcat(fn,WINE_PREFIX);
498 /* create the directory. don't care about errorcodes. */
499 mkdir(fn,0755); /* drwxr-xr-x */
500 strcat(fn,"/"SAVE_CURRENT_USER);
501 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
502 strcpy(tmp,fn);strcat(tmp,".tmp");
503 if (_savereg(key_current_user,tmp,all)) {
504 if (-1==rename(tmp,fn)) {
505 perror("rename tmp registry");
511 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
512 strcpy(fn,pwd->pw_dir);
513 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
514 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
515 strcpy(tmp,fn);strcat(tmp,".tmp");
516 if (_savereg(key_local_machine,tmp,all)) {
517 if (-1==rename(tmp,fn)) {
518 perror("rename tmp registry");
525 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
528 /************************ LOAD Registry Function ****************************/
531 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
532 LPKEYSTRUCT lpxkey,*lplpkey;
538 lplpkey= &(lpkey->nextsub);
541 if (!lstrcmpi32W(lpxkey->keyname,keyname))
543 lplpkey = &(lpxkey->next);
547 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
549 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
550 lpxkey->keyname = keyname;
558 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
564 if (name && !*name) {/* empty string equals default (NULL) value */
569 for (i=0;i<lpkey->nrofvalues;i++) {
575 if ( val->name!=NULL &&
576 !lstrcmpi32W(val->name,name)
581 if (i==lpkey->nrofvalues) {
582 lpkey->values = xrealloc(
584 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
587 memset(val,'\0',sizeof(KEYVALUE));
593 if (val->lastmodified<lastmodified) {
594 val->lastmodified=lastmodified;
605 /* reads a line including dynamically enlarging the readbuffer and throwing
609 _wine_read_line(FILE *F,char **buf,int *len) {
618 s=fgets(curread,mylen,F);
621 if (NULL==(s=strchr(curread,'\n'))) {
622 /* buffer wasn't large enough */
623 curoff = strlen(*buf);
624 *buf = xrealloc(*buf,*len*2);
625 curread = *buf + curoff;
626 mylen = *len; /* we filled up the buffer and
627 * got new '*len' bytes to fill
635 /* throw away comments */
636 if (**buf=='#' || **buf==';') {
641 if (s) /* got end of line */
647 /* converts a char* into a UNICODE string (up to a special char)
648 * and returns the position exactly after that string
651 _wine_read_USTRING(char *buf,LPWSTR *str) {
655 /* read up to "=" or "\0" or "\n" */
658 /* empty string is the win3.1 default value(NULL)*/
662 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
664 while (*s && (*s!='\n') && (*s!='=')) {
666 *ws++=*((unsigned char*)s++);
675 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
683 memcpy(xbuf,s,4);xbuf[4]='\0';
684 if (!sscanf(xbuf,"%x",&wc))
685 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
687 *ws++ =(unsigned short)wc;
694 *str = strdupW(*str);
703 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
710 lpkey->flags |= optflag;
712 /* good. we already got a line here ... so parse it */
722 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
725 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
728 /* let the caller handle this line */
729 if (i<level || **buf=='\0')
732 /* it can be: a value or a keyname. Parse the name first */
733 s=_wine_read_USTRING(s,&name);
735 /* switch() default: hack to avoid gotos */
739 lpxkey=_find_or_add_key(lpkey,name);
742 int len,lastmodified,type;
745 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
749 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
750 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
756 if ((1<<type) & UNICONVMASK) {
757 s=_wine_read_USTRING(s,(LPWSTR*)&data);
759 len = lstrlen32W((LPWSTR)data)*2+2;
764 data = (LPBYTE)xmalloc(len+1);
765 for (i=0;i<len;i++) {
767 if (*s>='0' && *s<='9')
769 if (*s>='a' && *s<='f')
771 if (*s>='A' && *s<='F')
774 if (*s>='0' && *s<='9')
776 if (*s>='a' && *s<='f')
778 if (*s>='A' && *s<='F')
783 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
786 /* read the next line */
787 if (!_wine_read_line(F,buf,buflen))
794 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
799 buf=xmalloc(10);buflen=10;
800 if (!_wine_read_line(F,&buf,&buflen)) {
804 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
808 if (ver!=REGISTRY_SAVE_VERSION) {
809 dprintf_info(reg,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
813 if (!_wine_read_line(F,&buf,&buflen)) {
817 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
826 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
831 dprintf_warn(reg,"Couldn't open %s for reading: %s\n",
836 if (!_wine_loadsubreg(F,lpkey,optflag)) {
845 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
852 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
854 for (j=0;j<from->nrofvalues;j++) {
858 valfrom = from->values+j;
860 if (name) name=strdupW(name);
861 data=(LPBYTE)xmalloc(valfrom->len);
862 memcpy(data,valfrom->data,valfrom->len);
870 valfrom->lastmodified
873 _copy_registry(from,lpxkey);
878 /* WINDOWS 95 REGISTRY LOADER */
880 * Structure of a win95 registry database.
884 * 8 : DWORD offset_of_RGDB_part
885 * 0C..0F: ? (someone fill in please)
886 * 10: WORD number of RGDB blocks
888 * 14: WORD always 0000?
889 * 16: WORD always 0001?
890 * 18..1F: ? (someone fill in please)
895 * 4 : DWORD offset to first RGDB section
896 * 8 : DWORD offset to ?
897 * C..0x1B: ? (fill in)
898 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
900 * Disk Key Entry Structure:
901 * 00: DWORD - Free entry indicator(?)
902 * 04: DWORD - Hash = sum of bytes of keyname
903 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
904 * 0C: DWORD - disk address of PreviousLevel Key.
905 * 10: DWORD - disk address of Next Sublevel Key.
906 * 14: DWORD - disk address of Next Key (on same level).
907 * DKEP>18: WORD - Nr, Low Significant part.
908 * 1A: WORD - Nr, High Significant part.
910 * The disk address always points to the nr part of the previous key entry
911 * of the referenced key. Don't ask me why, or even if I got this correct
912 * from staring at 1kg of hexdumps. (DKEP)
914 * The High significant part of the structure seems to equal the number
915 * of the RGDB section. The low significant part is a unique ID within
918 * There are two minor corrections to the position of that structure.
919 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
920 * the DKE reread from there.
921 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
922 * CPS - I have not experienced the above phenomenon in my registry files
926 * 04: DWORD offset to next RGDB section
928 * 0C: WORD always 000d?
929 * 0E: WORD RGDB block number
930 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
935 * 00: DWORD nextkeyoffset - offset to the next disk key structure
936 * 08: WORD nrLS - low significant part of NR
937 * 0A: WORD nrHS - high significant part of NR
938 * 0C: DWORD bytesused - bytes used in this structure.
939 * 10: WORD name_len - length of name in bytes. without \0
940 * 12: WORD nr_of_values - number of values.
941 * 14: char name[name_len] - name string. No \0.
942 * 14+name_len: disk values
943 * nextkeyoffset: ... next disk key
946 * 00: DWORD type - value type (hmm, could be WORD too)
947 * 04: DWORD - unknown, usually 0
948 * 08: WORD namelen - length of Name. 0 means name=NULL
949 * 0C: WORD datalen - length of Data.
950 * 10: char name[namelen] - name, no \0
951 * 10+namelen: BYTE data[datalen] - data, without \0 if string
952 * 10+namelen+datalen: next values or disk key
954 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
955 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
956 * structure) and reading another RGDB_section.
957 * repeat until end of file.
959 * An interesting relationship exists in RGDB_section. The value at offset
960 * 10 equals the value at offset 4 minus the value at offset 8. I have no
961 * idea at the moment what this means. (Kevin Cozens)
963 * FIXME: this description needs some serious help, yes.
966 struct _w95keyvalue {
968 unsigned short datalen;
978 struct _w95keyvalue *values;
979 struct _w95key *prevlvl;
980 struct _w95key *nextsub;
981 struct _w95key *next;
994 LPWSTR strcvtA2W(LPCSTR src, int nchars)
997 LPWSTR dest = xmalloc (2 * nchars + 2);
999 lstrcpynAtoW(dest,src, nchars);
1004 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1005 int nrLS, int nrMS, struct _w95_info *info )
1008 /* Disk Key Header structure (RGDB part) */
1010 unsigned long nextkeyoff;
1011 unsigned short nrLS;
1012 unsigned short nrMS;
1013 unsigned long bytesused;
1014 unsigned short keynamelen;
1015 unsigned short values;
1018 /* disk key values or nothing */
1020 /* Disk Key Value structure */
1024 unsigned short valnamelen;
1025 unsigned short valdatalen;
1026 /* valname, valdata */
1032 char *rgdbdata = info->rgdbbuffer;
1033 int nbytes = info->rgdbsize;
1034 char *curdata = rgdbdata;
1035 char *end = rgdbdata + nbytes;
1037 char *next = rgdbdata;
1043 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1045 memcpy(&off_next_rgdb,curdata+4,4);
1046 next = curdata + off_next_rgdb;
1047 nrgdb = (int) *((short *)curdata + 7);
1049 } while (nrgdb != nrMS && (next < end));
1051 /* curdata now points to the start of the right RGDB section */
1054 #define XREAD(whereto,len) \
1055 if ((curdata + len) <end) {\
1056 memcpy(whereto,curdata,len);\
1062 XREAD(&dkh, sizeof (dkh));
1063 if (dkh.nrLS == nrLS) break;
1065 curdata += dkh.nextkeyoff - sizeof(dkh);
1066 } while (curdata < next);
1068 if (dkh.nrLS != nrLS) return (NULL);
1070 if (nrgdb != dkh.nrMS) {
1074 assert((dkh.keynamelen<2) || curdata[0]);
1075 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1076 curdata += dkh.keynamelen;
1078 for (i=0;i< dkh.values; i++) {
1084 XREAD(&dkv,sizeof(dkv));
1086 name = strcvtA2W(curdata, dkv.valnamelen);
1087 curdata += dkv.valnamelen;
1089 if ((1 << dkv.type) & UNICONVMASK) {
1090 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1091 len = dkv.valdatalen + 1;
1093 /* I don't think we want to NULL terminate all data */
1094 data = xmalloc(dkv.valdatalen);
1095 memcpy (data, curdata, dkv.valdatalen);
1096 len = dkv.valdatalen;
1099 curdata += dkv.valdatalen;
1116 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1119 /* Disk Key Entry structure (RGKN part) */
1123 unsigned long x3;/*usually 0xFFFFFFFF */
1124 unsigned long prevlvl;
1125 unsigned long nextsub;
1127 unsigned short nrLS;
1128 unsigned short nrMS;
1129 } *dke = (struct dke *)off;
1133 dke = (struct dke *) ((char *)info->rgknbuffer);
1136 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1137 /* XXX <-- This is a hack*/
1142 if (dke->nextsub != -1 &&
1143 ((dke->nextsub - 0x20) < info->rgknsize)
1144 && (dke->nextsub > 0x20)) {
1146 _w95_walkrgkn(lpxkey,
1147 info->rgknbuffer + dke->nextsub - 0x20,
1151 if (dke->next != -1 &&
1152 ((dke->next - 0x20) < info->rgknsize) &&
1153 (dke->next > 0x20)) {
1154 _w95_walkrgkn(prevkey,
1155 info->rgknbuffer + dke->next - 0x20,
1163 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1166 unsigned long where,version,rgdbsection,end;
1167 struct _w95_info info;
1169 BY_HANDLE_FILE_INFORMATION hfdinfo;
1171 dprintf_info(reg,"Loading Win95 registry database '%s'\n",fn);
1172 hfd=OpenFile32(fn,&ofs,OF_READ);
1173 if (hfd==HFILE_ERROR32)
1176 if (4!=_lread32(hfd,magic,4))
1178 if (strcmp(magic,"CREG")) {
1179 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1182 if (4!=_lread32(hfd,&version,4))
1184 if (4!=_lread32(hfd,&rgdbsection,4))
1186 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1188 if (4!=_lread32(hfd,magic,4))
1190 if (strcmp(magic,"RGKN")) {
1191 dprintf_warn(reg, "second IFF header not RGKN, but %s\n", magic);
1195 /* STEP 1: Keylink structures */
1196 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1201 info.rgknsize = end - where;
1202 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1203 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1206 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1209 end = hfdinfo.nFileSizeLow;
1210 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1212 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1215 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1216 info.rgdbsize = end - rgdbsection;
1218 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1222 _w95_walkrgkn(lpkey, NULL, &info);
1224 free (info.rgdbbuffer);
1225 free (info.rgknbuffer);
1228 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1231 reghack - windows 3.11 registry data format demo program.
1233 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1234 a combined hash table and tree description, and finally a text table.
1236 The header is obvious from the struct header. The taboff1 and taboff2
1237 fields are always 0x20, and their usage is unknown.
1239 The 8-byte entry table has various entry types.
1241 tabent[0] is a root index. The second word has the index of the root of
1243 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1244 the index of the key/value that has that hash. Data with the same
1245 hash value are on a circular list. The other three words in the
1246 hash entry are always zero.
1247 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1248 entry: dirent and keyent/valent. They are identified by context.
1249 tabent[freeidx] is the first free entry. The first word in a free entry
1250 is the index of the next free entry. The last has 0 as a link.
1251 The other three words in the free list are probably irrelevant.
1253 Entries in text table are preceeded by a word at offset-2. This word
1254 has the value (2*index)+1, where index is the referring keyent/valent
1255 entry in the table. I have no suggestion for the 2* and the +1.
1256 Following the word, there are N bytes of data, as per the keyent/valent
1257 entry length. The offset of the keyent/valent entry is from the start
1258 of the text table to the first data byte.
1260 This information is not available from Microsoft. The data format is
1261 deduced from the reg.dat file by me. Mistakes may
1262 have been made. I claim no rights and give no guarantees for this program.
1264 Tor Sjøwall, tor@sn.no
1267 /* reg.dat header format */
1268 struct _w31_header {
1269 char cookie[8]; /* 'SHCC3.10' */
1270 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1271 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1272 unsigned long tabcnt; /* number of entries in index table */
1273 unsigned long textoff; /* offset of text part */
1274 unsigned long textsize; /* byte size of text part */
1275 unsigned short hashsize; /* hash size */
1276 unsigned short freeidx; /* free index */
1279 /* generic format of table entries */
1280 struct _w31_tabent {
1281 unsigned short w0, w1, w2, w3;
1284 /* directory tabent: */
1285 struct _w31_dirent {
1286 unsigned short sibling_idx; /* table index of sibling dirent */
1287 unsigned short child_idx; /* table index of child dirent */
1288 unsigned short key_idx; /* table index of key keyent */
1289 unsigned short value_idx; /* table index of value valent */
1293 struct _w31_keyent {
1294 unsigned short hash_idx; /* hash chain index for string */
1295 unsigned short refcnt; /* reference count */
1296 unsigned short length; /* length of string */
1297 unsigned short string_off; /* offset of string in text table */
1301 struct _w31_valent {
1302 unsigned short hash_idx; /* hash chain index for string */
1303 unsigned short refcnt; /* reference count */
1304 unsigned short length; /* length of string */
1305 unsigned short string_off; /* offset of string in text table */
1308 /* recursive helper function to display a directory tree */
1310 __w31_dumptree( unsigned short idx,
1312 struct _w31_tabent *tab,
1313 struct _w31_header *head,
1315 time_t lastmodified,
1318 struct _w31_dirent *dir;
1319 struct _w31_keyent *key;
1320 struct _w31_valent *val;
1321 LPKEYSTRUCT xlpkey = NULL;
1323 static char tail[400];
1326 dir=(struct _w31_dirent*)&tab[idx];
1329 key = (struct _w31_keyent*)&tab[dir->key_idx];
1331 memcpy(tail,&txt[key->string_off],key->length);
1332 tail[key->length]='\0';
1333 /* all toplevel entries AND the entries in the
1334 * toplevel subdirectory belong to \SOFTWARE\Classes
1336 if (!level && !lstrcmp32A(tail,".classes")) {
1337 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1338 idx=dir->sibling_idx;
1341 name=strdupA2W(tail);
1343 xlpkey=_find_or_add_key(lpkey,name);
1345 /* only add if leaf node or valued node */
1346 if (dir->value_idx!=0||dir->child_idx==0) {
1347 if (dir->value_idx) {
1348 val=(struct _w31_valent*)&tab[dir->value_idx];
1349 memcpy(tail,&txt[val->string_off],val->length);
1350 tail[val->length]='\0';
1351 value=strdupA2W(tail);
1352 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1356 dprintf_info(reg,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1358 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1359 idx=dir->sibling_idx;
1366 struct _w31_header head;
1367 struct _w31_tabent *tab;
1371 BY_HANDLE_FILE_INFORMATION hfinfo;
1372 time_t lastmodified;
1376 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1377 if (hf==HFILE_ERROR32)
1380 /* read & dump header */
1381 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1382 dprintf_err(reg, "_w31_loadreg:reg.dat is too short.\n");
1386 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1387 dprintf_err(reg, "_w31_loadreg:reg.dat has bad signature.\n");
1392 len = head.tabcnt * sizeof(struct _w31_tabent);
1393 /* read and dump index table */
1395 if (len!=_lread32(hf,tab,len)) {
1396 dprintf_err(reg,"_w31_loadreg:couldn't read %d bytes.\n",len);
1403 txt = xmalloc(head.textsize);
1404 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1405 dprintf_err(reg,"_w31_loadreg:couldn't seek to textblock.\n");
1411 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1412 dprintf_err(reg,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1419 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1420 dprintf_err(reg,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1426 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1428 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1430 lpkey = lookup_hkey(hkey);
1431 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1439 SHELL_LoadRegistry() {
1446 if (key_classes_root==NULL)
1449 /* Load windows 3.1 entries */
1451 /* Load windows 95 entries */
1452 _w95_loadreg("C:\\system.1st", key_local_machine);
1453 _w95_loadreg("system.dat", key_local_machine);
1454 _w95_loadreg("user.dat", key_users);
1456 /* the global user default is loaded under HKEY_USERS\\.Default */
1457 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1458 lpkey = lookup_hkey(hkey);
1459 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1461 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1462 _copy_registry(lpkey,key_current_user);
1465 /* the global machine defaults */
1466 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1468 /* load the user saved registries */
1470 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1472 pwd=getpwuid(getuid());
1473 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1474 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1475 strcpy(fn,pwd->pw_dir);
1476 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1477 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1479 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1480 strcpy(fn,pwd->pw_dir);
1481 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1482 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1485 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1486 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1487 DWORD junk,type,len;
1491 if (( RegQueryValueEx32A(
1498 )!=ERROR_SUCCESS) ||
1501 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1507 /********************* API FUNCTIONS ***************************************/
1511 * All functions are stubs to RegOpenKeyEx32W where all the
1514 * FIXME: security,options,desiredaccess,...
1517 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1518 * RegOpenKey32W -> RegOpenKeyEx32W
1521 /* RegOpenKeyExW [ADVAPI32.150] */
1522 DWORD WINAPI RegOpenKeyEx32W(
1529 LPKEYSTRUCT lpNextKey,lpxkey;
1532 dprintf_info(reg,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1533 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1536 lpNextKey = lookup_hkey(hkey);
1538 return SHELL_ERROR_BADKEY;
1539 if (!lpszSubKey || !*lpszSubKey) {
1540 add_handle(++currenthandle,lpNextKey,samDesired);
1541 *retkey=currenthandle;
1542 return SHELL_ERROR_SUCCESS;
1544 split_keypath(lpszSubKey,&wps,&wpc);
1546 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1549 lpxkey=lpNextKey->nextsub;
1551 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1553 lpxkey=lpxkey->next;
1557 return SHELL_ERROR_BADKEY;
1562 add_handle(++currenthandle,lpxkey,samDesired);
1563 *retkey = currenthandle;
1565 return SHELL_ERROR_SUCCESS;
1568 /* RegOpenKeyW [ADVAPI32.151] */
1569 DWORD WINAPI RegOpenKey32W(
1574 dprintf_info(reg,"RegOpenKey32W(%lx,%s,%p)\n",
1575 (LONG)hkey,W2C(lpszSubKey,0),retkey
1577 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1581 /* RegOpenKeyExA [ADVAPI32.149] */
1582 DWORD WINAPI RegOpenKeyEx32A(
1592 dprintf_info(reg,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1593 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1596 lpszSubKeyW=strdupA2W(lpszSubKey);
1599 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1605 /* RegOpenKeyA [ADVAPI32.148] */
1606 DWORD WINAPI RegOpenKey32A(
1611 dprintf_info(reg,"RegOpenKey32A(%lx,%s,%p)\n",
1612 (LONG)hkey,lpszSubKey,retkey
1614 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1617 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1618 DWORD WINAPI RegOpenKey16(
1623 dprintf_info(reg,"RegOpenKey16(%lx,%s,%p)\n",
1624 (LONG)hkey,lpszSubKey,retkey
1626 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1632 * All those functions convert their respective
1633 * arguments and call RegCreateKeyExW at the end.
1635 * FIXME: no security,no access attrib,no optionhandling yet.
1638 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1639 * RegCreateKey32W -> RegCreateKeyEx32W
1642 /* RegCreateKeyExW [ADVAPI32.131] */
1643 DWORD WINAPI RegCreateKeyEx32W(
1650 LPSECURITY_ATTRIBUTES lpSecAttribs,
1654 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1658 /*FIXME: handle security/access/whatever */
1659 dprintf_info(reg,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1671 lpNextKey = lookup_hkey(hkey);
1673 return SHELL_ERROR_BADKEY;
1674 if (!lpszSubKey || !*lpszSubKey) {
1675 add_handle(++currenthandle,lpNextKey,samDesired);
1676 *retkey=currenthandle;
1677 lpNextKey->flags|=REG_OPTION_TAINTED;
1678 return SHELL_ERROR_SUCCESS;
1680 split_keypath(lpszSubKey,&wps,&wpc);
1682 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1685 lpxkey=lpNextKey->nextsub;
1687 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1689 lpxkey=lpxkey->next;
1697 add_handle(++currenthandle,lpxkey,samDesired);
1698 lpxkey->flags |= REG_OPTION_TAINTED;
1699 *retkey = currenthandle;
1701 *lpDispos = REG_OPENED_EXISTING_KEY;
1703 return SHELL_ERROR_SUCCESS;
1705 /* good. now the hard part */
1707 lplpPrevKey = &(lpNextKey->nextsub);
1708 lpxkey = *lplpPrevKey;
1710 lplpPrevKey = &(lpxkey->next);
1711 lpxkey = *lplpPrevKey;
1713 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1714 if (!*lplpPrevKey) {
1716 return SHELL_ERROR_OUTOFMEMORY;
1718 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1719 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1720 (*lplpPrevKey)->next = NULL;
1721 (*lplpPrevKey)->nextsub = NULL;
1722 (*lplpPrevKey)->values = NULL;
1723 (*lplpPrevKey)->nrofvalues = 0;
1724 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1726 (*lplpPrevKey)->class = strdupW(lpszClass);
1728 (*lplpPrevKey)->class = NULL;
1729 lpNextKey = *lplpPrevKey;
1732 add_handle(++currenthandle,lpNextKey,samDesired);
1734 /*FIXME: flag handling correct? */
1735 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1737 lpNextKey->class = strdupW(lpszClass);
1739 lpNextKey->class = NULL;
1740 *retkey = currenthandle;
1742 *lpDispos = REG_CREATED_NEW_KEY;
1744 return SHELL_ERROR_SUCCESS;
1747 /* RegCreateKeyW [ADVAPI32.132] */
1748 DWORD WINAPI RegCreateKey32W(
1755 dprintf_info(reg,"RegCreateKey32W(%lx,%s,%p)\n",
1756 (LONG)hkey,W2C(lpszSubKey,0),retkey
1758 ret=RegCreateKeyEx32W(
1759 hkey, /* key handle */
1760 lpszSubKey, /* subkey name */
1761 0, /* reserved = 0 */
1762 NULL, /* lpszClass? FIXME: ? */
1763 REG_OPTION_NON_VOLATILE, /* options */
1764 KEY_ALL_ACCESS, /* desired access attribs */
1765 NULL, /* lpsecurity attributes */
1766 retkey, /* lpretkey */
1767 &junk /* disposition value */
1772 /* RegCreateKeyExA [ADVAPI32.130] */
1773 DWORD WINAPI RegCreateKeyEx32A(
1780 LPSECURITY_ATTRIBUTES lpSecAttribs,
1784 LPWSTR lpszSubKeyW,lpszClassW;
1787 dprintf_info(reg,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1799 lpszSubKeyW=strdupA2W(lpszSubKey);
1803 lpszClassW=strdupA2W(lpszClass);
1806 ret=RegCreateKeyEx32W(
1824 /* RegCreateKeyA [ADVAPI32.129] */
1825 DWORD WINAPI RegCreateKey32A(
1832 dprintf_info(reg,"RegCreateKey32A(%lx,%s,%p)\n",
1833 (LONG)hkey,lpszSubKey,retkey
1835 return RegCreateKeyEx32A(
1836 hkey, /* key handle */
1837 lpszSubKey, /* subkey name */
1838 0, /* reserved = 0 */
1839 NULL, /* lpszClass? FIXME: ? */
1840 REG_OPTION_NON_VOLATILE,/* options */
1841 KEY_ALL_ACCESS, /* desired access attribs */
1842 NULL, /* lpsecurity attributes */
1843 retkey, /* lpretkey */
1844 &junk /* disposition value */
1848 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1849 DWORD WINAPI RegCreateKey16(
1854 dprintf_info(reg,"RegCreateKey16(%lx,%s,%p)\n",
1855 (LONG)hkey,lpszSubKey,retkey
1857 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1861 * Query Value Functions
1862 * Win32 differs between keynames and valuenames.
1863 * multiple values may belong to one key, the special value
1864 * with name NULL is the default value used by the win31
1868 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1869 * RegQueryValue32W -> RegQueryValueEx32W
1872 /* RegQueryValueExW [ADVAPI32.158] */
1873 DWORD WINAPI RegQueryValueEx32W(
1875 LPWSTR lpszValueName,
1876 LPDWORD lpdwReserved,
1884 dprintf_info(reg,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1885 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1886 lpcbData?*lpcbData:0
1889 lpkey = lookup_hkey(hkey);
1891 return SHELL_ERROR_BADKEY;
1892 if (lpszValueName && !*lpszValueName)
1893 lpszValueName = NULL;
1894 if (lpszValueName==NULL) {
1895 for (i=0;i<lpkey->nrofvalues;i++)
1896 if (lpkey->values[i].name==NULL)
1899 for (i=0;i<lpkey->nrofvalues;i++)
1900 if ( lpkey->values[i].name &&
1901 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
1905 if (i==lpkey->nrofvalues) {
1906 if (lpszValueName==NULL) {
1908 *(WCHAR*)lpbData = 0;
1913 return SHELL_ERROR_SUCCESS;
1915 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1918 *lpdwType = lpkey->values[i].type;
1919 if (lpbData==NULL) {
1921 return SHELL_ERROR_SUCCESS;
1922 *lpcbData = lpkey->values[i].len;
1923 return SHELL_ERROR_SUCCESS;
1925 if (*lpcbData<lpkey->values[i].len) {
1928 *lpcbData = lpkey->values[i].len;
1929 return ERROR_MORE_DATA;
1931 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1932 *lpcbData = lpkey->values[i].len;
1933 return SHELL_ERROR_SUCCESS;
1936 /* RegQueryValueW [ADVAPI32.159] */
1937 DWORD WINAPI RegQueryValue32W(
1946 dprintf_info(reg,"RegQueryValue32W(%x,%s,%p,%ld)\n",
1947 hkey,W2C(lpszSubKey,0),lpszData,
1948 lpcbData?*lpcbData:0
1951 /* only open subkey, if we really do descend */
1952 if (lpszSubKey && *lpszSubKey) {
1953 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1954 if (ret!=ERROR_SUCCESS)
1960 ret = RegQueryValueEx32W(
1962 NULL, /* varname NULL -> compat */
1963 NULL, /* lpdwReserved, must be NULL */
1973 /* RegQueryValueExA [ADVAPI32.157] */
1974 DWORD WINAPI RegQueryValueEx32A(
1976 LPSTR lpszValueName,
1977 LPDWORD lpdwReserved,
1982 LPWSTR lpszValueNameW;
1988 dprintf_info(reg,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n",
1989 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
1990 lpcbData?*lpcbData:0
1993 lpszValueNameW=strdupA2W(lpszValueName);
1995 lpszValueNameW=NULL;
2004 ret=RegQueryValueEx32W(
2013 if (ret==ERROR_MORE_DATA) {
2014 buf = (LPBYTE)xmalloc(*mylen);
2016 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2017 myxlen = 2*(*lpcbData);
2022 myxlen = *lpcbData*2;
2027 ret=RegQueryValueEx32W(
2037 if (ret==ERROR_SUCCESS) {
2039 if (UNICONVMASK & (1<<(type))) {
2040 /* convert UNICODE to ASCII */
2041 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2042 *lpcbData = myxlen/2;
2044 if (myxlen>*lpcbData)
2045 ret = ERROR_MORE_DATA;
2047 memcpy(lpbData,buf,myxlen);
2052 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2053 *lpcbData = myxlen/2;
2056 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2057 *lpcbData = myxlen/2;
2064 /* RegQueryValueEx [KERNEL.225] */
2065 DWORD WINAPI RegQueryValueEx16(
2067 LPSTR lpszValueName,
2068 LPDWORD lpdwReserved,
2073 dprintf_info(reg,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2074 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2075 lpcbData?*lpcbData:0
2077 return RegQueryValueEx32A(
2087 /* RegQueryValueA [ADVAPI32.156] */
2088 DWORD WINAPI RegQueryValue32A(
2097 dprintf_info(reg,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2098 hkey,lpszSubKey,lpszData,
2099 lpcbData?*lpcbData:0
2102 /* only open subkey, if we really do descend */
2103 if (lpszSubKey && *lpszSubKey) {
2104 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2105 if (ret!=ERROR_SUCCESS)
2111 ret = RegQueryValueEx32A(
2113 NULL, /* lpszValueName NULL -> compat */
2114 NULL, /* lpdwReserved, must be NULL */
2124 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2125 DWORD WINAPI RegQueryValue16(
2131 dprintf_info(reg,"RegQueryValue16(%x,%s,%p,%ld)\n",
2132 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2134 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2135 * anyway, so we just mask out the high 16 bit.
2136 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2139 *lpcbData &= 0xFFFF;
2140 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2144 * Setting values of Registry keys
2147 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2148 * RegSetValue32W -> RegSetValueEx32W
2151 /* RegSetValueExW [ADVAPI32.170] */
2152 DWORD WINAPI RegSetValueEx32W(
2154 LPWSTR lpszValueName,
2163 dprintf_info(reg,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2164 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2166 /* we no longer care about the lpbData type here... */
2167 lpkey = lookup_hkey(hkey);
2169 return SHELL_ERROR_BADKEY;
2171 lpkey->flags |= REG_OPTION_TAINTED;
2173 if (lpszValueName==NULL) {
2174 for (i=0;i<lpkey->nrofvalues;i++)
2175 if (lpkey->values[i].name==NULL)
2178 for (i=0;i<lpkey->nrofvalues;i++)
2179 if ( lpkey->values[i].name &&
2180 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2184 if (i==lpkey->nrofvalues) {
2185 lpkey->values = (LPKEYVALUE)xrealloc(
2187 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2189 lpkey->nrofvalues++;
2190 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2192 if (lpkey->values[i].name==NULL)
2194 lpkey->values[i].name = strdupW(lpszValueName);
2196 lpkey->values[i].name = NULL;
2197 lpkey->values[i].len = cbData;
2198 lpkey->values[i].type = dwType;
2199 if (lpkey->values[i].data !=NULL)
2200 free(lpkey->values[i].data);
2201 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2202 lpkey->values[i].lastmodified = time(NULL);
2203 memcpy(lpkey->values[i].data,lpbData,cbData);
2204 return SHELL_ERROR_SUCCESS;
2207 /* RegSetValueExA [ADVAPI32.169] */
2208 DWORD WINAPI RegSetValueEx32A(
2210 LPSTR lpszValueName,
2217 LPWSTR lpszValueNameW;
2220 dprintf_info(reg,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n",
2221 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2223 if ((1<<dwType) & UNICONVMASK) {
2224 buf=(LPBYTE)strdupA2W(lpbData);
2225 cbData=2*strlen(lpbData)+2;
2229 lpszValueNameW = strdupA2W(lpszValueName);
2231 lpszValueNameW = NULL;
2232 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2234 free(lpszValueNameW);
2240 /* RegSetValueEx [KERNEL.226] */
2241 DWORD WINAPI RegSetValueEx16(
2243 LPSTR lpszValueName,
2249 dprintf_info(reg,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n",
2250 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2252 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2255 /* RegSetValueW [ADVAPI32.171] */
2256 DWORD WINAPI RegSetValue32W(
2266 dprintf_info(reg,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n",
2267 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2269 if (lpszSubKey && *lpszSubKey) {
2270 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2271 if (ret!=ERROR_SUCCESS)
2275 if (dwType!=REG_SZ) {
2276 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2279 if (cbData!=2*lstrlen32W(lpszData)+2) {
2280 dprintf_info(reg,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2281 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2283 cbData=2*lstrlen32W(lpszData)+2;
2285 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2291 /* RegSetValueA [ADVAPI32.168] */
2292 DWORD WINAPI RegSetValue32A(
2302 dprintf_info(reg,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n",
2303 hkey,lpszSubKey,dwType,lpszData,cbData
2305 if (lpszSubKey && *lpszSubKey) {
2306 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2307 if (ret!=ERROR_SUCCESS)
2312 if (dwType!=REG_SZ) {
2313 dprintf_info(reg,"RegSetValueA called with dwType=%ld!\n",dwType);
2316 if (cbData!=strlen(lpszData)+1)
2317 cbData=strlen(lpszData)+1;
2318 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2324 /* RegSetValue [KERNEL.221] [SHELL.5] */
2325 DWORD WINAPI RegSetValue16(
2333 dprintf_info(reg,"RegSetValue16(%x,%s,%ld,%s,%ld)\n",
2334 hkey,lpszSubKey,dwType,lpszData,cbData
2336 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2344 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2345 * RegEnumKey32W -> RegEnumKeyEx32W
2348 /* RegEnumKeyExW [ADVAPI32.139] */
2349 DWORD WINAPI RegEnumKeyEx32W(
2354 LPDWORD lpdwReserved,
2359 LPKEYSTRUCT lpkey,lpxkey;
2361 dprintf_info(reg,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2362 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2364 lpkey=lookup_hkey(hkey);
2366 return SHELL_ERROR_BADKEY;
2367 if (!lpkey->nextsub)
2368 return ERROR_NO_MORE_ITEMS;
2369 lpxkey=lpkey->nextsub;
2370 while (iSubkey && lpxkey) {
2372 lpxkey=lpxkey->next;
2374 if (iSubkey || !lpxkey)
2375 return ERROR_NO_MORE_ITEMS;
2376 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2377 return ERROR_MORE_DATA;
2378 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2380 /* what should we write into it? */
2384 return ERROR_SUCCESS;
2388 /* RegEnumKeyW [ADVAPI32.140] */
2389 DWORD WINAPI RegEnumKey32W(
2397 dprintf_info(reg,"RegEnumKey32W(%x,%ld,%p,%ld)\n",
2398 hkey,iSubkey,lpszName,lpcchName
2400 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2402 /* RegEnumKeyExA [ADVAPI32.138] */
2403 DWORD WINAPI RegEnumKeyEx32A(
2408 LPDWORD lpdwReserved,
2413 DWORD ret,lpcchNameW,lpcchClassW;
2414 LPWSTR lpszNameW,lpszClassW;
2417 dprintf_info(reg,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2418 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2421 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2422 lpcchNameW = *lpcchName*2;
2428 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2429 lpcchClassW = *lpcchClass*2;
2434 ret=RegEnumKeyEx32W(
2444 if (ret==ERROR_SUCCESS) {
2445 lstrcpyWtoA(lpszName,lpszNameW);
2446 *lpcchName=strlen(lpszName);
2448 lstrcpyWtoA(lpszClass,lpszClassW);
2449 *lpcchClass=strlen(lpszClass);
2459 /* RegEnumKeyA [ADVAPI32.137] */
2460 DWORD WINAPI RegEnumKey32A(
2468 dprintf_info(reg,"RegEnumKey32A(%x,%ld,%p,%ld)\n",
2469 hkey,iSubkey,lpszName,lpcchName
2471 return RegEnumKeyEx32A(
2483 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2484 DWORD WINAPI RegEnumKey16(
2490 dprintf_info(reg,"RegEnumKey16(%x,%ld,%p,%ld)\n",
2491 hkey,iSubkey,lpszName,lpcchName
2493 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2497 * Enumerate Registry Values
2500 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2503 /* RegEnumValueW [ADVAPI32.142] */
2504 DWORD WINAPI RegEnumValue32W(
2509 LPDWORD lpdReserved,
2517 dprintf_info(reg,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2518 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2520 lpkey = lookup_hkey(hkey);
2522 return SHELL_ERROR_BADKEY;
2523 if (lpkey->nrofvalues<=iValue)
2524 return ERROR_NO_MORE_ITEMS;
2525 val = lpkey->values+iValue;
2528 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2529 *lpcchValue = lstrlen32W(val->name)*2+2;
2530 return ERROR_MORE_DATA;
2532 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2533 *lpcchValue=lstrlen32W(val->name)*2+2;
2539 *lpdwType=val->type;
2541 if (val->len>*lpcbData)
2542 return ERROR_MORE_DATA;
2543 memcpy(lpbData,val->data,val->len);
2544 *lpcbData = val->len;
2546 return SHELL_ERROR_SUCCESS;
2549 /* RegEnumValueA [ADVAPI32.141] */
2550 DWORD WINAPI RegEnumValue32A(
2555 LPDWORD lpdReserved,
2562 DWORD ret,lpcbDataW;
2564 dprintf_info(reg,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2565 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2568 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2570 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2571 lpcbDataW = *lpcbData*2;
2574 ret=RegEnumValue32W(
2585 if (ret==ERROR_SUCCESS) {
2586 lstrcpyWtoA(lpszValue,lpszValueW);
2588 if ((1<<*lpdwType) & UNICONVMASK) {
2589 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2591 if (lpcbDataW > *lpcbData)
2592 ret = ERROR_MORE_DATA;
2594 memcpy(lpbData,lpbDataW,lpcbDataW);
2596 *lpcbData = lpcbDataW;
2606 /* RegEnumValue [KERNEL.223] */
2607 DWORD WINAPI RegEnumValue16(
2612 LPDWORD lpdReserved,
2617 dprintf_info(reg,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2618 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2620 return RegEnumValue32A(
2633 * Close registry key
2635 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2636 DWORD WINAPI RegCloseKey(HKEY hkey) {
2637 dprintf_info(reg,"RegCloseKey(%x)\n",hkey);
2638 remove_handle(hkey);
2639 return ERROR_SUCCESS;
2642 * Delete registry key
2645 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2647 /* RegDeleteKeyW [ADVAPI32.134] */
2648 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2649 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2653 dprintf_info(reg,"RegDeleteKey32W(%x,%s)\n",
2654 hkey,W2C(lpszSubKey,0)
2656 lpNextKey = lookup_hkey(hkey);
2658 dprintf_info(reg, " Badkey[1].\n");
2659 return SHELL_ERROR_BADKEY;
2661 /* we need to know the previous key in the hier. */
2662 if (!lpszSubKey || !*lpszSubKey) {
2663 dprintf_info(reg, " Badkey[2].\n");
2664 return SHELL_ERROR_BADKEY;
2666 split_keypath(lpszSubKey,&wps,&wpc);
2670 lpxkey=lpNextKey->nextsub;
2672 dprintf_info(reg, " Scanning [%s]\n",
2673 W2C (lpxkey->keyname, 0));
2674 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2676 lpxkey=lpxkey->next;
2680 dprintf_info(reg, " Not found.\n");
2681 /* not found is success */
2682 return SHELL_ERROR_SUCCESS;
2687 lpxkey = lpNextKey->nextsub;
2688 lplpPrevKey = &(lpNextKey->nextsub);
2690 dprintf_info(reg, " Scanning [%s]\n",
2691 W2C (lpxkey->keyname, 0));
2692 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2694 lplpPrevKey = &(lpxkey->next);
2695 lpxkey = lpxkey->next;
2699 dprintf_warn(reg , " Not found.\n");
2700 return SHELL_ERROR_BADKEY;
2702 if (lpxkey->nextsub) {
2704 dprintf_warn(reg , " Not empty.\n");
2705 return SHELL_ERROR_CANTWRITE;
2707 *lplpPrevKey = lpxkey->next;
2708 free(lpxkey->keyname);
2710 free(lpxkey->class);
2712 free(lpxkey->values);
2715 dprintf_info(reg, " Done.\n");
2716 return SHELL_ERROR_SUCCESS;
2719 /* RegDeleteKeyA [ADVAPI32.133] */
2720 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2724 dprintf_info(reg,"RegDeleteKey32A(%x,%s)\n",
2727 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2728 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2729 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2733 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2734 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2735 dprintf_info(reg,"RegDeleteKey16(%x,%s)\n",
2738 return RegDeleteKey32A(hkey,lpszSubKey);
2742 * Delete registry value
2745 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2747 /* RegDeleteValueW [ADVAPI32.136] */
2748 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2754 dprintf_info(reg,"RegDeleteValue32W(%x,%s)\n",
2755 hkey,W2C(lpszValue,0)
2757 lpkey=lookup_hkey(hkey);
2759 return SHELL_ERROR_BADKEY;
2761 for (i=0;i<lpkey->nrofvalues;i++)
2762 if ( lpkey->values[i].name &&
2763 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2767 for (i=0;i<lpkey->nrofvalues;i++)
2768 if (lpkey->values[i].name==NULL)
2771 if (i==lpkey->nrofvalues)
2772 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2773 val = lpkey->values+i;
2774 if (val->name) free(val->name);
2775 if (val->data) free(val->data);
2779 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2781 lpkey->values = (LPKEYVALUE)xrealloc(
2783 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2785 lpkey->nrofvalues--;
2786 return SHELL_ERROR_SUCCESS;
2789 /* RegDeleteValueA [ADVAPI32.135] */
2790 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2795 dprintf_info(reg, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2796 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2797 ret=RegDeleteValue32W(hkey,lpszValueW);
2798 HeapFree(GetProcessHeap(),0,lpszValueW);
2802 /* RegDeleteValue [KERNEL.222] */
2803 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2805 dprintf_info(reg,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2806 return RegDeleteValue32A(hkey,lpszValue);
2809 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2810 DWORD WINAPI RegFlushKey(HKEY hkey)
2812 dprintf_fixme(reg, "RegFlushKey(%x), STUB.\n", hkey);
2813 return SHELL_ERROR_SUCCESS;
2816 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2818 /* RegQueryInfoKeyW [ADVAPI32.153] */
2819 DWORD WINAPI RegQueryInfoKey32W(
2823 LPDWORD lpdwReserved,
2825 LPDWORD lpcchMaxSubkey,
2826 LPDWORD lpcchMaxClass,
2828 LPDWORD lpcchMaxValueName,
2829 LPDWORD lpccbMaxValueData,
2830 LPDWORD lpcbSecurityDescriptor,
2833 LPKEYSTRUCT lpkey,lpxkey;
2834 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2837 dprintf_info(reg,"RegQueryInfoKey32W(%x,......)\n",hkey);
2838 lpkey=lookup_hkey(hkey);
2840 return SHELL_ERROR_BADKEY;
2843 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2844 *lpcchClass=lstrlen32W(lpkey->class)*2;
2845 return ERROR_MORE_DATA;
2847 *lpcchClass=lstrlen32W(lpkey->class)*2;
2848 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2855 *lpcchClass = lstrlen32W(lpkey->class)*2;
2857 lpxkey=lpkey->nextsub;
2858 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2861 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2862 maxsubkey=lstrlen32W(lpxkey->keyname);
2863 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2864 maxclass=lstrlen32W(lpxkey->class);
2865 if (lpxkey->nrofvalues>maxvalues)
2866 maxvalues=lpxkey->nrofvalues;
2867 for (i=0;i<lpxkey->nrofvalues;i++) {
2868 LPKEYVALUE val=lpxkey->values+i;
2870 if (val->name && lstrlen32W(val->name)>maxvname)
2871 maxvname=lstrlen32W(val->name);
2872 if (val->len>maxvdata)
2875 lpxkey=lpxkey->next;
2877 if (!maxclass) maxclass = 1;
2878 if (!maxvname) maxvname = 1;
2880 *lpcSubKeys = nrofkeys;
2882 *lpcchMaxSubkey = maxsubkey*2;
2884 *lpcchMaxClass = maxclass*2;
2886 *lpcValues = maxvalues;
2887 if (lpcchMaxValueName)
2888 *lpcchMaxValueName= maxvname;
2889 if (lpccbMaxValueData)
2890 *lpccbMaxValueData= maxvdata;
2891 return SHELL_ERROR_SUCCESS;
2894 /* RegQueryInfoKeyA [ADVAPI32.152] */
2895 DWORD WINAPI RegQueryInfoKey32A(
2899 LPDWORD lpdwReserved,
2901 LPDWORD lpcchMaxSubkey,
2902 LPDWORD lpcchMaxClass,
2904 LPDWORD lpcchMaxValueName,
2905 LPDWORD lpccbMaxValueData,
2906 LPDWORD lpcbSecurityDescriptor,
2912 dprintf_info(reg,"RegQueryInfoKey32A(%x,......)\n",hkey);
2915 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2919 ret=RegQueryInfoKey32W(
2930 lpcbSecurityDescriptor,
2933 if (ret==ERROR_SUCCESS && lpszClass)
2934 lstrcpyWtoA(lpszClass,lpszClassW);
2941 if (lpcchMaxValueName)
2942 *lpcchMaxValueName/=2;
2947 /* RegConnectRegistryA [ADVAPI32.127] */
2948 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
2950 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
2953 return ERROR_FILE_NOT_FOUND; /* FIXME */