4 * Copyright 1996 Marcus Meissner
13 #include <sys/types.h>
14 #include <sys/fcntl.h>
27 /* FIXME: following defines should be configured global ... */
29 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
30 #define WINE_PREFIX "/.wine"
31 #define SAVE_CURRENT_USER_DEFAULT "/usr/local/etc/wine.userreg"
32 /* relative in ~user/.wine/ */
33 #define SAVE_CURRENT_USER "user.reg"
34 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
35 /* relative in ~user/.wine/ */
36 #define SAVE_LOCAL_MACHINE "system.reg"
38 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
39 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
40 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
41 static KEYSTRUCT *key_users=NULL; /* all users? */
43 /* dynamic, not saved */
44 static KEYSTRUCT *key_performance_data=NULL;
45 static KEYSTRUCT *key_current_config=NULL;
46 static KEYSTRUCT *key_dyn_data=NULL;
48 /* what valuetypes do we need to convert? */
49 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
51 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
52 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
53 #define strdupW(x) STRING32_strdupW(x)
54 #define strcmpW(a,b) STRING32_lstrcmpW(a,b)
55 #define strcmpniW(a,b) STRING32_lstrcmpniW(a,b)
56 #define strchrW(a,c) STRING32_lstrchrW(a,c)
57 #define strlenW(a) STRING32_UniLen(a)
58 #define strcpyWA(a,b) STRING32_UniToAnsi(a,b)
60 static struct openhandle {
65 static int nrofopenhandles=0;
66 static int currenthandle=1;
69 add_handle(HKEY hkey,LPKEYSTRUCT lpkey,REGSAM accessmask) {
72 for (i=0;i<nrofopenhandles;i++) {
73 if (openhandles[i].lpkey==lpkey) {
74 dprintf_reg(stddeb,"add_handle:Tried to add %p twice!\n",lpkey);
76 if (openhandles[i].hkey==hkey) {
77 dprintf_reg(stddeb,"add_handle:Tried to add %lx twice!\n",(LONG)hkey);
80 openhandles=xrealloc( openhandles,
81 sizeof(struct openhandle)*(nrofopenhandles+1)
83 openhandles[i].lpkey = lpkey;
84 openhandles[i].hkey = hkey;
85 openhandles[i].accessmask= accessmask;
90 get_handle(HKEY hkey) {
93 for (i=0;i<nrofopenhandles;i++)
94 if (openhandles[i].hkey==hkey)
95 return openhandles[i].lpkey;
96 dprintf_reg(stddeb,"get_handle:Didn't find handle %lx?\n",(LONG)hkey);
101 remove_handle(HKEY hkey) {
104 for (i=0;i<nrofopenhandles;i++)
105 if (openhandles[i].hkey==hkey)
107 if (i==nrofopenhandles) {
108 dprintf_reg(stddeb,"remove_handle:Didn't find handle %lx?\n",hkey);
111 memcpy( openhandles+i,
113 sizeof(struct openhandle)*(nrofopenhandles-i-1)
115 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
121 /* debug function, converts a unicode into a static memory area
122 * (sub for using two static strings, in case we need them in a single call)
125 W2C(LPCWSTR x,int sub) {
126 static LPSTR unicodedebug[2]={NULL,NULL};
129 if (sub!=0 && sub!=1)
130 return "<W2C:bad sub>";
131 if (unicodedebug[sub]) free(unicodedebug[sub]);
132 unicodedebug[sub] = strdupW2A(x);
133 return unicodedebug[sub];
137 lookup_hkey(HKEY hkey) {
141 case HKEY_CLASSES_ROOT:
142 return key_classes_root;
143 case HKEY_CURRENT_USER:
144 return key_current_user;
145 case HKEY_LOCAL_MACHINE:
146 return key_local_machine;
149 case HKEY_PERFORMANCE_DATA:
150 return key_performance_data;
153 case HKEY_CURRENT_CONFIG:
154 return key_current_config;
156 dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n",
159 return get_handle(hkey);
165 * splits the unicode string 'wp' into an array of strings.
166 * the array is allocated by this function.
167 * the number of components will be stored in 'wpc'
168 * Free the array using FREE_KEY_PATH
171 split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) {
177 for (i=0;ws[i];i++) {
184 *wpv = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2));
192 #define FREE_KEY_PATH free(wps[0]);free(wps);
195 * Shell initialisation, allocates keys.
201 HKEY cl_r_hkey,c_u_hkey;
202 #define ADD_ROOT_KEY(xx) \
203 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
204 memset(xx,'\0',sizeof(KEYSTRUCT));\
205 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
207 ADD_ROOT_KEY(key_local_machine);
208 if (RegCreateKey(HKEY_LOCAL_MACHINE,"\\SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
209 fprintf(stderr,"couldn't create HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes. This is impossible.\n");
212 key_classes_root = lookup_hkey(cl_r_hkey);
214 ADD_ROOT_KEY(key_users);
217 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
218 * (later, when a win32 registry editing tool becomes avail.)
220 while (pwd=getpwent()) {
221 if (pwd->pw_name == NULL)
223 RegCreateKey(HKEY_USERS,pwd->pw_name,&c_u_hkey);
224 RegCloseKey(c_u_hkey);
227 pwd=getpwuid(getuid());
228 if (pwd && pwd->pw_name) {
229 RegCreateKey(HKEY_USERS,pwd->pw_name,&c_u_hkey);
230 key_current_user = lookup_hkey(c_u_hkey);
232 ADD_ROOT_KEY(key_current_user);
234 ADD_ROOT_KEY(key_performance_data);
235 ADD_ROOT_KEY(key_current_config);
236 ADD_ROOT_KEY(key_dyn_data);
240 /************************ SAVE Registry Function ****************************/
242 #define REGISTRY_SAVE_VERSION 0x00000001
244 /* Registry saveformat:
245 * If you change it, increase above number by 1, which will flush
246 * old registry database files.
249 * "WINE REGISTRY Version %d"
253 * valuename=lastmodified,type,data
257 * keyname,valuename,stringdata:
258 * the usual ascii characters from 0x00-0xff (well, not 0x00)
259 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
260 * ( "=\\\t" escaped in \uXXXX form.)
264 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
268 _write_USTRING(FILE *F,LPWSTR wstr,int escapeeq) {
273 /* FIXME: NULL equals empty string... I hope
274 * the empty string isn't a valid valuename
285 if (escapeeq && *s=='=')
288 fputc(*s,F); /* if \\ than put it twice. */
290 fprintf(F,"\\u%04x",*((unsigned short*)s));
298 _do_save_subkey(FILE *F,LPKEYSTRUCT lpkey,int level) {
304 if (!(lpxkey->flags & REG_OPTION_VOLATILE)) {
305 for (tabs=level;tabs--;)
307 _write_USTRING(F,lpxkey->keyname,1);
309 for (i=0;i<lpxkey->nrofvalues;i++) {
310 LPKEYVALUE val=lpxkey->values+i;
312 for (tabs=level+1;tabs--;)
314 _write_USTRING(F,val->name,0);
316 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
317 if ((1<<val->type) & UNICONVMASK)
318 _write_USTRING(F,(LPWSTR)val->data,0);
320 for (j=0;j<val->len;j++)
321 fprintf(F,"%02x",*((unsigned char*)val->data+j));
324 /* descend recursively */
325 if (!_do_save_subkey(F,lpxkey->nextsub,level+1))
334 _do_savesubreg(FILE *F,LPKEYSTRUCT lpkey) {
335 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
336 return _do_save_subkey(F,lpkey->nextsub,0);
340 _SaveSubReg(LPKEYSTRUCT lpkey,char *fn) {
345 fprintf(stddeb,__FILE__":_SaveSubReg:Couldn't open %s for writing: %s\n",
350 if (!_do_savesubreg(F,lpkey)) {
353 fprintf(stddeb,__FILE__":_SaveSubReg:Failed to save keys, perhaps no more diskspace for %s?\n",fn);
360 SHELL_SaveRegistry() {
364 pwd=getpwuid(getuid());
365 if (pwd!=NULL && pwd->pw_dir!=NULL) {
366 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
367 strcpy(fn,pwd->pw_dir);
368 strcat(fn,WINE_PREFIX);
369 /* create the directory. don't care about errorcodes. */
370 mkdir(fn,0755); /* drwxr-xr-x */
371 strcat(fn,"/"SAVE_CURRENT_USER);
372 _SaveSubReg(key_current_user,fn);
374 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
375 strcpy(fn,pwd->pw_dir);
376 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
377 _SaveSubReg(key_local_machine,fn);
380 fprintf(stderr,"SHELL_SaveRegistry:failed to get homedirectory of UID %d.\n",getuid());
384 /************************ LOAD Registry Function ****************************/
386 /* reads a line including dynamically enlarging the readbuffer and throwing
390 _read_line(FILE *F,char **buf,int *len) {
399 s=fgets(curread,mylen,F);
402 if (NULL==(s=strchr(curread,'\n'))) {
403 /* buffer wasn't large enough */
404 curoff = strlen(*buf);
405 *buf = xrealloc(*buf,*len*2);
406 curread = *buf + curoff;
407 mylen = *len; /* we filled up the buffer and
408 * got new '*len' bytes to fill
416 /* throw away comments */
417 if (**buf=='#' || **buf==';') {
422 if (s) /* got end of line */
428 /* converts a char* into a UNICODE string (up to a special char)
429 * and returns the position exactly after that string
432 _read_USTRING(char *buf,LPWSTR *str) {
436 /* read up to "=" or "\0" or "\n" */
439 /* empty string is the win3.1 default value(NULL)*/
443 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
445 while (*s && (*s!='\n') && (*s!='=')) {
447 *ws++=*((unsigned char*)s++);
456 fprintf(stderr,"_read_USTRING:Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
464 memcpy(xbuf,s,4);xbuf[4]='\0';
465 if (!sscanf(xbuf,"%x",&wc))
466 fprintf(stderr,"_read_USTRING:strange escape sequence %s found in |%s|\n",xbuf,buf);
468 *ws++ =(unsigned short)wc;
474 *str = strdupW(*str);
480 _do_load_subkey(FILE *F,LPKEYSTRUCT lpkey,int level,char **buf,int *buflen) {
481 LPKEYSTRUCT lpxkey,*lplpkey;
486 /* good. we already got a line here ... so parse it */
496 fprintf(stderr,"_do_load_subkey:Got a subhierarchy without resp. key?\n");
499 _do_load_subkey(F,lpxkey,level+1,buf,buflen);
502 /* let the caller handle this line */
503 if (i<level || **buf=='\0')
505 /* good. this is one line for us.
506 * it can be: a value or a keyname. Parse the name first
508 s=_read_USTRING(s,&name);
510 /* switch() default: hack to avoid gotos */
515 * look for the name in the already existing keys
518 lplpkey= &(lpkey->nextsub);
521 if (!strcmpW(lpxkey->keyname,name))
523 lplpkey = &(lpxkey->next);
527 /* we have no key with that name yet. allocate
530 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
532 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
533 lpxkey->keyname = name;
535 /* already got it. we just remember it in
543 int len,lastmodified,type;
546 fprintf(stderr,"_do_load_subkey:unexpected character: %c\n",*s);
549 /* good. this looks like a value to me */
551 for (i=0;i<lpkey->nrofvalues;i++) {
557 if ( val->name!=NULL &&
558 !strcmpW(val->name,name)
563 if (i==lpkey->nrofvalues) {
564 lpkey->values = xrealloc(
566 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
569 memset(val,'\0',sizeof(KEYVALUE));
572 /* value already exists, free name */
575 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
576 fprintf(stderr,"_do_load_subkey: haven't understood possible value in |%s|, skipping.\n",*buf);
582 if ((1<<type) & UNICONVMASK) {
583 s=_read_USTRING(s,(LPWSTR*)&data);
585 len = strlenW((LPWSTR)data)*2+2;
590 data = (LPBYTE)xmalloc(len+1);
591 for (i=0;i<len;i++) {
593 if (*s>='0' && *s<='9')
595 if (*s>='a' && *s<='f')
597 if (*s>='A' && *s<='F')
600 if (*s>='0' && *s<='9')
602 if (*s>='a' && *s<='f')
604 if (*s>='A' && *s<='F')
609 if (val->lastmodified<lastmodified) {
610 val->lastmodified=lastmodified;
621 /* read the next line */
622 if (!_read_line(F,buf,buflen))
629 _do_loadsubreg(FILE *F,LPKEYSTRUCT lpkey) {
634 buf=xmalloc(10);buflen=10;
635 if (!_read_line(F,&buf,&buflen)) {
639 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
643 if (ver!=REGISTRY_SAVE_VERSION) {
644 dprintf_reg(stddeb,__FILE__":_do_loadsubreg:Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
648 if (!_read_line(F,&buf,&buflen)) {
652 if (!_do_load_subkey(F,lpkey,0,&buf,&buflen)) {
654 /* FIXME: memory leak on failure to read registry ...
655 * But this won't happen very often.
665 _LoadSubReg(LPKEYSTRUCT lpkey,char *fn) {
670 dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n",
675 if (!_do_loadsubreg(F,lpkey)) {
684 SHELL_LoadRegistry() {
688 if (key_classes_root==NULL)
690 /* load the machine-wide defaults first */
691 _LoadSubReg(key_current_user,SAVE_CURRENT_USER_DEFAULT);
692 _LoadSubReg(key_local_machine,SAVE_LOCAL_MACHINE_DEFAULT);
694 /* load the user saved registry. overwriting only newer entries */
695 pwd=getpwuid(getuid());
696 if (pwd!=NULL && pwd->pw_dir!=NULL) {
697 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
698 strcpy(fn,pwd->pw_dir);
699 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
700 _LoadSubReg(key_current_user,fn);
702 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
703 strcpy(fn,pwd->pw_dir);
704 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
705 _LoadSubReg(key_local_machine,fn);
708 fprintf(stderr,"SHELL_LoadRegistry:failed to get homedirectory of UID %d.\n",getuid());
710 /* FIXME: load all users and their resp. pwd->pw_dir/.wine/user.reg
711 * (later, when a win32 registry editing tool becomes avail.)
715 /********************* API FUNCTIONS ***************************************/
720 * All functions are stubs to RegOpenKeyExW where all the
723 * FIXME: security,options,desiredaccess,...
726 * RegOpenKey -> RegOpenKeyA -> RegOpenKeyExA \
727 * RegOpenKeyW -> RegOpenKeyExW
730 /* RegOpenKeyExW [ADVAPI32.150] */
739 LPKEYSTRUCT lpNextKey,lpxkey;
742 dprintf_reg(stddeb,"RegOpenKeyExW(%lx,%s,%ld,%lx,%p)\n",
743 (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey
746 lpNextKey = lookup_hkey(hkey);
748 return SHELL_ERROR_BADKEY;
749 if (!lpszSubKey || !*lpszSubKey) {
750 add_handle(++currenthandle,lpNextKey,samDesired);
751 *retkey=currenthandle;
752 return SHELL_ERROR_SUCCESS;
754 split_keypath(lpszSubKey,&wps,&wpc);
756 while ((i<wpc) && (wps[i][0]=='\0')) i++;
759 lpxkey=lpNextKey->nextsub;
761 if (!strcmpW(wps[i],lpxkey->keyname))
767 return SHELL_ERROR_BADKEY;
772 add_handle(++currenthandle,lpxkey,samDesired);
773 *retkey = currenthandle;
775 return SHELL_ERROR_SUCCESS;
778 /* RegOpenKeyW [ADVAPI32.151] */
785 dprintf_reg(stddeb,"RegOpenKeyW(%lx,%s,%p)\n",
786 (LONG)hkey,W2C(lpszSubKey,0),retkey
788 return RegOpenKeyExW(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
792 /* RegOpenKeyExA [ADVAPI32.149] */
804 dprintf_reg(stddeb,"RegOpenKeyExA(%lx,%s,%ld,%lx,%p)\n",
805 (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey
808 lpszSubKeyW=strdupA2W(lpszSubKey);
811 ret=RegOpenKeyExW(hkey,lpszSubKeyW,dwReserved,samDesired,retkey);
817 /* RegOpenKeyA [ADVAPI32.148] */
824 dprintf_reg(stddeb,"RegOpenKeyA(%lx,%s,%p)\n",
825 (LONG)hkey,lpszSubKey,retkey
827 return RegOpenKeyExA(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey);
830 /* RegOpenKey [SHELL.1] [KERNEL.217] */
837 dprintf_reg(stddeb,"RegOpenKey(%lx,%s,%p)\n",
838 (LONG)hkey,lpszSubKey,retkey
840 return RegOpenKeyA(hkey,lpszSubKey,retkey);
846 * All those functions convert their respective
847 * arguments and call RegCreateKeyExW at the end.
849 * FIXME: no security,no access attrib,no optionhandling yet.
852 * RegCreateKey -> RegCreateKeyA -> RegCreateKeyExA \
853 * RegCreateKeyW -> RegCreateKeyExW
856 /* RegCreateKeyExW [ADVAPI32.131] */
865 LPSECURITY_ATTRIBUTES lpSecAttribs,
869 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
873 /*FIXME: handle security/access/whatever */
874 dprintf_reg(stddeb,"RegCreateKeyExW(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
886 lpNextKey = lookup_hkey(hkey);
888 return SHELL_ERROR_BADKEY;
889 if (!lpszSubKey || !*lpszSubKey) {
890 add_handle(++currenthandle,lpNextKey,samDesired);
891 *retkey=currenthandle;
892 return SHELL_ERROR_SUCCESS;
894 split_keypath(lpszSubKey,&wps,&wpc);
896 while ((i<wpc) && (wps[i][0]=='\0')) i++;
899 lpxkey=lpNextKey->nextsub;
901 if (!strcmpW(wps[i],lpxkey->keyname))
911 add_handle(++currenthandle,lpxkey,samDesired);
912 *retkey = currenthandle;
913 *lpDispos = REG_OPENED_EXISTING_KEY;
915 return SHELL_ERROR_SUCCESS;
917 /* good. now the hard part */
919 lplpPrevKey = &(lpNextKey->nextsub);
920 lpxkey = *lplpPrevKey;
922 lplpPrevKey = &(lpxkey->next);
923 lpxkey = *lplpPrevKey;
925 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
928 return SHELL_ERROR_OUTOFMEMORY;
930 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
931 (*lplpPrevKey)->keyname = strdupW(wps[i]);
932 (*lplpPrevKey)->next = NULL;
933 (*lplpPrevKey)->nextsub = NULL;
934 (*lplpPrevKey)->values = NULL;
935 (*lplpPrevKey)->nrofvalues = 0;
937 (*lplpPrevKey)->class = strdupW(lpszClass);
939 (*lplpPrevKey)->class = NULL;
940 lpNextKey = *lplpPrevKey;
943 add_handle(++currenthandle,lpNextKey,samDesired);
945 /*FIXME: flag handling correct? */
946 lpNextKey->flags= fdwOptions;
948 lpNextKey->class = strdupW(lpszClass);
950 lpNextKey->class = NULL;
951 *retkey = currenthandle;
952 *lpDispos = REG_CREATED_NEW_KEY;
954 return SHELL_ERROR_SUCCESS;
957 /* RegCreateKeyW [ADVAPI32.132] */
966 dprintf_reg(stddeb,"RegCreateKeyW(%lx,%s,%p)\n",
967 (LONG)hkey,W2C(lpszSubKey,0),retkey
970 hkey, /* key handle */
971 lpszSubKey, /* subkey name */
972 0, /* reserved = 0 */
973 NULL, /* lpszClass? FIXME: ? */
974 REG_OPTION_NON_VOLATILE, /* options */
975 KEY_ALL_ACCESS, /* desired access attribs */
976 NULL, /* lpsecurity attributes */
977 retkey, /* lpretkey */
978 &junk /* disposition value */
983 /* RegCreateKeyExA [ADVAPI32.130] */
992 LPSECURITY_ATTRIBUTES lpSecAttribs,
996 LPWSTR lpszSubKeyW,lpszClassW;
999 dprintf_reg(stddeb,"RegCreateKeyExA(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",
1011 lpszSubKeyW=strdupA2W(lpszSubKey);
1015 lpszClassW=strdupA2W(lpszClass);
1018 ret=RegCreateKeyExW(
1036 /* RegCreateKeyA [ADVAPI32.129] */
1045 dprintf_reg(stddeb,"RegCreateKeyA(%lx,%s,%p)\n",
1046 (LONG)hkey,lpszSubKey,retkey
1048 return RegCreateKeyExA(
1049 hkey, /* key handle */
1050 lpszSubKey, /* subkey name */
1051 0, /* reserved = 0 */
1052 NULL, /* lpszClass? FIXME: ? */
1053 REG_OPTION_NON_VOLATILE,/* options */
1054 KEY_ALL_ACCESS, /* desired access attribs */
1055 NULL, /* lpsecurity attributes */
1056 retkey, /* lpretkey */
1057 &junk /* disposition value */
1061 /* RegCreateKey [SHELL.2] [KERNEL.218] */
1068 dprintf_reg(stddeb,"RegCreateKey(%lx,%s,%p)\n",
1069 (LONG)hkey,lpszSubKey,retkey
1071 return RegCreateKeyA(hkey,lpszSubKey,retkey);
1075 * Query Value Functions
1076 * Win32 differs between keynames and valuenames.
1077 * multiple values may belong to one key, the special value
1078 * with name NULL is the default value used by the win31
1082 * RegQueryValue -> RegQueryValueA -> RegQueryValueExA \
1083 * RegQueryValueW -> RegQueryValueExW
1086 /* RegQueryValueExW [ADVAPI32.158] */
1090 LPWSTR lpszValueName,
1091 LPDWORD lpdwReserved,
1099 dprintf_reg(stddeb,"RegQueryValueExW(%lx,%s,%p,%p,%p,%p)\n",
1100 hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,lpcbData
1103 lpkey = lookup_hkey(hkey);
1105 return SHELL_ERROR_BADKEY;
1106 if (lpszValueName==NULL) {
1107 for (i=0;i<lpkey->nrofvalues;i++)
1108 if (lpkey->values[i].name==NULL)
1111 for (i=0;i<lpkey->nrofvalues;i++)
1112 if (!strcmpW(lpszValueName,lpkey->values[i].name))
1115 if (i==lpkey->nrofvalues) {
1116 if (lpszValueName==NULL) {
1117 *(WCHAR*)lpbData = 0;
1120 return SHELL_ERROR_SUCCESS;
1122 return SHELL_ERROR_BADKEY;/*FIXME: correct return? */
1125 *lpdwType = lpkey->values[i].type;
1126 if (lpbData==NULL) {
1128 return SHELL_ERROR_SUCCESS;
1129 *lpcbData = lpkey->values[i].len;
1130 return SHELL_ERROR_SUCCESS;
1132 if (*lpcbData<lpkey->values[i].len) {
1135 *lpcbData = lpkey->values[i].len;
1136 return ERROR_MORE_DATA;
1138 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
1139 *lpcbData = lpkey->values[i].len;
1140 return SHELL_ERROR_SUCCESS;
1143 /* RegQueryValueW [ADVAPI32.159] */
1154 dprintf_reg(stddeb,"RegQueryValueW(%lx,%s,%p,%p)\n->",
1155 hkey,W2C(lpszSubKey,0),lpszData,lpcbData
1158 /* only open subkey, if we really do descend */
1159 if (lpszSubKey && *lpszSubKey) {
1160 ret = RegOpenKeyW(hkey,lpszSubKey,&xhkey);
1161 if (ret!=ERROR_SUCCESS)
1167 ret = RegQueryValueExW(
1169 NULL, /* varname NULL -> compat */
1170 NULL, /* lpdwReserved, must be NULL */
1180 /* RegQueryValueExA [ADVAPI32.157] */
1184 LPSTR lpszValueName,
1185 LPDWORD lpdwReserved,
1190 LPWSTR lpszValueNameW;
1195 dprintf_reg(stddeb,"RegQueryValueExA(%lx,%s,%p,%p,%p,%p)\n->",
1196 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData
1200 buf = (LPBYTE)xmalloc((*lpcbData)*2);
1201 myxlen = *lpcbData*2;
1206 myxlen = *lpcbData*2;
1212 lpszValueNameW=strdupA2W(lpszValueName);
1214 lpszValueNameW=NULL;
1216 ret=RegQueryValueExW(
1225 if (ret==ERROR_SUCCESS) {
1227 if (UNICONVMASK & (1<<(*lpdwType))) {
1228 /* convert UNICODE to ASCII */
1229 strcpyWA(lpbData,(LPWSTR)buf);
1230 *lpcbData = myxlen/2;
1232 if (myxlen>*lpcbData)
1233 ret = ERROR_MORE_DATA;
1235 memcpy(lpbData,buf,myxlen);
1240 if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData)
1241 *lpcbData = myxlen/2;
1244 if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData)
1245 *lpcbData = myxlen/2;
1252 /* RegQueryValueEx [KERNEL.225] */
1256 LPSTR lpszValueName,
1257 LPDWORD lpdwReserved,
1262 dprintf_reg(stddeb,"RegQueryValueEx(%lx,%s,%p,%p,%p,%p)\n",
1263 hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData
1265 return RegQueryValueExA(
1275 /* RegQueryValueA [ADVAPI32.156] */
1286 dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n",
1287 hkey,lpszSubKey,lpszData,lpcbData
1290 /* only open subkey, if we really do descend */
1291 if (lpszSubKey && *lpszSubKey) {
1292 ret = RegOpenKey(hkey,lpszSubKey,&xhkey);
1293 if (ret!=ERROR_SUCCESS)
1299 ret = RegQueryValueExA(
1301 NULL, /* lpszValueName NULL -> compat */
1302 NULL, /* lpdwReserved, must be NULL */
1312 /* RegQueryValue [SHELL.6] [KERNEL.224] */
1320 dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n",
1321 hkey,lpszSubKey,lpszData,lpcbData
1323 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
1327 * Setting values of Registry keys
1330 * RegSetValue -> RegSetValueA -> RegSetValueExA \
1331 * RegSetValueW -> RegSetValueExW
1334 /* RegSetValueExW [ADVAPI32.170] */
1338 LPWSTR lpszValueName,
1347 dprintf_reg(stddeb,"RegSetValueExW(%lx,%s,%ld,%ld,%p,%ld)\n",
1348 hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData
1350 /* we no longer care about the lpbData dwType here... */
1351 lpkey = lookup_hkey(hkey);
1353 return SHELL_ERROR_BADKEY;
1354 if (lpszValueName==NULL) {
1355 for (i=0;i<lpkey->nrofvalues;i++)
1356 if (lpkey->values[i].name==NULL)
1359 for (i=0;i<lpkey->nrofvalues;i++)
1360 if (!strcmpW(lpszValueName,lpkey->values[i].name))
1363 if (i==lpkey->nrofvalues) {
1364 lpkey->values = (LPKEYVALUE)xrealloc(
1366 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
1368 lpkey->nrofvalues++;
1369 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
1371 if (lpkey->values[i].name==NULL)
1373 lpkey->values[i].name = strdupW(lpszValueName);
1375 lpkey->values[i].name = NULL;
1376 lpkey->values[i].len = cbData;
1377 lpkey->values[i].type = dwType;
1378 if (lpkey->values[i].data !=NULL)
1379 free(lpkey->values[i].data);
1380 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
1381 lpkey->values[i].lastmodified = time(NULL);
1382 memcpy(lpkey->values[i].data,lpbData,cbData);
1383 return SHELL_ERROR_SUCCESS;
1386 /* RegSetValueExA [ADVAPI32.169] */
1390 LPSTR lpszValueName,
1397 LPWSTR lpszValueNameW;
1400 dprintf_reg(stddeb,"RegSetValueExA(%lx,%s,%ld,%ld,%p,%ld)\n->",
1401 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
1403 if ((1<<dwType) & UNICONVMASK) {
1404 buf=(LPBYTE)strdupA2W(lpbData);
1405 cbData=2*strlen(lpbData)+2;
1409 lpszValueNameW = strdupA2W(lpszValueName);
1411 lpszValueNameW = NULL;
1412 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
1414 free(lpszValueNameW);
1420 /* RegSetValueEx [KERNEL.226] */
1424 LPSTR lpszValueName,
1430 dprintf_reg(stddeb,"RegSetValueEx(%lx,%s,%ld,%ld,%p,%ld)\n->",
1431 hkey,lpszValueName,dwReserved,dwType,lpbData,cbData
1433 return RegSetValueExA(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData);
1436 /* RegSetValueW [ADVAPI32.171] */
1448 dprintf_reg(stddeb,"RegSetValueW(%lx,%s,%ld,%s,%ld)\n->",
1449 hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData
1451 if (lpszSubKey && *lpszSubKey) {
1452 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
1453 if (ret!=ERROR_SUCCESS)
1457 if (dwType!=REG_SZ) {
1458 fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType);
1461 if (cbData!=2*strlenW(lpszData)+2) {
1462 dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n",
1463 cbData,W2C(lpszData,0),2*strlenW(lpszData)+2
1465 cbData=2*strlenW(lpszData)+2;
1467 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
1473 /* RegSetValueA [ADVAPI32.168] */
1485 dprintf_reg(stddeb,"RegSetValueA(%lx,%s,%ld,%s,%ld)\n->",
1486 hkey,lpszSubKey,dwType,lpszData,cbData
1488 if (lpszSubKey && *lpszSubKey) {
1489 ret=RegCreateKey(hkey,lpszSubKey,&xhkey);
1490 if (ret!=ERROR_SUCCESS)
1495 if (dwType!=REG_SZ) {
1496 dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType);
1499 if (cbData!=strlen(lpszData)+1)
1500 cbData=strlen(lpszData)+1;
1501 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
1507 /* RegSetValue [KERNEL.221] [SHELL.5] */
1517 dprintf_reg(stddeb,"RegSetValue(%lx,%s,%ld,%s,%ld)\n->",
1518 hkey,lpszSubKey,dwType,lpszData,cbData
1520 ret=RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
1528 * RegEnumKey -> RegEnumKeyA -> RegEnumKeyExA \
1529 * RegEnumKeyW -> RegEnumKeyExW
1532 /* RegEnumKeyExW [ADVAPI32.139] */
1539 LPDWORD lpdwReserved,
1544 LPKEYSTRUCT lpkey,lpxkey;
1546 dprintf_reg(stddeb,"RegEnumKeyExW(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n",
1547 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
1549 lpkey=lookup_hkey(hkey);
1551 return SHELL_ERROR_BADKEY;
1552 if (!lpkey->nextsub)
1553 return ERROR_NO_MORE_ITEMS;
1554 lpxkey=lpkey->nextsub;
1555 while (iSubkey && lpxkey) {
1557 lpxkey=lpxkey->next;
1559 if (iSubkey || !lpxkey)
1560 return ERROR_NO_MORE_ITEMS;
1561 if (2*strlenW(lpxkey->keyname)+2>*lpcchName)
1562 return ERROR_MORE_DATA;
1563 memcpy(lpszName,lpxkey->keyname,strlenW(lpxkey->keyname)*2+2);
1565 /* what should we write into it? */
1569 return ERROR_SUCCESS;
1573 /* RegEnumKeyW [ADVAPI32.140] */
1583 dprintf_reg(stddeb,"RegEnumKeyW(%lx,%ld,%p,%ld)\n->",
1584 hkey,iSubkey,lpszName,lpcchName
1586 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
1588 /* RegEnumKeyExA [ADVAPI32.138] */
1595 LPDWORD lpdwReserved,
1600 DWORD ret,lpcchNameW,lpcchClassW;
1601 LPWSTR lpszNameW,lpszClassW;
1604 dprintf_reg(stddeb,"RegEnumKeyExA(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n->",
1605 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
1608 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
1609 lpcchNameW = *lpcchName*2;
1615 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
1616 lpcchClassW = *lpcchClass*2;
1631 if (ret==ERROR_SUCCESS) {
1632 strcpyWA(lpszName,lpszNameW);
1633 *lpcchName=strlen(lpszName);
1635 strcpyWA(lpszClass,lpszClassW);
1636 *lpcchClass=strlen(lpszClass);
1646 /* RegEnumKeyA [ADVAPI32.137] */
1656 dprintf_reg(stddeb,"RegEnumKeyA(%lx,%ld,%p,%ld)\n->",
1657 hkey,iSubkey,lpszName,lpcchName
1659 return RegEnumKeyExA(
1671 /* RegEnumKey [SHELL.7] [KERNEL.216] */
1679 dprintf_reg(stddeb,"RegEnumKey(%lx,%ld,%p,%ld)\n->",
1680 hkey,iSubkey,lpszName,lpcchName
1682 return RegEnumKeyA(hkey,iSubkey,lpszName,lpcchName);
1686 * Enumerate Registry Values
1689 * RegEnumValue -> RegEnumValueA -> RegEnumValueW
1692 /* RegEnumValueW [ADVAPI32.142] */
1699 LPDWORD lpdReserved,
1707 dprintf_reg(stddeb,"RegEnumValueW(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1708 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1710 lpkey = lookup_hkey(hkey);
1712 return SHELL_ERROR_BADKEY;
1713 if (lpkey->nrofvalues<=iValue)
1714 return ERROR_NO_MORE_ITEMS;
1715 val = lpkey->values+iValue;
1718 if (strlenW(val->name)*2+2>*lpcchValue) {
1719 *lpcchValue = strlenW(val->name)*2+2;
1720 return ERROR_MORE_DATA;
1722 memcpy(lpszValue,val->name,2*strlenW(val->name)+2);
1723 *lpcchValue=strlenW(val->name)*2+2;
1725 /* how to handle NULL value? */
1729 *lpdwType=val->type;
1731 if (val->len>*lpcbData)
1732 return ERROR_MORE_DATA;
1733 memcpy(lpbData,val->data,val->len);
1734 *lpcbData = val->len;
1736 return SHELL_ERROR_SUCCESS;
1739 /* RegEnumValueA [ADVAPI32.141] */
1746 LPDWORD lpdReserved,
1753 DWORD ret,lpcbDataW;
1755 dprintf_reg(stddeb,"RegEnumValueA(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1756 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1759 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
1761 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
1762 lpcbDataW = *lpcbData*2;
1776 if (ret==ERROR_SUCCESS) {
1777 strcpyWA(lpszValue,lpszValueW);
1779 if ((1<<*lpdwType) & UNICONVMASK) {
1780 strcpyWA(lpbData,(LPWSTR)lpbDataW);
1782 if (lpcbDataW > *lpcbData)
1783 ret = ERROR_MORE_DATA;
1785 memcpy(lpbData,lpbDataW,lpcbDataW);
1787 *lpcbData = lpcbDataW;
1797 /* RegEnumValue [KERNEL.223] */
1804 LPDWORD lpdReserved,
1809 dprintf_reg(stddeb,"RegEnumValue(%ld,%ld,%p,%p,%p,%p,%p,%p)\n",
1810 hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData
1812 return RegEnumValueA(
1825 * Close registry key
1827 /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */
1829 RegCloseKey(HKEY hkey) {
1830 dprintf_reg(stddeb,"RegCloseKey(%ld)\n",hkey);
1831 remove_handle(hkey);
1832 return ERROR_SUCCESS;
1835 * Delete registry key
1838 * RegDeleteKey -> RegDeleteKeyA -> RegDeleteKeyW
1840 /* RegDeleteKeyW [ADVAPI32.134] */
1842 RegDeleteKeyW(HKEY hkey,LPWSTR lpszSubKey) {
1843 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1847 dprintf_reg(stddeb,"RegDeleteKeyW(%ld,%s)\n",
1848 hkey,W2C(lpszSubKey,0)
1850 lpNextKey = lookup_hkey(hkey);
1852 return SHELL_ERROR_BADKEY;
1853 /* we need to know the previous key in the hier. */
1854 if (!lpszSubKey || !*lpszSubKey)
1855 return SHELL_ERROR_BADKEY;
1856 split_keypath(lpszSubKey,&wps,&wpc);
1860 lpxkey=lpNextKey->nextsub;
1862 if (!strcmpW(wps[i],lpxkey->keyname))
1864 lpxkey=lpxkey->next;
1868 /* not found is success */
1869 return SHELL_ERROR_SUCCESS;
1874 lpxkey = lpNextKey->nextsub;
1875 lplpPrevKey = &(lpNextKey->nextsub);
1877 if (!strcmpW(wps[i],lpxkey->keyname))
1879 lplpPrevKey = &(lpxkey->next);
1880 lpxkey = lpxkey->next;
1883 return SHELL_ERROR_SUCCESS;
1884 if (lpxkey->nextsub)
1885 return SHELL_ERROR_CANTWRITE;
1886 *lplpPrevKey = lpxkey->next;
1887 free(lpxkey->keyname);
1889 free(lpxkey->class);
1891 free(lpxkey->values);
1894 return SHELL_ERROR_SUCCESS;
1897 /* RegDeleteKeyA [ADVAPI32.133] */
1899 RegDeleteKeyA(HKEY hkey,LPCSTR lpszSubKey) {
1903 dprintf_reg(stddeb,"RegDeleteKeyA(%ld,%s)\n",
1906 lpszSubKeyW=strdupA2W(lpszSubKey);
1907 ret=RegDeleteKeyW(hkey,lpszSubKeyW);
1912 /* RegDeleteKey [SHELL.4] [KERNEL.219] */
1914 RegDeleteKey(HKEY hkey,LPCSTR lpszSubKey) {
1915 dprintf_reg(stddeb,"RegDeleteKey(%ld,%s)\n",
1918 return RegDeleteKeyA(hkey,lpszSubKey);
1922 * Delete registry value
1925 * RegDeleteValue -> RegDeleteValueA -> RegDeleteValueW
1927 /* RegDeleteValueW [ADVAPI32.136] */
1929 RegDeleteValueW(HKEY hkey,LPWSTR lpszValue) {
1934 dprintf_reg(stddeb,"RegDeleteValueW(%ld,%s)\n",
1935 hkey,W2C(lpszValue,0)
1937 lpkey=lookup_hkey(hkey);
1939 return SHELL_ERROR_BADKEY;
1941 for (i=0;i<lpkey->nrofvalues;i++)
1942 if (!strcmpW(lpkey->values[i].name,lpszValue))
1945 for (i=0;i<lpkey->nrofvalues;i++)
1946 if (lpkey->values[i].name==NULL)
1949 if (i==lpkey->nrofvalues)
1950 return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */
1951 val = lpkey->values+i;
1952 if (val->name) free(val->name);
1953 if (val->data) free(val->data);
1957 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
1959 lpkey->values = (LPKEYVALUE)xrealloc(
1961 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
1963 lpkey->nrofvalues--;
1964 return SHELL_ERROR_SUCCESS;
1967 /* RegDeleteValueA [ADVAPI32.135] */
1969 RegDeleteValueA(HKEY hkey,LPSTR lpszValue) {
1973 dprintf_reg(stddeb,"RegDeleteValueA(%ld,%s)\n",
1977 lpszValueW=strdupA2W(lpszValue);
1980 ret=RegDeleteValueW(hkey,lpszValueW);
1986 /* RegDeleteValue [KERNEL.222] */
1988 RegDeleteValue(HKEY hkey,LPSTR lpszValue) {
1989 dprintf_reg(stddeb,"RegDeleteValue(%ld,%s)\n",
1992 return RegDeleteValueA(hkey,lpszValue);
1995 /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */
1997 RegFlushKey(HKEY hkey) {
1998 dprintf_reg(stddeb,"RegFlushKey(%ld), STUB.\n",hkey);
1999 return SHELL_ERROR_SUCCESS;
2002 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
2004 /* RegQueryInfoKeyW [ADVAPI32.153] */
2010 LPDWORD lpdwReserved,
2012 LPDWORD lpcchMaxSubkey,
2013 LPDWORD lpcchMaxClass,
2015 LPDWORD lpcchMaxValueName,
2016 LPDWORD lpccbMaxValueData,
2017 LPDWORD lpcbSecurityDescriptor,
2020 LPKEYSTRUCT lpkey,lpxkey;
2021 int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata;
2024 dprintf_reg(stddeb,"RegQueryInfoKeyW(%lx,......)\n",hkey);
2025 lpkey=lookup_hkey(hkey);
2027 return SHELL_ERROR_BADKEY;
2030 if (strlenW(lpkey->class)*2+2>*lpcchClass) {
2031 *lpcchClass=strlenW(lpkey->class)*2;
2032 return ERROR_MORE_DATA;
2034 *lpcchClass=strlenW(lpkey->class)*2;
2035 memcpy(lpszClass,lpkey->class,strlenW(lpkey->class));
2042 *lpcchClass = strlenW(lpkey->class)*2;
2044 lpxkey=lpkey->nextsub;
2045 nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0;
2048 if (strlenW(lpxkey->keyname)>maxsubkey)
2049 maxsubkey=strlenW(lpxkey->keyname);
2050 if (lpxkey->class && strlenW(lpxkey->class)>maxclass)
2051 maxclass=strlenW(lpxkey->class);
2052 if (lpxkey->nrofvalues>maxvalues)
2053 maxvalues=lpxkey->nrofvalues;
2054 for (i=0;i<lpxkey->nrofvalues;i++) {
2055 LPKEYVALUE val=lpxkey->values+i;
2057 if (val->name && strlenW(val->name)>maxvname)
2058 maxvname=strlenW(val->name);
2059 if (val->len>maxvdata)
2062 lpxkey=lpxkey->next;
2064 if (!maxclass) maxclass = 1;
2065 if (!maxvname) maxvname = 1;
2067 *lpcSubKeys = nrofkeys;
2069 *lpcchMaxSubkey = maxsubkey*2;
2071 *lpcchMaxClass = maxclass*2;
2073 *lpcValues = maxvalues;
2074 if (lpcchMaxValueName)
2075 *lpcchMaxValueName= maxvname;
2076 if (lpccbMaxValueData)
2077 *lpccbMaxValueData= maxvdata;
2078 return SHELL_ERROR_SUCCESS;
2081 /* RegQueryInfoKeyA [ADVAPI32.152] */
2087 LPDWORD lpdwReserved,
2089 LPDWORD lpcchMaxSubkey,
2090 LPDWORD lpcchMaxClass,
2092 LPDWORD lpcchMaxValueName,
2093 LPDWORD lpccbMaxValueData,
2094 LPDWORD lpcbSecurityDescriptor,
2100 dprintf_reg(stddeb,"RegQueryInfoKeyA(%lx,......)\n",hkey);
2103 lpszClassW = (LPWSTR)xmalloc(*lpcchClass);
2107 ret=RegQueryInfoKeyW(
2118 lpcbSecurityDescriptor,
2121 if (ret==ERROR_SUCCESS)
2122 strcpyWA(lpszClass,lpszClassW);
2129 if (lpcchMaxValueName)
2130 *lpcchMaxValueName/=2;