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>
33 #define DEBUG_W95_LOADREG 0
35 /* FIXME: following defines should be configured global ... */
37 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
38 #define WINE_PREFIX "/.wine"
39 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
40 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
42 /* relative in ~user/.wine/ : */
43 #define SAVE_CURRENT_USER "user.reg"
44 #define SAVE_LOCAL_MACHINE "system.reg"
46 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
47 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
49 /* one value of a key */
50 typedef struct tagKEYVALUE
52 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
53 DWORD type; /* type of value */
54 DWORD len; /* length of data */
55 DWORD lastmodified; /* time of seconds since 1.1.1970 */
56 LPBYTE data; /* content, may be strings, binaries, etc. */
57 } KEYVALUE,*LPKEYVALUE;
60 typedef struct tagKEYSTRUCT
62 LPWSTR keyname; /* name of THIS key (UNICODE) */
63 DWORD flags; /* flags. */
66 DWORD nrofvalues; /* nr of values in THIS key */
67 LPKEYVALUE values; /* values in THIS key */
68 /* key management pointers */
69 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
70 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
71 } KEYSTRUCT, *LPKEYSTRUCT;
74 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
75 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
76 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
77 static KEYSTRUCT *key_users=NULL; /* all users? */
79 /* dynamic, not saved */
80 static KEYSTRUCT *key_performance_data=NULL;
81 static KEYSTRUCT *key_current_config=NULL;
82 static KEYSTRUCT *key_dyn_data=NULL;
84 /* what valuetypes do we need to convert? */
85 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
87 extern LPWSTR __cdecl CRTDLL_wcschr(LPWSTR a,WCHAR c);
89 static LPWSTR strdupA2W(LPCSTR src)
91 LPWSTR dest=xmalloc(2*strlen(src)+2);
92 lstrcpyAtoW(dest,src);
96 static LPWSTR strdupW(LPCWSTR a) {
100 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
101 b=(LPWSTR)xmalloc(len);
107 static struct openhandle {
112 static int nrofopenhandles=0;
113 static int currenthandle=1;
116 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
119 for (i=0;i<nrofopenhandles;i++) {
120 if (openhandles[i].lpkey==lpkey) {
121 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
123 if (openhandles[i].hkey==hkey) {
124 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
127 openhandles=xrealloc( openhandles,
128 sizeof(struct openhandle)*(nrofopenhandles+1)
130 openhandles[i].lpkey = lpkey;
131 openhandles[i].hkey = hkey;
132 openhandles[i].accessmask= accessmask;
137 get_handle(HKEY hkey) {
140 for (i=0;i<nrofopenhandles;i++)
141 if (openhandles[i].hkey==hkey)
142 return openhandles[i].lpkey;
143 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
148 remove_handle(HKEY hkey) {
151 for (i=0;i<nrofopenhandles;i++)
152 if (openhandles[i].hkey==hkey)
154 if (i==nrofopenhandles) {
155 dprintf_reg(stddeb,"remove_handle:Didn't find handle %08x?\n",hkey);
158 memcpy( openhandles+i,
160 sizeof(struct openhandle)*(nrofopenhandles-i-1)
162 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
168 /* debug function, converts a unicode into a static memory area
169 * (sub for using two static strings, in case we need them in a single call)
172 W2C(LPCWSTR x,int sub) {
173 static LPSTR unicodedebug[2]={NULL,NULL};
176 if (sub!=0 && sub!=1)
177 return "<W2C:bad sub>";
178 if (unicodedebug[sub]) HeapFree( SystemHeap, 0, unicodedebug[sub] );
179 unicodedebug[sub] = HEAP_strdupWtoA( SystemHeap, 0, x );
180 return unicodedebug[sub];
184 lookup_hkey(HKEY hkey) {
188 case HKEY_CLASSES_ROOT:
189 return key_classes_root;
190 case HKEY_CURRENT_USER:
191 return key_current_user;
192 case HKEY_LOCAL_MACHINE:
193 return key_local_machine;
196 case HKEY_PERFORMANCE_DATA:
197 return key_performance_data;
200 case HKEY_CURRENT_CONFIG:
201 return key_current_config;
203 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
206 return get_handle(hkey);
212 * splits the unicode string 'wp' into an array of strings.
213 * the array is allocated by this function.
214 * the number of components will be stored in 'wpc'
215 * Free the array using FREE_KEY_PATH
218 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
222 ws = HEAP_strdupW( SystemHeap, 0, wp );
224 for (i=0;ws[i];i++) {
231 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
239 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
242 * Shell initialisation, allocates keys.
244 void SHELL_StartupRegistry();
249 HKEY cl_r_hkey,c_u_hkey;
250 #define ADD_ROOT_KEY(xx) \
251 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
252 memset(xx,'\0',sizeof(KEYSTRUCT));\
253 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
255 ADD_ROOT_KEY(key_local_machine);
256 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
257 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
260 key_classes_root = lookup_hkey(cl_r_hkey);
262 ADD_ROOT_KEY(key_users);
265 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
266 * (later, when a win32 registry editing tool becomes avail.)
268 while (pwd=getpwent()) {
269 if (pwd->pw_name == NULL)
271 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
272 RegCloseKey(c_u_hkey);
275 pwd=getpwuid(getuid());
276 if (pwd && pwd->pw_name) {
277 RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey);
278 key_current_user = lookup_hkey(c_u_hkey);
280 ADD_ROOT_KEY(key_current_user);
282 ADD_ROOT_KEY(key_performance_data);
283 ADD_ROOT_KEY(key_current_config);
284 ADD_ROOT_KEY(key_dyn_data);
286 SHELL_StartupRegistry();
291 SHELL_StartupRegistry() {
294 char buf[200],cpubuf[200];
296 RegCreateKey16(HKEY_DYN_DATA,"\\PerfStats\\StatData",&xhkey);
299 RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
301 F=fopen("/proc/cpuinfo","r");
304 while (NULL!=fgets(buf,200,F)) {
305 if (sscanf(buf,"processor\t: %d",&x)) {
310 RegCreateKey16(hkey,buf,&xhkey);
312 if (sscanf(buf,"cpu\t\t: %s",cpubuf)) {
313 sprintf(buf,"CPU %s",cpubuf);
315 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
325 RegCreateKey16(hkey,"0",&xhkey);
326 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
328 RegOpenKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System",&hkey);
329 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
331 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
335 * string RegisteredOwner
336 * string RegisteredOrganization
339 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
344 if (-1!=gethostname(buf,200)) {
345 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&xhkey);
346 RegSetValueEx16(xhkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
350 /************************ SAVE Registry Function ****************************/
352 #define REGISTRY_SAVE_VERSION 0x00000001
354 /* Registry saveformat:
355 * If you change it, increase above number by 1, which will flush
356 * old registry database files.
359 * "WINE REGISTRY Version %d"
363 * valuename=lastmodified,type,data
367 * keyname,valuename,stringdata:
368 * the usual ascii characters from 0x00-0xff (well, not 0x00)
369 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
370 * ( "=\\\t" escaped in \uXXXX form.)
374 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
376 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
377 * SaveOnlyUpdatedKeys=yes
380 _save_check_tainted(LPKEYSTRUCT lpkey) {
385 if (lpkey->flags & REG_OPTION_TAINTED)
390 if (_save_check_tainted(lpkey->nextsub)) {
391 lpkey->flags |= REG_OPTION_TAINTED;
400 _save_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
413 if (escapeeq && *s=='=')
416 fputc(*s,F); /* if \\ then put it twice. */
418 fprintf(F,"\\u%04x",*((unsigned short*)s));
426 _savesubkey(FILE *F,LPKEYSTRUCT lpkey,int level,int all) {
432 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
433 (all || (lpxkey->flags & REG_OPTION_TAINTED))
435 for (tabs=level;tabs--;)
437 _save_USTRING(F,lpxkey->keyname,1);
439 for (i=0;i<lpxkey->nrofvalues;i++) {
440 LPKEYVALUE val=lpxkey->values+i;
442 for (tabs=level+1;tabs--;)
444 _save_USTRING(F,val->name,0);
446 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
447 if ((1<<val->type) & UNICONVMASK)
448 _save_USTRING(F,(LPWSTR)val->data,0);
450 for (j=0;j<val->len;j++)
451 fprintf(F,"%02x",*((unsigned char*)val->data+j));
454 /* descend recursively */
455 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
464 _savesubreg(FILE *F,LPKEYSTRUCT lpkey,int all) {
465 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
466 _save_check_tainted(lpkey->nextsub);
467 return _savesubkey(F,lpkey->nextsub,0,all);
471 _savereg(LPKEYSTRUCT lpkey,char *fn,int all) {
476 fprintf(stddeb,__FILE__":_savereg:Couldn't open %s for writing: %s\n",
481 if (!_savesubreg(F,lpkey,all)) {
484 fprintf(stddeb,__FILE__":_savereg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
492 SHELL_SaveRegistry() {
500 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
506 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
518 if (lstrcmpi32A(buf,"yes"))
520 pwd=getpwuid(getuid());
521 if (pwd!=NULL && pwd->pw_dir!=NULL)
525 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
526 strlen(SAVE_CURRENT_USER) + 2 );
527 strcpy(fn,pwd->pw_dir);
528 strcat(fn,WINE_PREFIX);
529 /* create the directory. don't care about errorcodes. */
530 mkdir(fn,0755); /* drwxr-xr-x */
531 strcat(fn,"/"SAVE_CURRENT_USER);
532 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
533 strcpy(tmp,fn);strcat(tmp,".tmp");
534 if (_savereg(key_current_user,tmp,all)) {
535 if (-1==rename(tmp,fn)) {
536 perror("rename tmp registry");
542 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
543 strcpy(fn,pwd->pw_dir);
544 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
545 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
546 strcpy(tmp,fn);strcat(tmp,".tmp");
547 if (_savereg(key_local_machine,tmp,all)) {
548 if (-1==rename(tmp,fn)) {
549 perror("rename tmp registry");
556 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
559 /************************ LOAD Registry Function ****************************/
562 _find_or_add_key(LPKEYSTRUCT lpkey,LPWSTR keyname) {
563 LPKEYSTRUCT lpxkey,*lplpkey;
565 lplpkey= &(lpkey->nextsub);
568 if (!lstrcmpi32W(lpxkey->keyname,keyname))
570 lplpkey = &(lpxkey->next);
574 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
576 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
577 lpxkey->keyname = keyname;
585 LPKEYSTRUCT lpkey,LPWSTR name,DWORD type,LPBYTE data,DWORD len,
591 if (name && !*name) {/* empty string equals default (NULL) value */
596 for (i=0;i<lpkey->nrofvalues;i++) {
602 if ( val->name!=NULL &&
603 !lstrcmpi32W(val->name,name)
608 if (i==lpkey->nrofvalues) {
609 lpkey->values = xrealloc(
611 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
614 memset(val,'\0',sizeof(KEYVALUE));
620 if (val->lastmodified<lastmodified) {
621 val->lastmodified=lastmodified;
632 /* reads a line including dynamically enlarging the readbuffer and throwing
636 _wine_read_line(FILE *F,char **buf,int *len) {
645 s=fgets(curread,mylen,F);
648 if (NULL==(s=strchr(curread,'\n'))) {
649 /* buffer wasn't large enough */
650 curoff = strlen(*buf);
651 *buf = xrealloc(*buf,*len*2);
652 curread = *buf + curoff;
653 mylen = *len; /* we filled up the buffer and
654 * got new '*len' bytes to fill
662 /* throw away comments */
663 if (**buf=='#' || **buf==';') {
668 if (s) /* got end of line */
674 /* converts a char* into a UNICODE string (up to a special char)
675 * and returns the position exactly after that string
678 _wine_read_USTRING(char *buf,LPWSTR *str) {
682 /* read up to "=" or "\0" or "\n" */
685 /* empty string is the win3.1 default value(NULL)*/
689 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
691 while (*s && (*s!='\n') && (*s!='=')) {
693 *ws++=*((unsigned char*)s++);
702 fprintf(stderr,"_wine_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
710 memcpy(xbuf,s,4);xbuf[4]='\0';
711 if (!sscanf(xbuf,"%x",&wc))
712 fprintf(stderr,"_wine_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
714 *ws++ =(unsigned short)wc;
721 *str = strdupW(*str);
730 FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen,int optflag
737 lpkey->flags |= optflag;
739 /* good. we already got a line here ... so parse it */
749 fprintf(stderr,"_load_subkey:Got a subhierarchy without resp. key?\n");
752 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
755 /* let the caller handle this line */
756 if (i<level || **buf=='\0')
759 /* it can be: a value or a keyname. Parse the name first */
760 s=_wine_read_USTRING(s,&name);
762 /* switch() default: hack to avoid gotos */
766 lpxkey=_find_or_add_key(lpkey,name);
769 int len,lastmodified,type;
772 fprintf(stderr,"_wine_load_subkey:unexpected character: %c\n",*s);
776 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
777 fprintf(stderr,"_wine_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
783 if ((1<<type) & UNICONVMASK) {
784 s=_wine_read_USTRING(s,(LPWSTR*)&data);
786 len = lstrlen32W((LPWSTR)data)*2+2;
791 data = (LPBYTE)xmalloc(len+1);
792 for (i=0;i<len;i++) {
794 if (*s>='0' && *s<='9')
796 if (*s>='a' && *s<='f')
798 if (*s>='A' && *s<='F')
801 if (*s>='0' && *s<='9')
803 if (*s>='a' && *s<='f')
805 if (*s>='A' && *s<='F')
810 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
813 /* read the next line */
814 if (!_wine_read_line(F,buf,buflen))
821 _wine_loadsubreg(FILE *F,LPKEYSTRUCT lpkey,int optflag) {
826 buf=xmalloc(10);buflen=10;
827 if (!_wine_read_line(F,&buf,&buflen)) {
831 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
835 if (ver!=REGISTRY_SAVE_VERSION) {
836 dprintf_reg(stddeb,__FILE__":_wine_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
840 if (!_wine_read_line(F,&buf,&buflen)) {
844 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
853 _wine_loadreg(LPKEYSTRUCT lpkey,char *fn,int optflag) {
858 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
863 if (!_wine_loadsubreg(F,lpkey,optflag)) {
872 _copy_registry(LPKEYSTRUCT from,LPKEYSTRUCT to) {
879 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
881 for (j=0;j<from->nrofvalues;j++) {
885 valfrom = from->values+j;
887 if (name) name=strdupW(name);
888 data=(LPBYTE)malloc(valfrom->len);
889 memcpy(data,valfrom->data,valfrom->len);
897 valfrom->lastmodified
900 _copy_registry(from,lpxkey);
905 /* WINDOWS 95 REGISTRY LOADER */
907 * Structure of a win95 registry database.
911 * 8 : DWORD offset_of_RGDB_part
912 * 0C..0F: ? (someone fill in please)
913 * 10: WORD number of RGDB blocks
915 * 14: WORD always 0000?
916 * 16: WORD always 0001?
917 * 18..1F: ? (someone fill in please)
922 * 4 : DWORD offset to first RGDB section
923 * 8 : DWORD offset to ?
924 * C..0x1B: ? (fill in)
925 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
927 * Disk Key Entry Structure:
928 * 00: DWORD - Free entry indicator(?)
929 * 04: DWORD - Hash = sum of bytes of keyname
930 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
931 * 0C: DWORD - disk address of PreviousLevel Key.
932 * 10: DWORD - disk address of Next Sublevel Key.
933 * 14: DWORD - disk address of Next Key (on same level).
934 * DKEP>18: WORD - Nr, Low Significant part.
935 * 1A: WORD - Nr, High Significant part.
937 * The disk address always points to the nr part of the previous key entry
938 * of the referenced key. Don't ask me why, or even if I got this correct
939 * from staring at 1kg of hexdumps. (DKEP)
941 * The High significant part of the structure seems to equal the number
942 * of the RGDB section. The low significant part is a unique ID within
945 * There are two minor corrections to the position of that structure.
946 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
947 * the DKE reread from there.
948 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
949 * CPS - I have not experienced the above phenomenon in my registry files
953 * 04: DWORD offset to next RGDB section
955 * 0C: WORD always 000d?
956 * 0E: WORD RGDB block number
957 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
962 * 00: DWORD nextkeyoffset - offset to the next disk key structure
963 * 08: WORD nrLS - low significant part of NR
964 * 0A: WORD nrHS - high significant part of NR
965 * 0C: DWORD bytesused - bytes used in this structure.
966 * 10: WORD name_len - length of name in bytes. without \0
967 * 12: WORD nr_of_values - number of values.
968 * 14: char name[name_len] - name string. No \0.
969 * 14+name_len: disk values
970 * nextkeyoffset: ... next disk key
973 * 00: DWORD type - value type (hmm, could be WORD too)
974 * 04: DWORD - unknown, usually 0
975 * 08: WORD namelen - length of Name. 0 means name=NULL
976 * 0C: WORD datalen - length of Data.
977 * 10: char name[namelen] - name, no \0
978 * 10+namelen: BYTE data[datalen] - data, without \0 if string
979 * 10+namelen+datalen: next values or disk key
981 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
982 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
983 * structure) and reading another RGDB_section.
984 * repeat until end of file.
986 * An interesting relationship exists in RGDB_section. The value at offset
987 * 10 equals the value at offset 4 minus the value at offset 8. I have no
988 * idea at the moment what this means. (Kevin Cozens)
990 * FIXME: this description needs some serious help, yes.
993 struct _w95keyvalue {
995 unsigned short datalen;
1005 struct _w95keyvalue *values;
1006 struct _w95key *prevlvl;
1007 struct _w95key *nextsub;
1008 struct _w95key *next;
1021 LPWSTR strcvtA2W(LPCSTR src, int nchars)
1024 LPWSTR dest = xmalloc (2 * nchars + 2);
1026 lstrcpynAtoW(dest,src, nchars);
1031 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1032 int nrLS, int nrMS, struct _w95_info *info )
1035 /* Disk Key Header structure (RGDB part) */
1037 unsigned long nextkeyoff;
1038 unsigned short nrLS;
1039 unsigned short nrMS;
1040 unsigned long bytesused;
1041 unsigned short keynamelen;
1042 unsigned short values;
1045 /* disk key values or nothing */
1047 /* Disk Key Value structure */
1051 unsigned short valnamelen;
1052 unsigned short valdatalen;
1053 /* valname, valdata */
1059 char *rgdbdata = info->rgdbbuffer;
1060 int nbytes = info->rgdbsize;
1061 char *curdata = rgdbdata;
1062 char *end = rgdbdata + nbytes;
1064 char *next = rgdbdata;
1070 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1072 memcpy(&off_next_rgdb,curdata+4,4);
1073 next = curdata + off_next_rgdb;
1074 nrgdb = (int) *((short *)curdata + 7);
1076 } while (nrgdb != nrMS && (next < end));
1078 /* curdata now points to the start of the right RGDB section */
1081 #define XREAD(whereto,len) \
1082 if ((curdata + len) <end) {\
1083 memcpy(whereto,curdata,len);\
1089 XREAD(&dkh, sizeof (dkh));
1090 if (dkh.nrLS == nrLS) break;
1092 curdata += dkh.nextkeyoff - sizeof(dkh);
1093 } while (curdata < next);
1095 if (dkh.nrLS != nrLS) return (NULL);
1097 if (nrgdb != dkh.nrMS) {
1101 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1102 curdata += dkh.keynamelen;
1104 for (i=0;i< dkh.values; i++) {
1110 XREAD(&dkv,sizeof(dkv));
1112 name = strcvtA2W(curdata, dkv.valnamelen);
1113 curdata += dkv.valnamelen;
1115 if ((1 << dkv.type) & UNICONVMASK) {
1116 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1117 len = dkv.valdatalen + 1;
1119 /* I don't think we want to NULL terminate all data */
1120 data = xmalloc(dkv.valdatalen);
1121 memcpy (data, curdata, dkv.valdatalen);
1122 len = dkv.valdatalen;
1125 curdata += dkv.valdatalen;
1142 _w95_walkrgkn(LPKEYSTRUCT prevkey, char *off, struct _w95_info *info)
1145 /* Disk Key Entry structure (RGKN part) */
1149 unsigned long x3;/*usually 0xFFFFFFFF */
1150 unsigned long prevlvl;
1151 unsigned long nextsub;
1153 unsigned short nrLS;
1154 unsigned short nrMS;
1155 } *dke = (struct dke *)off;
1159 dke = (struct dke *) ((char *)info->rgknbuffer);
1162 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1163 /* XXX <-- This is a hack*/
1168 if (dke->nextsub != -1 &&
1169 ((dke->nextsub - 0x20) < info->rgknsize)
1170 && (dke->nextsub > 0x20)) {
1172 _w95_walkrgkn(lpxkey,
1173 info->rgknbuffer + dke->nextsub - 0x20,
1177 if (dke->next != -1 &&
1178 ((dke->next - 0x20) < info->rgknsize) &&
1179 (dke->next > 0x20)) {
1180 _w95_walkrgkn(prevkey,
1181 info->rgknbuffer + dke->next - 0x20,
1189 _w95_loadreg(char* fn,LPKEYSTRUCT lpkey) {
1192 unsigned long where,version,rgdbsection,end;
1193 struct _w95_info info;
1195 BY_HANDLE_FILE_INFORMATION hfdinfo;
1197 dprintf_reg(stddeb,"Loading Win95 registry database '%s'\n",fn);
1198 hfd=OpenFile32(fn,&ofs,OF_READ);
1199 if (hfd==HFILE_ERROR32)
1202 if (4!=_lread32(hfd,magic,4))
1204 if (strcmp(magic,"CREG")) {
1205 fprintf(stddeb,"%s is not a w95 registry.\n",fn);
1208 if (4!=_lread32(hfd,&version,4))
1210 if (4!=_lread32(hfd,&rgdbsection,4))
1212 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1214 if (4!=_lread32(hfd,magic,4))
1216 if (strcmp(magic,"RGKN")) {
1217 dprintf_reg(stddeb,"second IFF header not RGKN, but %s\n",magic);
1221 /* STEP 1: Keylink structures */
1222 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1227 info.rgknsize = end - where;
1228 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1229 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1232 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1235 end = hfdinfo.nFileSizeLow;
1236 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1238 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1241 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1242 info.rgdbsize = end - rgdbsection;
1244 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1248 _w95_walkrgkn(lpkey, NULL, &info);
1250 free (info.rgdbbuffer);
1251 free (info.rgknbuffer);
1254 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1257 reghack - windows 3.11 registry data format demo program.
1259 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1260 a combined hash table and tree description, and finally a text table.
1262 The header is obvious from the struct header. The taboff1 and taboff2
1263 fields are always 0x20, and their usage is unknown.
1265 The 8-byte entry table has various entry types.
1267 tabent[0] is a root index. The second word has the index of the root of
1269 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1270 the index of the key/value that has that hash. Data with the same
1271 hash value are on a circular list. The other three words in the
1272 hash entry are always zero.
1273 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1274 entry: dirent and keyent/valent. They are identified by context.
1275 tabent[freeidx] is the first free entry. The first word in a free entry
1276 is the index of the next free entry. The last has 0 as a link.
1277 The other three words in the free list are probably irrelevant.
1279 Entries in text table are preceeded by a word at offset-2. This word
1280 has the value (2*index)+1, where index is the referring keyent/valent
1281 entry in the table. I have no suggestion for the 2* and the +1.
1282 Following the word, there are N bytes of data, as per the keyent/valent
1283 entry length. The offset of the keyent/valent entry is from the start
1284 of the text table to the first data byte.
1286 This information is not available from Microsoft. The data format is
1287 deduced from the reg.dat file by me. Mistakes may
1288 have been made. I claim no rights and give no guarantees for this program.
1290 Tor Sjøwall, tor@sn.no
1293 /* reg.dat header format */
1294 struct _w31_header {
1295 char cookie[8]; /* 'SHCC3.10' */
1296 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1297 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1298 unsigned long tabcnt; /* number of entries in index table */
1299 unsigned long textoff; /* offset of text part */
1300 unsigned long textsize; /* byte size of text part */
1301 unsigned short hashsize; /* hash size */
1302 unsigned short freeidx; /* free index */
1305 /* generic format of table entries */
1306 struct _w31_tabent {
1307 unsigned short w0, w1, w2, w3;
1310 /* directory tabent: */
1311 struct _w31_dirent {
1312 unsigned short sibling_idx; /* table index of sibling dirent */
1313 unsigned short child_idx; /* table index of child dirent */
1314 unsigned short key_idx; /* table index of key keyent */
1315 unsigned short value_idx; /* table index of value valent */
1319 struct _w31_keyent {
1320 unsigned short hash_idx; /* hash chain index for string */
1321 unsigned short refcnt; /* reference count */
1322 unsigned short length; /* length of string */
1323 unsigned short string_off; /* offset of string in text table */
1327 struct _w31_valent {
1328 unsigned short hash_idx; /* hash chain index for string */
1329 unsigned short refcnt; /* reference count */
1330 unsigned short length; /* length of string */
1331 unsigned short string_off; /* offset of string in text table */
1334 /* recursive helper function to display a directory tree */
1336 __w31_dumptree( unsigned short idx,
1338 struct _w31_tabent *tab,
1339 struct _w31_header *head,
1341 time_t lastmodified,
1344 struct _w31_dirent *dir;
1345 struct _w31_keyent *key;
1346 struct _w31_valent *val;
1347 LPKEYSTRUCT xlpkey = NULL;
1349 static char tail[400];
1352 dir=(struct _w31_dirent*)&tab[idx];
1355 key = (struct _w31_keyent*)&tab[dir->key_idx];
1357 memcpy(tail,&txt[key->string_off],key->length);
1358 tail[key->length]='\0';
1359 /* all toplevel entries AND the entries in the
1360 * toplevel subdirectory belong to \SOFTWARE\Classes
1362 if (!level && !lstrcmp32A(tail,".classes")) {
1363 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1364 idx=dir->sibling_idx;
1367 name=strdupA2W(tail);
1369 xlpkey=_find_or_add_key(lpkey,name);
1371 /* only add if leaf node or valued node */
1372 if (dir->value_idx!=0||dir->child_idx==0) {
1373 if (dir->value_idx) {
1374 val=(struct _w31_valent*)&tab[dir->value_idx];
1375 memcpy(tail,&txt[val->string_off],val->length);
1376 tail[val->length]='\0';
1377 value=strdupA2W(tail);
1378 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1382 dprintf_reg(stddeb,"__w31_dumptree:strange: no directory key name, idx=%04x\n", idx);
1384 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1385 idx=dir->sibling_idx;
1392 struct _w31_header head;
1393 struct _w31_tabent *tab;
1397 BY_HANDLE_FILE_INFORMATION hfinfo;
1398 time_t lastmodified;
1402 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1403 if (hf==HFILE_ERROR32)
1406 /* read & dump header */
1407 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1408 dprintf_reg(stddeb,"_w31_loadreg:reg.dat is too short.\n");
1412 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1413 dprintf_reg(stddeb,"_w31_loadreg:reg.dat has bad signature.\n");
1418 len = head.tabcnt * sizeof(struct _w31_tabent);
1419 /* read and dump index table */
1421 if (len!=_lread32(hf,tab,len)) {
1422 dprintf_reg(stderr,"_w31_loadreg:couldn't read %d bytes.\n",len);
1429 txt = xmalloc(head.textsize);
1430 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1431 dprintf_reg(stderr,"_w31_loadreg:couldn't seek to textblock.\n");
1437 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1438 dprintf_reg(stderr,"_w31_loadreg:textblock too short (%d instead of %ld).\n",len,head.textsize);
1445 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1446 dprintf_reg(stderr,"_w31_loadreg:GetFileInformationByHandle failed?.\n");
1452 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1454 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&hkey)!=ERROR_SUCCESS)
1456 lpkey = lookup_hkey(hkey);
1457 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1465 SHELL_LoadRegistry() {
1472 if (key_classes_root==NULL)
1475 /* Load windows 3.1 entries */
1477 /* Load windows 95 entries */
1478 _w95_loadreg("C:\\system.1st", key_local_machine);
1479 _w95_loadreg("system.dat", key_local_machine);
1480 _w95_loadreg("user.dat", key_users);
1482 /* the global user default is loaded under HKEY_USERS\\.Default */
1483 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1484 lpkey = lookup_hkey(hkey);
1485 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1487 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1488 _copy_registry(lpkey,key_current_user);
1491 /* the global machine defaults */
1492 _wine_loadreg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT,0);
1494 /* load the user saved registries */
1496 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1498 pwd=getpwuid(getuid());
1499 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1500 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1501 strcpy(fn,pwd->pw_dir);
1502 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1503 _wine_loadreg(key_current_user,fn,REG_OPTION_TAINTED);
1505 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1506 strcpy(fn,pwd->pw_dir);
1507 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1508 _wine_loadreg(key_local_machine,fn,REG_OPTION_TAINTED);
1511 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
1512 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1513 DWORD junk,type,len;
1517 if (( RegQueryValueEx32A(
1524 )!=ERROR_SUCCESS) ||
1527 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1533 /********************* API FUNCTIONS ***************************************/
1537 * All functions are stubs to RegOpenKeyEx32W where all the
1540 * FIXME: security,options,desiredaccess,...
1543 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1544 * RegOpenKey32W -> RegOpenKeyEx32W
1547 /* RegOpenKeyExW [ADVAPI32.150] */
1548 DWORD WINAPI RegOpenKeyEx32W(
1555 LPKEYSTRUCT lpNextKey,lpxkey;
1558 dprintf_reg(stddeb,"RegOpenKeyEx32W(%lx,%s,%ld,%lx,%p)\n",
1559 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
1562 lpNextKey = lookup_hkey(hkey);
1564 return SHELL_ERROR_BADKEY;
1565 if (!lpszSubKey || !*lpszSubKey) {
1566 add_handle(++currenthandle,lpNextKey,samDesired);
1567 *retkey=currenthandle;
1568 return SHELL_ERROR_SUCCESS;
1570 split_keypath(lpszSubKey,&wps,&wpc);
1572 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1575 lpxkey=lpNextKey->nextsub;
1577 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1579 lpxkey=lpxkey->next;
1583 return SHELL_ERROR_BADKEY;
1588 add_handle(++currenthandle,lpxkey,samDesired);
1589 *retkey = currenthandle;
1591 return SHELL_ERROR_SUCCESS;
1594 /* RegOpenKeyW [ADVAPI32.151] */
1595 DWORD WINAPI RegOpenKey32W(
1600 dprintf_reg(stddeb,"RegOpenKey32W(%lx,%s,%p)\n",
1601 (LONG)hkey,W2C(lpszSubKey,0),retkey
1603 return RegOpenKeyEx32W(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1607 /* RegOpenKeyExA [ADVAPI32.149] */
1608 DWORD WINAPI RegOpenKeyEx32A(
1618 dprintf_reg(stddeb,"RegOpenKeyEx32A(%lx,%s,%ld,%lx,%p)\n",
1619 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
1622 lpszSubKeyW=strdupA2W(lpszSubKey);
1625 ret=RegOpenKeyEx32W(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
1631 /* RegOpenKeyA [ADVAPI32.148] */
1632 DWORD WINAPI RegOpenKey32A(
1637 dprintf_reg(stddeb,"RegOpenKey32A(%lx,%s,%p)\n",
1638 (LONG)hkey,lpszSubKey,retkey
1640 return RegOpenKeyEx32A(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
1643 /* RegOpenKey [SHELL.1] [KERNEL.217] */
1644 DWORD WINAPI RegOpenKey16(
1649 dprintf_reg(stddeb,"RegOpenKey16(%lx,%s,%p)\n",
1650 (LONG)hkey,lpszSubKey,retkey
1652 return RegOpenKey32A(hkey,lpszSubKey,retkey);
1658 * All those functions convert their respective
1659 * arguments and call RegCreateKeyExW at the end.
1661 * FIXME: no security,no access attrib,no optionhandling yet.
1664 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKeyEx32A \
1665 * RegCreateKey32W -> RegCreateKeyEx32W
1668 /* RegCreateKeyExW [ADVAPI32.131] */
1669 DWORD WINAPI RegCreateKeyEx32W(
1676 LPSECURITY_ATTRIBUTES lpSecAttribs,
1680 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1684 /*FIXME: handle security/access/whatever */
1685 dprintf_reg(stddeb,"RegCreateKeyEx32W(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1697 lpNextKey = lookup_hkey(hkey);
1699 return SHELL_ERROR_BADKEY;
1700 if (!lpszSubKey || !*lpszSubKey) {
1701 add_handle(++currenthandle,lpNextKey,samDesired);
1702 *retkey=currenthandle;
1703 lpNextKey->flags|=REG_OPTION_TAINTED;
1704 return SHELL_ERROR_SUCCESS;
1706 split_keypath(lpszSubKey,&wps,&wpc);
1708 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1711 lpxkey=lpNextKey->nextsub;
1713 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
1715 lpxkey=lpxkey->next;
1723 add_handle(++currenthandle,lpxkey,samDesired);
1724 lpxkey->flags |= REG_OPTION_TAINTED;
1725 *retkey = currenthandle;
1727 *lpDispos = REG_OPENED_EXISTING_KEY;
1729 return SHELL_ERROR_SUCCESS;
1731 /* good. now the hard part */
1733 lplpPrevKey = &(lpNextKey->nextsub);
1734 lpxkey = *lplpPrevKey;
1736 lplpPrevKey = &(lpxkey->next);
1737 lpxkey = *lplpPrevKey;
1739 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
1740 if (!*lplpPrevKey) {
1742 return SHELL_ERROR_OUTOFMEMORY;
1744 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
1745 (*lplpPrevKey)->keyname = strdupW(wps[i]);
1746 (*lplpPrevKey)->next = NULL;
1747 (*lplpPrevKey)->nextsub = NULL;
1748 (*lplpPrevKey)->values = NULL;
1749 (*lplpPrevKey)->nrofvalues = 0;
1750 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
1752 (*lplpPrevKey)->class = strdupW(lpszClass);
1754 (*lplpPrevKey)->class = NULL;
1755 lpNextKey = *lplpPrevKey;
1758 add_handle(++currenthandle,lpNextKey,samDesired);
1760 /*FIXME: flag handling correct? */
1761 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
1763 lpNextKey->class = strdupW(lpszClass);
1765 lpNextKey->class = NULL;
1766 *retkey = currenthandle;
1768 *lpDispos = REG_CREATED_NEW_KEY;
1770 return SHELL_ERROR_SUCCESS;
1773 /* RegCreateKeyW [ADVAPI32.132] */
1774 DWORD WINAPI RegCreateKey32W(
1781 dprintf_reg(stddeb,"RegCreateKey32W(%lx,%s,%p)\n",
1782 (LONG)hkey,W2C(lpszSubKey,0),retkey
1784 ret=RegCreateKeyEx32W(
1785 hkey, /* key handle */
1786 lpszSubKey, /* subkey name */
1787 0, /* reserved = 0 */
1788 NULL, /* lpszClass? FIXME: ? */
1789 REG_OPTION_NON_VOLATILE, /* options */
1790 KEY_ALL_ACCESS, /* desired access attribs */
1791 NULL, /* lpsecurity attributes */
1792 retkey, /* lpretkey */
1793 &junk /* disposition value */
1798 /* RegCreateKeyExA [ADVAPI32.130] */
1799 DWORD WINAPI RegCreateKeyEx32A(
1806 LPSECURITY_ATTRIBUTES lpSecAttribs,
1810 LPWSTR lpszSubKeyW,lpszClassW;
1813 dprintf_reg(stddeb,"RegCreateKeyEx32A(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1825 lpszSubKeyW=strdupA2W(lpszSubKey);
1829 lpszClassW=strdupA2W(lpszClass);
1832 ret=RegCreateKeyEx32W(
1850 /* RegCreateKeyA [ADVAPI32.129] */
1851 DWORD WINAPI RegCreateKey32A(
1858 dprintf_reg(stddeb,"RegCreateKey32A(%lx,%s,%p)\n",
1859 (LONG)hkey,lpszSubKey,retkey
1861 return RegCreateKeyEx32A(
1862 hkey, /* key handle */
1863 lpszSubKey, /* subkey name */
1864 0, /* reserved = 0 */
1865 NULL, /* lpszClass? FIXME: ? */
1866 REG_OPTION_NON_VOLATILE,/* options */
1867 KEY_ALL_ACCESS, /* desired access attribs */
1868 NULL, /* lpsecurity attributes */
1869 retkey, /* lpretkey */
1870 &junk /* disposition value */
1874 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1875 DWORD WINAPI RegCreateKey16(
1880 dprintf_reg(stddeb,"RegCreateKey16(%lx,%s,%p)\n",
1881 (LONG)hkey,lpszSubKey,retkey
1883 return RegCreateKey32A(hkey,lpszSubKey,retkey);
1887 * Query Value Functions
1888 * Win32 differs between keynames and valuenames.
1889 * multiple values may belong to one key, the special value
1890 * with name NULL is the default value used by the win31
1894 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
1895 * RegQueryValue32W -> RegQueryValueEx32W
1898 /* RegQueryValueExW [ADVAPI32.158] */
1899 DWORD WINAPI RegQueryValueEx32W(
1901 LPWSTR lpszValueName,
1902 LPDWORD lpdwReserved,
1910 dprintf_reg(stddeb,"RegQueryValueEx32W(%x,%s,%p,%p,%p,%ld)\n",
1911 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,
1912 lpcbData?*lpcbData:0
1915 lpkey = lookup_hkey(hkey);
1917 return SHELL_ERROR_BADKEY;
1918 if (lpszValueName && !*lpszValueName)
1919 lpszValueName = NULL;
1920 if (lpszValueName==NULL) {
1921 for (i=0;i<lpkey->nrofvalues;i++)
1922 if (lpkey->values[i].name==NULL)
1925 for (i=0;i<lpkey->nrofvalues;i++)
1926 if ( lpkey->values[i].name &&
1927 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
1931 if (i==lpkey->nrofvalues) {
1932 if (lpszValueName==NULL) {
1934 *(WCHAR*)lpbData = 0;
1939 return SHELL_ERROR_SUCCESS;
1941 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1944 *lpdwType = lpkey->values[i].type;
1945 if (lpbData==NULL) {
1947 return SHELL_ERROR_SUCCESS;
1948 *lpcbData = lpkey->values[i].len;
1949 return SHELL_ERROR_SUCCESS;
1951 if (*lpcbData<lpkey->values[i].len) {
1954 *lpcbData = lpkey->values[i].len;
1955 return ERROR_MORE_DATA;
1957 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1958 *lpcbData = lpkey->values[i].len;
1959 return SHELL_ERROR_SUCCESS;
1962 /* RegQueryValueW [ADVAPI32.159] */
1963 DWORD WINAPI RegQueryValue32W(
1972 dprintf_reg(stddeb,"RegQueryValue32W(%x,%s,%p,%ld)\n->",
1973 hkey,W2C(lpszSubKey,0),lpszData,
1974 lpcbData?*lpcbData:0
1977 /* only open subkey, if we really do descend */
1978 if (lpszSubKey && *lpszSubKey) {
1979 ret = RegOpenKey32W(hkey,lpszSubKey,&xhkey);
1980 if (ret!=ERROR_SUCCESS)
1986 ret = RegQueryValueEx32W(
1988 NULL, /* varname NULL -> compat */
1989 NULL, /* lpdwReserved, must be NULL */
1999 /* RegQueryValueExA [ADVAPI32.157] */
2000 DWORD WINAPI RegQueryValueEx32A(
2002 LPSTR lpszValueName,
2003 LPDWORD lpdwReserved,
2008 LPWSTR lpszValueNameW;
2014 dprintf_reg(stddeb,"RegQueryValueEx32A(%x,%s,%p,%p,%p,%ld)\n->",
2015 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2016 lpcbData?*lpcbData:0
2019 lpszValueNameW=strdupA2W(lpszValueName);
2021 lpszValueNameW=NULL;
2030 ret=RegQueryValueEx32W(
2039 if (ret==ERROR_MORE_DATA) {
2040 buf = (LPBYTE)xmalloc(*mylen);
2042 buf = (LPBYTE)xmalloc(2*(*lpcbData));
2043 myxlen = 2*(*lpcbData);
2048 myxlen = *lpcbData*2;
2053 ret=RegQueryValueEx32W(
2063 if (ret==ERROR_SUCCESS) {
2065 if (UNICONVMASK & (1<<(type))) {
2066 /* convert UNICODE to ASCII */
2067 lstrcpyWtoA(lpbData,(LPWSTR)buf);
2068 *lpcbData = myxlen/2;
2070 if (myxlen>*lpcbData)
2071 ret = ERROR_MORE_DATA;
2073 memcpy(lpbData,buf,myxlen);
2078 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2079 *lpcbData = myxlen/2;
2082 if ((UNICONVMASK & (1<<(type))) && lpcbData)
2083 *lpcbData = myxlen/2;
2090 /* RegQueryValueEx [KERNEL.225] */
2091 DWORD WINAPI RegQueryValueEx16(
2093 LPSTR lpszValueName,
2094 LPDWORD lpdwReserved,
2099 dprintf_reg(stddeb,"RegQueryValueEx16(%x,%s,%p,%p,%p,%ld)\n",
2100 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,
2101 lpcbData?*lpcbData:0
2103 return RegQueryValueEx32A(
2113 /* RegQueryValueA [ADVAPI32.156] */
2114 DWORD WINAPI RegQueryValue32A(
2123 dprintf_reg(stddeb,"RegQueryValue32A(%x,%s,%p,%ld)\n",
2124 hkey,lpszSubKey,lpszData,
2125 lpcbData?*lpcbData:0
2128 /* only open subkey, if we really do descend */
2129 if (lpszSubKey && *lpszSubKey) {
2130 ret = RegOpenKey16(hkey,lpszSubKey,&xhkey);
2131 if (ret!=ERROR_SUCCESS)
2137 ret = RegQueryValueEx32A(
2139 NULL, /* lpszValueName NULL -> compat */
2140 NULL, /* lpdwReserved, must be NULL */
2150 /* RegQueryValue [SHELL.6] [KERNEL.224] */
2151 DWORD WINAPI RegQueryValue16(
2157 dprintf_reg(stddeb,"RegQueryValue16(%x,%s,%p,%ld)\n",
2158 hkey,lpszSubKey,lpszData,lpcbData?*lpcbData:0
2160 /* HACK: the 16bit RegQueryValue doesn't handle selectorblocks
2161 * anyway, so we just mask out the high 16 bit.
2162 * (this (not so much incidently;) hopefully fixes Aldus FH4)
2165 *lpcbData &= 0xFFFF;
2166 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2170 * Setting values of Registry keys
2173 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2174 * RegSetValue32W -> RegSetValueEx32W
2177 /* RegSetValueExW [ADVAPI32.170] */
2178 DWORD WINAPI RegSetValueEx32W(
2180 LPWSTR lpszValueName,
2189 dprintf_reg(stddeb,"RegSetValueEx32W(%x,%s,%ld,%ld,%p,%ld)\n",
2190 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
2192 /* we no longer care about the lpbData type here... */
2193 lpkey = lookup_hkey(hkey);
2195 return SHELL_ERROR_BADKEY;
2197 lpkey->flags |= REG_OPTION_TAINTED;
2199 if (lpszValueName==NULL) {
2200 for (i=0;i<lpkey->nrofvalues;i++)
2201 if (lpkey->values[i].name==NULL)
2204 for (i=0;i<lpkey->nrofvalues;i++)
2205 if ( lpkey->values[i].name &&
2206 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2210 if (i==lpkey->nrofvalues) {
2211 lpkey->values = (LPKEYVALUE)xrealloc(
2213 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2215 lpkey->nrofvalues++;
2216 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2218 if (lpkey->values[i].name==NULL)
2220 lpkey->values[i].name = strdupW(lpszValueName);
2222 lpkey->values[i].name = NULL;
2223 lpkey->values[i].len = cbData;
2224 lpkey->values[i].type = dwType;
2225 if (lpkey->values[i].data !=NULL)
2226 free(lpkey->values[i].data);
2227 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2228 lpkey->values[i].lastmodified = time(NULL);
2229 memcpy(lpkey->values[i].data,lpbData,cbData);
2230 return SHELL_ERROR_SUCCESS;
2233 /* RegSetValueExA [ADVAPI32.169] */
2234 DWORD WINAPI RegSetValueEx32A(
2236 LPSTR lpszValueName,
2243 LPWSTR lpszValueNameW;
2246 dprintf_reg(stddeb,"RegSetValueEx32A(%x,%s,%ld,%ld,%p,%ld)\n->",
2247 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2249 if ((1<<dwType) & UNICONVMASK) {
2250 buf=(LPBYTE)strdupA2W(lpbData);
2251 cbData=2*strlen(lpbData)+2;
2255 lpszValueNameW = strdupA2W(lpszValueName);
2257 lpszValueNameW = NULL;
2258 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2260 free(lpszValueNameW);
2266 /* RegSetValueEx [KERNEL.226] */
2267 DWORD WINAPI RegSetValueEx16(
2269 LPSTR lpszValueName,
2275 dprintf_reg(stddeb,"RegSetValueEx16(%x,%s,%ld,%ld,%p,%ld)\n->",
2276 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
2278 return RegSetValueEx32A(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
2281 /* RegSetValueW [ADVAPI32.171] */
2282 DWORD WINAPI RegSetValue32W(
2292 dprintf_reg(stddeb,"RegSetValue32W(%x,%s,%ld,%s,%ld)\n->",
2293 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
2295 if (lpszSubKey && *lpszSubKey) {
2296 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2297 if (ret!=ERROR_SUCCESS)
2301 if (dwType!=REG_SZ) {
2302 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
2305 if (cbData!=2*lstrlen32W(lpszData)+2) {
2306 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
2307 cbData,W2C(lpszData,0),2*lstrlen32W(lpszData)+2
2309 cbData=2*lstrlen32W(lpszData)+2;
2311 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2317 /* RegSetValueA [ADVAPI32.168] */
2318 DWORD WINAPI RegSetValue32A(
2328 dprintf_reg(stddeb,"RegSetValue32A(%x,%s,%ld,%s,%ld)\n->",
2329 hkey,lpszSubKey,dwType,lpszData,cbData
2331 if (lpszSubKey && *lpszSubKey) {
2332 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2333 if (ret!=ERROR_SUCCESS)
2338 if (dwType!=REG_SZ) {
2339 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
2342 if (cbData!=strlen(lpszData)+1)
2343 cbData=strlen(lpszData)+1;
2344 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2350 /* RegSetValue [KERNEL.221] [SHELL.5] */
2351 DWORD WINAPI RegSetValue16(
2359 dprintf_reg(stddeb,"RegSetValue16(%x,%s,%ld,%s,%ld)\n->",
2360 hkey,lpszSubKey,dwType,lpszData,cbData
2362 ret=RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2370 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2371 * RegEnumKey32W -> RegEnumKeyEx32W
2374 /* RegEnumKeyExW [ADVAPI32.139] */
2375 DWORD WINAPI RegEnumKeyEx32W(
2380 LPDWORD lpdwReserved,
2385 LPKEYSTRUCT lpkey,lpxkey;
2387 dprintf_reg(stddeb,"RegEnumKeyEx32W(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2388 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2390 lpkey=lookup_hkey(hkey);
2392 return SHELL_ERROR_BADKEY;
2393 if (!lpkey->nextsub)
2394 return ERROR_NO_MORE_ITEMS;
2395 lpxkey=lpkey->nextsub;
2396 while (iSubkey && lpxkey) {
2398 lpxkey=lpxkey->next;
2400 if (iSubkey || !lpxkey)
2401 return ERROR_NO_MORE_ITEMS;
2402 if (2*lstrlen32W(lpxkey->keyname)+2>*lpcchName)
2403 return ERROR_MORE_DATA;
2404 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2406 /* what should we write into it? */
2410 return ERROR_SUCCESS;
2414 /* RegEnumKeyW [ADVAPI32.140] */
2415 DWORD WINAPI RegEnumKey32W(
2423 dprintf_reg(stddeb,"RegEnumKey32W(%x,%ld,%p,%ld)\n->",
2424 hkey,iSubkey,lpszName,lpcchName
2426 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2428 /* RegEnumKeyExA [ADVAPI32.138] */
2429 DWORD WINAPI RegEnumKeyEx32A(
2434 LPDWORD lpdwReserved,
2439 DWORD ret,lpcchNameW,lpcchClassW;
2440 LPWSTR lpszNameW,lpszClassW;
2443 dprintf_reg(stddeb,"RegEnumKeyEx32A(%x,%ld,%p,%ld,%p,%p,%p,%p)\n->",
2444 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2447 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2448 lpcchNameW = *lpcchName*2;
2454 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2455 lpcchClassW = *lpcchClass*2;
2460 ret=RegEnumKeyEx32W(
2470 if (ret==ERROR_SUCCESS) {
2471 lstrcpyWtoA(lpszName,lpszNameW);
2472 *lpcchName=strlen(lpszName);
2474 lstrcpyWtoA(lpszClass,lpszClassW);
2475 *lpcchClass=strlen(lpszClass);
2485 /* RegEnumKeyA [ADVAPI32.137] */
2486 DWORD WINAPI RegEnumKey32A(
2494 dprintf_reg(stddeb,"RegEnumKey32A(%x,%ld,%p,%ld)\n->",
2495 hkey,iSubkey,lpszName,lpcchName
2497 return RegEnumKeyEx32A(
2509 /* RegEnumKey [SHELL.7] [KERNEL.216] */
2510 DWORD WINAPI RegEnumKey16(
2516 dprintf_reg(stddeb,"RegEnumKey16(%x,%ld,%p,%ld)\n->",
2517 hkey,iSubkey,lpszName,lpcchName
2519 return RegEnumKey32A(hkey,iSubkey,lpszName,lpcchName);
2523 * Enumerate Registry Values
2526 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2529 /* RegEnumValueW [ADVAPI32.142] */
2530 DWORD WINAPI RegEnumValue32W(
2535 LPDWORD lpdReserved,
2543 dprintf_reg(stddeb,"RegEnumValue32W(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2544 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2546 lpkey = lookup_hkey(hkey);
2548 return SHELL_ERROR_BADKEY;
2549 if (lpkey->nrofvalues<=iValue)
2550 return ERROR_NO_MORE_ITEMS;
2551 val = lpkey->values+iValue;
2554 if (lstrlen32W(val->name)*2+2>*lpcchValue) {
2555 *lpcchValue = lstrlen32W(val->name)*2+2;
2556 return ERROR_MORE_DATA;
2558 memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
2559 *lpcchValue=lstrlen32W(val->name)*2+2;
2565 *lpdwType=val->type;
2567 if (val->len>*lpcbData)
2568 return ERROR_MORE_DATA;
2569 memcpy(lpbData,val->data,val->len);
2570 *lpcbData = val->len;
2572 return SHELL_ERROR_SUCCESS;
2575 /* RegEnumValueA [ADVAPI32.141] */
2576 DWORD WINAPI RegEnumValue32A(
2581 LPDWORD lpdReserved,
2588 DWORD ret,lpcbDataW;
2590 dprintf_reg(stddeb,"RegEnumValue32A(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2591 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2594 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2596 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2597 lpcbDataW = *lpcbData*2;
2600 ret=RegEnumValue32W(
2611 if (ret==ERROR_SUCCESS) {
2612 lstrcpyWtoA(lpszValue,lpszValueW);
2614 if ((1<<*lpdwType) & UNICONVMASK) {
2615 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2617 if (lpcbDataW > *lpcbData)
2618 ret = ERROR_MORE_DATA;
2620 memcpy(lpbData,lpbDataW,lpcbDataW);
2622 *lpcbData = lpcbDataW;
2632 /* RegEnumValue [KERNEL.223] */
2633 DWORD WINAPI RegEnumValue16(
2638 LPDWORD lpdReserved,
2643 dprintf_reg(stddeb,"RegEnumValue(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
2644 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
2646 return RegEnumValue32A(
2659 * Close registry key
2661 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
2662 DWORD WINAPI RegCloseKey(HKEY hkey) {
2663 dprintf_reg(stddeb,"RegCloseKey(%x)\n",hkey);
2664 remove_handle(hkey);
2665 return ERROR_SUCCESS;
2668 * Delete registry key
2671 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2673 /* RegDeleteKeyW [ADVAPI32.134] */
2674 DWORD WINAPI RegDeleteKey32W(HKEY hkey,LPWSTR lpszSubKey) {
2675 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2679 dprintf_reg(stddeb,"RegDeleteKey32W(%x,%s)\n",
2680 hkey,W2C(lpszSubKey,0)
2682 lpNextKey = lookup_hkey(hkey);
2684 dprintf_reg (stddeb, " Badkey[1].\n");
2685 return SHELL_ERROR_BADKEY;
2687 /* we need to know the previous key in the hier. */
2688 if (!lpszSubKey || !*lpszSubKey) {
2689 dprintf_reg (stddeb, " Badkey[2].\n");
2690 return SHELL_ERROR_BADKEY;
2692 split_keypath(lpszSubKey,&wps,&wpc);
2696 lpxkey=lpNextKey->nextsub;
2698 dprintf_reg (stddeb, " Scanning [%s]\n",
2699 W2C (lpxkey->keyname, 0));
2700 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2702 lpxkey=lpxkey->next;
2706 dprintf_reg (stddeb, " Not found.\n");
2707 /* not found is success */
2708 return SHELL_ERROR_SUCCESS;
2713 lpxkey = lpNextKey->nextsub;
2714 lplpPrevKey = &(lpNextKey->nextsub);
2716 dprintf_reg (stddeb, " Scanning [%s]\n",
2717 W2C (lpxkey->keyname, 0));
2718 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2720 lplpPrevKey = &(lpxkey->next);
2721 lpxkey = lpxkey->next;
2725 dprintf_reg (stddeb, " Not found.\n");
2726 return SHELL_ERROR_BADKEY;
2727 return SHELL_ERROR_SUCCESS;
2729 if (lpxkey->nextsub) {
2731 dprintf_reg (stddeb, " Not empty.\n");
2732 return SHELL_ERROR_CANTWRITE;
2734 *lplpPrevKey = lpxkey->next;
2735 free(lpxkey->keyname);
2737 free(lpxkey->class);
2739 free(lpxkey->values);
2742 dprintf_reg (stddeb, " Done.\n");
2743 return SHELL_ERROR_SUCCESS;
2746 /* RegDeleteKeyA [ADVAPI32.133] */
2747 DWORD WINAPI RegDeleteKey32A(HKEY hkey,LPCSTR lpszSubKey) {
2751 dprintf_reg(stddeb,"RegDeleteKey32A(%x,%s)\n",
2754 lpszSubKeyW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszSubKey);
2755 ret=RegDeleteKey32W(hkey,lpszSubKeyW);
2756 HeapFree(GetProcessHeap(),0,lpszSubKeyW);
2760 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
2761 DWORD WINAPI RegDeleteKey16(HKEY hkey,LPCSTR lpszSubKey) {
2762 dprintf_reg(stddeb,"RegDeleteKey16(%x,%s)\n",
2765 return RegDeleteKey32A(hkey,lpszSubKey);
2769 * Delete registry value
2772 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
2774 /* RegDeleteValueW [ADVAPI32.136] */
2775 DWORD WINAPI RegDeleteValue32W(HKEY hkey,LPWSTR lpszValue)
2781 dprintf_reg(stddeb,"RegDeleteValue32W(%x,%s)\n",
2782 hkey,W2C(lpszValue,0)
2784 lpkey=lookup_hkey(hkey);
2786 return SHELL_ERROR_BADKEY;
2788 for (i=0;i<lpkey->nrofvalues;i++)
2789 if ( lpkey->values[i].name &&
2790 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
2794 for (i=0;i<lpkey->nrofvalues;i++)
2795 if (lpkey->values[i].name==NULL)
2798 if (i==lpkey->nrofvalues)
2799 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
2800 val = lpkey->values+i;
2801 if (val->name) free(val->name);
2802 if (val->data) free(val->data);
2806 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
2808 lpkey->values = (LPKEYVALUE)xrealloc(
2810 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
2812 lpkey->nrofvalues--;
2813 return SHELL_ERROR_SUCCESS;
2816 /* RegDeleteValueA [ADVAPI32.135] */
2817 DWORD WINAPI RegDeleteValue32A(HKEY hkey,LPSTR lpszValue)
2822 dprintf_reg( stddeb, "RegDeleteValue32A(%x,%s)\n", hkey,lpszValue );
2823 lpszValueW=HEAP_strdupAtoW(GetProcessHeap(),0,lpszValue);
2824 ret=RegDeleteValue32W(hkey,lpszValueW);
2825 HeapFree(GetProcessHeap(),0,lpszValueW);
2829 /* RegDeleteValue [KERNEL.222] */
2830 DWORD WINAPI RegDeleteValue16(HKEY hkey,LPSTR lpszValue)
2832 dprintf_reg( stddeb,"RegDeleteValue16(%x,%s)\n", hkey,lpszValue );
2833 return RegDeleteValue32A(hkey,lpszValue);
2836 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
2837 DWORD WINAPI RegFlushKey(HKEY hkey)
2839 dprintf_reg(stddeb,"RegFlushKey(%x), STUB.\n",hkey);
2840 return SHELL_ERROR_SUCCESS;
2843 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2845 /* RegQueryInfoKeyW [ADVAPI32.153] */
2846 DWORD WINAPI RegQueryInfoKey32W(
2850 LPDWORD lpdwReserved,
2852 LPDWORD lpcchMaxSubkey,
2853 LPDWORD lpcchMaxClass,
2855 LPDWORD lpcchMaxValueName,
2856 LPDWORD lpccbMaxValueData,
2857 LPDWORD lpcbSecurityDescriptor,
2860 LPKEYSTRUCT lpkey,lpxkey;
2861 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2864 dprintf_reg(stddeb,"RegQueryInfoKey32W(%x,......)\n",hkey);
2865 lpkey=lookup_hkey(hkey);
2867 return SHELL_ERROR_BADKEY;
2870 if (lstrlen32W(lpkey->class)*2+2>*lpcchClass) {
2871 *lpcchClass=lstrlen32W(lpkey->class)*2;
2872 return ERROR_MORE_DATA;
2874 *lpcchClass=lstrlen32W(lpkey->class)*2;
2875 memcpy(lpszClass,lpkey->class,lstrlen32W(lpkey->class));
2882 *lpcchClass = lstrlen32W(lpkey->class)*2;
2884 lpxkey=lpkey->nextsub;
2885 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2888 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
2889 maxsubkey=lstrlen32W(lpxkey->keyname);
2890 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
2891 maxclass=lstrlen32W(lpxkey->class);
2892 if (lpxkey->nrofvalues>maxvalues)
2893 maxvalues=lpxkey->nrofvalues;
2894 for (i=0;i<lpxkey->nrofvalues;i++) {
2895 LPKEYVALUE val=lpxkey->values+i;
2897 if (val->name && lstrlen32W(val->name)>maxvname)
2898 maxvname=lstrlen32W(val->name);
2899 if (val->len>maxvdata)
2902 lpxkey=lpxkey->next;
2904 if (!maxclass) maxclass = 1;
2905 if (!maxvname) maxvname = 1;
2907 *lpcSubKeys = nrofkeys;
2909 *lpcchMaxSubkey = maxsubkey*2;
2911 *lpcchMaxClass = maxclass*2;
2913 *lpcValues = maxvalues;
2914 if (lpcchMaxValueName)
2915 *lpcchMaxValueName= maxvname;
2916 if (lpccbMaxValueData)
2917 *lpccbMaxValueData= maxvdata;
2918 return SHELL_ERROR_SUCCESS;
2921 /* RegQueryInfoKeyA [ADVAPI32.152] */
2922 DWORD WINAPI RegQueryInfoKey32A(
2926 LPDWORD lpdwReserved,
2928 LPDWORD lpcchMaxSubkey,
2929 LPDWORD lpcchMaxClass,
2931 LPDWORD lpcchMaxValueName,
2932 LPDWORD lpccbMaxValueData,
2933 LPDWORD lpcbSecurityDescriptor,
2939 dprintf_reg(stddeb,"RegQueryInfoKey32A(%x,......)\n",hkey);
2942 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2946 ret=RegQueryInfoKey32W(
2957 lpcbSecurityDescriptor,
2960 if (ret==ERROR_SUCCESS && lpszClass)
2961 lstrcpyWtoA(lpszClass,lpszClassW);
2968 if (lpcchMaxValueName)
2969 *lpcchMaxValueName/=2;
2974 /* RegConnectRegistryA [ADVAPI32.127] */
2975 DWORD WINAPI RegConnectRegistry32A(LPCSTR machine,HKEY hkey,LPHKEY reskey)
2977 fprintf(stderr,"RegConnectRegistry32A(%s,%08x,%p), STUB.\n",
2980 return ERROR_FILE_NOT_FOUND; /* FIXME */