/* * Registry Functions * * Copyright 1996 Marcus Meissner */ #include #include #include #include #include #include "windows.h" #include "win.h" #include "winerror.h" #include "string32.h" #include "kernel32.h" /* LPSECURITY_ATTRIBUTES */ #include "stddebug.h" #include "debug.h" #include "xmalloc.h" #include "winreg.h" #define SAVE_CLASSES_ROOT "/tmp/reg.classes_root" #define SAVE_CURRENT_USER "/tmp/reg.current_user" #define SAVE_LOCAL_MACHINE "/tmp/reg.local_machine" #define SAVE_USERS "/tmp/reg.users" static KEYSTRUCT *key_classes_root=NULL; /* windows global values */ static KEYSTRUCT *key_current_user=NULL; /* user specific values */ static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */ static KEYSTRUCT *key_users=NULL; /* all users? */ /* dynamic, not saved */ static KEYSTRUCT *key_performance_data=NULL; static KEYSTRUCT *key_current_config=NULL; static KEYSTRUCT *key_dyn_data=NULL; /* what valuetypes do we need to convert? */ #define UNICONVMASK ((1<"; if (sub!=0 && sub!=1) return ""; if (unicodedebug[sub]) free(unicodedebug[sub]); unicodedebug[sub] = strdupW2A(x); return unicodedebug[sub]; } static LPKEYSTRUCT lookup_hkey(HKEY hkey) { switch (hkey) { case 0x00000000: case 0x00000001: case HKEY_CLASSES_ROOT: return key_classes_root; case HKEY_CURRENT_USER: return key_current_user; case HKEY_LOCAL_MACHINE: return key_local_machine; case HKEY_USERS: return key_users; case HKEY_PERFORMANCE_DATA: return key_performance_data; case HKEY_DYN_DATA: return key_dyn_data; case HKEY_CURRENT_CONFIG: return key_current_config; default: dprintf_reg(stddeb,"lookup_hkey(%lx), special key!\n", (LONG)hkey ); return get_handle(hkey); } /*NOTREACHED*/ } /* * splits the unicode string 'wp' into an array of strings. * the array is allocated by this function. * the number of components will be stored in 'wpc' * Free the array using FREE_KEY_PATH */ static void split_keypath(LPCWSTR wp,LPWSTR **wpv,int *wpc) { int i,j,len; LPWSTR ws; ws = strdupW(wp); *wpc = 1; for (i=0;ws[i];i++) { if (ws[i]=='\\') { ws[i]=0; (*wpc)++; } } len = i; *wpv = (LPWSTR*)xmalloc(sizeof(LPWSTR)*(*wpc+2)); (*wpv)[0]= ws; j = 1; for (i=1;ikeyname= strdupA2W(""); ADD_ROOT_KEY(key_classes_root); ADD_ROOT_KEY(key_current_user); ADD_ROOT_KEY(key_local_machine); ADD_ROOT_KEY(key_users); ADD_ROOT_KEY(key_performance_data); ADD_ROOT_KEY(key_current_config); ADD_ROOT_KEY(key_dyn_data); #undef ADD_ROOT_KEY } /************************ SAVE Registry Function ****************************/ #define REGISTRY_SAVE_VERSION 0x00000001 /* Registry saveformat: * If you change it, increase above number by 1, which will flush * old registry database files. * * Global: * DWORD version * DWORD nrofkeys * KEY keys[nrofkeys] * * KEY: * USTRING name * USTRING class * DWORD nrofvalues * VALUE vals[nrofvalues] * DWORD nrofsubkeys * KEY keys[nrofsubkeys] * * Value: * USTRING name * DWORD type * DWORD len * BYTE data[len] * * USTRING: * DWORD len (len==0 means data=NULL) * BYTE data[len] * * * All _write_XXX and _read_XXX functions return !0 on sucess. */ static int _write_DWORD(FILE *F,DWORD dw) { return fwrite(&dw,sizeof(dw),1,F); } static int _write_USTRING(FILE *F,LPWSTR str) { int len; if (str==NULL) { if (!_write_DWORD(F,0)) return 0; } else { len=strlenW(str)*2+2; if (!_write_DWORD(F,len)) return 0; if (!fwrite(str,len,1,F)) return 0; } return 1; } static int _do_save_subkey(FILE *F,LPKEYSTRUCT lpkey) { LPKEYSTRUCT lpxkey; int nrofkeys; int i; nrofkeys= 0; lpxkey = lpkey; while (lpxkey) { if (!(lpxkey->flags & REG_OPTION_VOLATILE)) nrofkeys++; lpxkey = lpxkey->next; } if (!_write_DWORD(F,nrofkeys)) return 0; lpxkey = lpkey; while (lpxkey) { if (!(lpxkey->flags & REG_OPTION_VOLATILE)) { if (!_write_USTRING(F,lpxkey->keyname)) return 0; if (!_write_USTRING(F,lpxkey->class)) return 0; if (!_write_DWORD(F,lpxkey->nrofvalues)) return 0; for (i=0;inrofvalues;i++) { LPKEYVALUE val=lpxkey->values+i; if (!_write_USTRING(F,val->name)) return 0; if (!_write_DWORD(F,val->type)) return 0; if (!_write_DWORD(F,val->len)) return 0; if (!fwrite(val->data,val->len,1,F)) return 0; } /* descend recursively */ if (!_do_save_subkey(F,lpxkey->nextsub)) return 0; } lpxkey=lpxkey->next; } return 1; } static int _do_savesubreg(FILE *F,LPKEYSTRUCT lpkey) { if (!_write_DWORD(F,REGISTRY_SAVE_VERSION)) return 0; return _do_save_subkey(F,lpkey->nextsub); } static void _SaveSubReg(LPKEYSTRUCT lpkey,char *fn) { FILE *F; F=fopen(fn,"wb"); if (F==NULL) { fprintf(stddeb,__FILE__":_SaveSubReg:Couldn't open %s for writing: %s\n", fn,strerror(errno) ); return; } if (!_do_savesubreg(F,lpkey)) { fclose(F); unlink(fn); fprintf(stddeb,__FILE__":_SaveSubReg:Failed to save keys, perhaps no more diskspace for %s?\n",fn); return; } fclose(F); } void SHELL_SaveRegistry() { _SaveSubReg(key_classes_root,SAVE_CLASSES_ROOT); _SaveSubReg(key_current_user,SAVE_CURRENT_USER); _SaveSubReg(key_local_machine,SAVE_LOCAL_MACHINE); _SaveSubReg(key_users,SAVE_USERS); } /************************ LOAD Registry Function ****************************/ /* FIXME: * Currently overwrites any old registry data (leaks it away) * should better be a merge, or ? */ static int _read_DWORD(FILE *F,DWORD *dw) { return fread(dw,sizeof(DWORD),1,F); } static int _read_USTRING(FILE *F,LPWSTR *str) { DWORD len; if (!_read_DWORD(F,&len)) return 0; if (len==0) { *str=NULL; return 1; } *str=xmalloc(len); return fread(*str,len,1,F); } static int _do_load_subkey(FILE *F,LPKEYSTRUCT lpkey) { DWORD howmuch; LPKEYSTRUCT *lplpkey,lpxkey; int i; if (!_read_DWORD(F,&howmuch)) return 0; /* no subkeys? */ if (howmuch==0) return 1; lplpkey = &(lpkey->nextsub); while (howmuch--) { *lplpkey= (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT)); memset(*lplpkey,'\0',sizeof(KEYSTRUCT)); lpxkey = *lplpkey; if (!_read_USTRING(F,&(lpxkey->keyname))) return 0; if (!_read_USTRING(F,&(lpxkey->class))) return 0; if (!_read_DWORD(F,&(lpxkey->nrofvalues))) return 0; if (lpxkey->nrofvalues) { lpxkey->values = (LPKEYVALUE)xmalloc( lpxkey->nrofvalues*sizeof(KEYVALUE) ); for (i=0;inrofvalues;i++) { LPKEYVALUE val=lpxkey->values+i; memset(val,'\0',sizeof(KEYVALUE)); if (!_read_USTRING(F,&(val->name))) return 0; if (!_read_DWORD(F,&(val->type))) return 0; if (!_read_DWORD(F,&(val->len))) return 0; val->data = (LPBYTE)xmalloc(val->len); if (!fread(val->data,val->len,1,F)) return 0; } } if (!_do_load_subkey(F,*lplpkey)) return 0; lplpkey = &(lpxkey->next); } return 1; } static int _do_loadsubreg(FILE *F,LPKEYSTRUCT lpkey) { DWORD ver; if (!_read_DWORD(F,&ver)) return 0; if (ver!=REGISTRY_SAVE_VERSION) { dprintf_reg(stddeb,__FILE__":_do_loadsubreg:Old format (%lx) registry found, ignoring it.\n",ver); return 0; } if (!_do_load_subkey(F,lpkey)) { /* FIXME: memory leak on failure to read registry ... * But this won't happen very often. */ lpkey->nextsub=NULL; return 0; } return 1; } static void _LoadSubReg(LPKEYSTRUCT lpkey,char *fn) { FILE *F; F=fopen(fn,"rb"); if (F==NULL) { dprintf_reg(stddeb,__FILE__":Couldn't open %s for reading: %s\n", fn,strerror(errno) ); return; } if (!_do_loadsubreg(F,lpkey)) { fclose(F); unlink(fn); } fclose(F); } void SHELL_LoadRegistry() { if (key_classes_root==NULL) SHELL_Init(); _LoadSubReg(key_classes_root,SAVE_CLASSES_ROOT); _LoadSubReg(key_current_user,SAVE_CURRENT_USER); _LoadSubReg(key_local_machine,SAVE_LOCAL_MACHINE); _LoadSubReg(key_users,SAVE_USERS); } /********************* API FUNCTIONS ***************************************/ /* * Open Keys. * * All functions are stubs to RegOpenKeyExW where all the * magic happens. * * FIXME: security,options,desiredaccess,... * * Callpath: * RegOpenKey -> RegOpenKeyA -> RegOpenKeyExA \ * RegOpenKeyW -> RegOpenKeyExW */ /* RegOpenKeyExW [ADVAPI32.150] */ WINAPI DWORD RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved, REGSAM samDesired, LPHKEY retkey ) { LPKEYSTRUCT lpNextKey,lpxkey; LPWSTR *wps; int wpc,i; dprintf_reg(stddeb,"RegOpenKeyExW(%lx,%s,%ld,%lx,%p)\n", (LONG)hkey,W2C(lpszSubKey,0),dwReserved,samDesired,retkey ); lpNextKey = lookup_hkey(hkey); if (!lpNextKey) return SHELL_ERROR_BADKEY; if (!lpszSubKey || !*lpszSubKey) { add_handle(++currenthandle,lpNextKey,samDesired); *retkey=currenthandle; return SHELL_ERROR_SUCCESS; } split_keypath(lpszSubKey,&wps,&wpc); i = 0; lpxkey = lpNextKey; while (inextsub; while (lpxkey) { if (!strcmpW(wps[i],lpxkey->keyname)) break; lpxkey=lpxkey->next; } if (!lpxkey) { FREE_KEY_PATH; return SHELL_ERROR_BADKEY; } i++; lpNextKey = lpxkey; } add_handle(++currenthandle,lpxkey,samDesired); *retkey = currenthandle; FREE_KEY_PATH; return SHELL_ERROR_SUCCESS; } /* RegOpenKeyW [ADVAPI32.151] */ WINAPI DWORD RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey ) { dprintf_reg(stddeb,"RegOpenKeyW(%lx,%s,%p)\n", (LONG)hkey,W2C(lpszSubKey,0),retkey ); return RegOpenKeyExW(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey); } /* RegOpenKeyExA [ADVAPI32.149] */ WINAPI DWORD RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved, REGSAM samDesired, LPHKEY retkey ) { LPWSTR lpszSubKeyW; DWORD ret; dprintf_reg(stddeb,"RegOpenKeyExA(%lx,%s,%ld,%lx,%p)\n", (LONG)hkey,lpszSubKey,dwReserved,samDesired,retkey ); if (lpszSubKey) lpszSubKeyW=strdupA2W(lpszSubKey); else lpszSubKeyW=NULL; ret=RegOpenKeyExW(hkey,lpszSubKeyW,dwReserved,samDesired,retkey); if (lpszSubKeyW) free(lpszSubKeyW); return ret; } /* RegOpenKeyA [ADVAPI32.148] */ WINAPI DWORD RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey ) { dprintf_reg(stddeb,"RegOpenKeyA(%lx,%s,%p)\n", (LONG)hkey,lpszSubKey,retkey ); return RegOpenKeyExA(hkey,lpszSubKey,0,KEY_ALL_ACCESS,retkey); } /* RegOpenKey [SHELL.1] [KERNEL.217] */ WINAPI DWORD RegOpenKey( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey ) { dprintf_reg(stddeb,"RegOpenKey(%lx,%s,%p)\n", (LONG)hkey,lpszSubKey,retkey ); return RegOpenKeyA(hkey,lpszSubKey,retkey); } /* * Create keys * * All those functions convert their respective * arguments and call RegCreateKeyExW at the end. * * FIXME: no security,no access attrib,no optionhandling yet. * * Callpath: * RegCreateKey -> RegCreateKeyA -> RegCreateKeyExA \ * RegCreateKeyW -> RegCreateKeyExW */ /* RegCreateKeyExW [ADVAPI32.131] */ WINAPI DWORD RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved, LPWSTR lpszClass, DWORD fdwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecAttribs, LPHKEY retkey, LPDWORD lpDispos ) { LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey; LPWSTR *wps; int wpc,i; /*FIXME: handle security/access/whatever */ dprintf_reg(stddeb,"RegCreateKeyExW(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", (LONG)hkey, W2C(lpszSubKey,0), dwReserved, W2C(lpszClass,1), fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos ); lpNextKey = lookup_hkey(hkey); if (!lpNextKey) return SHELL_ERROR_BADKEY; if (!lpszSubKey || !*lpszSubKey) { add_handle(++currenthandle,lpNextKey,samDesired); *retkey=currenthandle; return SHELL_ERROR_SUCCESS; } split_keypath(lpszSubKey,&wps,&wpc); i = 0; lpxkey = lpNextKey; while (inextsub; while (lpxkey) { if (!strcmpW(wps[i],lpxkey->keyname)) break; lpxkey=lpxkey->next; } if (!lpxkey) break; i++; lpNextKey = lpxkey; } if (lpxkey) { add_handle(++currenthandle,lpxkey,samDesired); *retkey = currenthandle; *lpDispos = REG_OPENED_EXISTING_KEY; FREE_KEY_PATH; return SHELL_ERROR_SUCCESS; } /* good. now the hard part */ while (inextsub); lpxkey = *lplpPrevKey; while (lpxkey) { lplpPrevKey = &(lpxkey->next); lpxkey = *lplpPrevKey; } *lplpPrevKey=malloc(sizeof(KEYSTRUCT)); if (!*lplpPrevKey) { FREE_KEY_PATH; return SHELL_ERROR_OUTOFMEMORY; } memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT)); (*lplpPrevKey)->keyname = strdupW(wps[i]); (*lplpPrevKey)->next = NULL; (*lplpPrevKey)->nextsub = NULL; (*lplpPrevKey)->values = NULL; (*lplpPrevKey)->nrofvalues = 0; if (lpszClass) (*lplpPrevKey)->class = strdupW(lpszClass); else (*lplpPrevKey)->class = NULL; lpNextKey = *lplpPrevKey; i++; } add_handle(++currenthandle,lpNextKey,samDesired); /*FIXME: flag handling correct? */ lpNextKey->flags= fdwOptions; if (lpszClass) lpNextKey->class = strdupW(lpszClass); else lpNextKey->class = NULL; *retkey = currenthandle; *lpDispos = REG_CREATED_NEW_KEY; FREE_KEY_PATH; return SHELL_ERROR_SUCCESS; } /* RegCreateKeyW [ADVAPI32.132] */ WINAPI DWORD RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey ) { DWORD junk,ret; dprintf_reg(stddeb,"RegCreateKeyW(%lx,%s,%p)\n", (LONG)hkey,W2C(lpszSubKey,0),retkey ); ret=RegCreateKeyExW( hkey, /* key handle */ lpszSubKey, /* subkey name */ 0, /* reserved = 0 */ NULL, /* lpszClass? FIXME: ? */ REG_OPTION_NON_VOLATILE, /* options */ KEY_ALL_ACCESS, /* desired access attribs */ NULL, /* lpsecurity attributes */ retkey, /* lpretkey */ &junk /* disposition value */ ); return ret; } /* RegCreateKeyExA [ADVAPI32.130] */ WINAPI DWORD RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved, LPSTR lpszClass, DWORD fdwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecAttribs, LPHKEY retkey, LPDWORD lpDispos ) { LPWSTR lpszSubKeyW,lpszClassW; DWORD ret; dprintf_reg(stddeb,"RegCreateKeyExA(%lx,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", (LONG)hkey, lpszSubKey, dwReserved, lpszClass, fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos ); if (lpszSubKey) lpszSubKeyW=strdupA2W(lpszSubKey); else lpszSubKeyW=NULL; if (lpszClass) lpszClassW=strdupA2W(lpszClass); else lpszClassW=NULL; ret=RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW, fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos ); if (lpszSubKeyW) free(lpszSubKeyW); if (lpszClassW) free(lpszClassW); return ret; } /* RegCreateKeyA [ADVAPI32.129] */ WINAPI DWORD RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey ) { DWORD junk; dprintf_reg(stddeb,"RegCreateKeyA(%lx,%s,%p)\n", (LONG)hkey,lpszSubKey,retkey ); return RegCreateKeyExA( hkey, /* key handle */ lpszSubKey, /* subkey name */ 0, /* reserved = 0 */ NULL, /* lpszClass? FIXME: ? */ REG_OPTION_NON_VOLATILE,/* options */ KEY_ALL_ACCESS, /* desired access attribs */ NULL, /* lpsecurity attributes */ retkey, /* lpretkey */ &junk /* disposition value */ ); } /* RegCreateKey [SHELL.2] [KERNEL.218] */ WINAPI DWORD RegCreateKey( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey ) { dprintf_reg(stddeb,"RegCreateKey(%lx,%s,%p)\n", (LONG)hkey,lpszSubKey,retkey ); return RegCreateKeyA(hkey,lpszSubKey,retkey); } /* * Query Value Functions * Win32 differs between keynames and valuenames. * multiple values may belong to one key, the special value * with name NULL is the default value used by the win31 * compat functions. * * Callpath: * RegQueryValue -> RegQueryValueA -> RegQueryValueExA \ * RegQueryValueW -> RegQueryValueExW */ /* RegQueryValueExW [ADVAPI32.158] */ WINAPI DWORD RegQueryValueExW( HKEY hkey, LPWSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { LPKEYSTRUCT lpkey; int i; dprintf_reg(stddeb,"RegQueryValueExW(%lx,%s,%p,%p,%p,%p)\n", hkey,W2C(lpszValueName,0),lpdwReserved,lpdwType,lpbData,lpcbData ); lpkey = lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (lpszValueName==NULL) { for (i=0;inrofvalues;i++) if (lpkey->values[i].name==NULL) break; } else { for (i=0;inrofvalues;i++) if (!strcmpW(lpszValueName,lpkey->values[i].name)) break; } if (i==lpkey->nrofvalues) { if (lpszValueName==NULL) { *(WCHAR*)lpbData = 0; *lpcbData = 2; *lpdwType = REG_SZ; return SHELL_ERROR_SUCCESS; } return SHELL_ERROR_BADKEY;/*FIXME: correct return? */ } if (lpdwType) *lpdwType = lpkey->values[i].type; if (lpbData==NULL) { if (lpcbData==NULL) return SHELL_ERROR_SUCCESS; *lpcbData = lpkey->values[i].len; return SHELL_ERROR_SUCCESS; } if (*lpcbDatavalues[i].len) { *(WCHAR*)lpbData = 0; *lpcbData = lpkey->values[i].len; return ERROR_MORE_DATA; } memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len); *lpcbData = lpkey->values[i].len; return SHELL_ERROR_SUCCESS; } /* RegQueryValueW [ADVAPI32.159] */ WINAPI DWORD RegQueryValueW( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData, LPDWORD lpcbData ) { HKEY xhkey; DWORD ret,lpdwType; dprintf_reg(stddeb,"RegQueryValueW(%lx,%s,%p,%p)\n->", hkey,W2C(lpszSubKey,0),lpszData,lpcbData ); /* only open subkey, if we really do descend */ if (lpszSubKey && *lpszSubKey) { ret = RegOpenKeyW(hkey,lpszSubKey,&xhkey); if (ret!=ERROR_SUCCESS) return ret; } else xhkey = hkey; lpdwType = REG_SZ; ret = RegQueryValueExW( xhkey, NULL, /* varname NULL -> compat */ NULL, /* lpdwReserved, must be NULL */ &lpdwType, (LPBYTE)lpszData, lpcbData ); if (xhkey!=hkey) RegCloseKey(xhkey); return ret; } /* RegQueryValueExA [ADVAPI32.157] */ WINAPI DWORD RegQueryValueExA( HKEY hkey, LPSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { LPWSTR lpszValueNameW; LPBYTE buf; DWORD ret,myxlen; DWORD *mylen; dprintf_reg(stddeb,"RegQueryValueExA(%lx,%s,%p,%p,%p,%p)\n->", hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData ); if (lpbData) { /* double buffer */ buf = (LPBYTE)xmalloc((*lpcbData)*2); myxlen = *lpcbData*2; mylen = &myxlen; } else { buf=NULL; if (lpcbData) { myxlen = *lpcbData*2; mylen = &myxlen; } mylen = NULL; } if (lpszValueName) lpszValueNameW=strdupA2W(lpszValueName); else lpszValueNameW=NULL; ret=RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, buf, mylen ); if (ret==ERROR_SUCCESS) { if (buf) { if (UNICONVMASK & (1<<(*lpdwType))) { /* convert UNICODE to ASCII */ strcpyWA(lpbData,(LPWSTR)buf); *lpcbData = myxlen/2; } else { if (myxlen>*lpcbData) ret = ERROR_MORE_DATA; else memcpy(lpbData,buf,myxlen); *lpcbData = myxlen; } } else { if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData) *lpcbData = myxlen/2; } } else { if ((UNICONVMASK & (1<<(*lpdwType))) && lpcbData) *lpcbData = myxlen/2; } if (buf) free(buf); return ret; } /* RegQueryValueEx [KERNEL.225] */ WINAPI DWORD RegQueryValueEx( HKEY hkey, LPSTR lpszValueName, LPDWORD lpdwReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { dprintf_reg(stddeb,"RegQueryValueEx(%lx,%s,%p,%p,%p,%p)\n", hkey,lpszValueName,lpdwReserved,lpdwType,lpbData,lpcbData ); return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType, lpbData, lpcbData ); } /* RegQueryValueA [ADVAPI32.156] */ WINAPI DWORD RegQueryValueA( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData, LPDWORD lpcbData ) { HKEY xhkey; DWORD ret,lpdwType; dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n", hkey,lpszSubKey,lpszData,lpcbData ); /* only open subkey, if we really do descend */ if (lpszSubKey && *lpszSubKey) { ret = RegOpenKey(hkey,lpszSubKey,&xhkey); if (ret!=ERROR_SUCCESS) return ret; } else xhkey = hkey; lpdwType = REG_SZ; ret = RegQueryValueExA( xhkey, NULL, /* lpszValueName NULL -> compat */ NULL, /* lpdwReserved, must be NULL */ &lpdwType, (LPBYTE)lpszData, lpcbData ); if (xhkey!=hkey) RegCloseKey(xhkey); return ret; } /* RegQueryValue [SHELL.6] [KERNEL.224] */ WINAPI DWORD RegQueryValue( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData, LPDWORD lpcbData ) { dprintf_reg(stddeb,"RegQueryValueA(%lx,%s,%p,%p)\n", hkey,lpszSubKey,lpszData,lpcbData ); return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData); } /* * Setting values of Registry keys * * Callpath: * RegSetValue -> RegSetValueA -> RegSetValueExA \ * RegSetValueW -> RegSetValueExW */ /* RegSetValueExW [ADVAPI32.170] */ WINAPI DWORD RegSetValueExW( HKEY hkey, LPWSTR lpszValueName, DWORD dwReserved, DWORD dwType, LPBYTE lpbData, DWORD cbData ) { LPKEYSTRUCT lpkey; int i; dprintf_reg(stddeb,"RegSetValueExW(%lx,%s,%ld,%ld,%p,%ld)\n", hkey,W2C(lpszValueName,0),dwReserved,dwType,lpbData,cbData ); /* we no longer care about the lpbData dwType here... */ lpkey = lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (lpszValueName==NULL) { for (i=0;inrofvalues;i++) if (lpkey->values[i].name==NULL) break; } else { for (i=0;inrofvalues;i++) if (!strcmpW(lpszValueName,lpkey->values[i].name)) break; } if (i==lpkey->nrofvalues) { lpkey->values = (LPKEYVALUE)xrealloc( lpkey->values, (lpkey->nrofvalues+1)*sizeof(KEYVALUE) ); lpkey->nrofvalues++; memset(lpkey->values+i,'\0',sizeof(KEYVALUE)); } if (lpkey->values[i].name==NULL) if (lpszValueName) lpkey->values[i].name = strdupW(lpszValueName); else lpkey->values[i].name = NULL; lpkey->values[i].len = cbData; lpkey->values[i].type = dwType; if (lpkey->values[i].data !=NULL) free(lpkey->values[i].data); lpkey->values[i].data = (LPBYTE)xmalloc(cbData); memcpy(lpkey->values[i].data,lpbData,cbData); return SHELL_ERROR_SUCCESS; } /* RegSetValueExA [ADVAPI32.169] */ WINAPI DWORD RegSetValueExA( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved, DWORD dwType, LPBYTE lpbData, DWORD cbData ) { LPBYTE buf; LPWSTR lpszValueNameW; DWORD ret; dprintf_reg(stddeb,"RegSetValueExA(%lx,%s,%ld,%ld,%p,%ld)\n->", hkey,lpszValueName,dwReserved,dwType,lpbData,cbData ); if ((1<", hkey,lpszValueName,dwReserved,dwType,lpbData,cbData ); return RegSetValueExA(hkey,lpszValueName,dwReserved,dwType,lpbData,cbData); } /* RegSetValueW [ADVAPI32.171] */ WINAPI DWORD RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType, LPCWSTR lpszData, DWORD cbData ) { HKEY xhkey; DWORD ret; dprintf_reg(stddeb,"RegSetValueW(%lx,%s,%ld,%s,%ld)\n->", hkey,W2C(lpszSubKey,0),dwType,W2C(lpszData,0),cbData ); if (lpszSubKey && *lpszSubKey) { ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey); if (ret!=ERROR_SUCCESS) return ret; } else xhkey=hkey; if (dwType!=REG_SZ) { fprintf(stddeb,"RegSetValueX called with dwType=%ld!\n",dwType); dwType=REG_SZ; } if (cbData!=2*strlenW(lpszData)+2) { dprintf_reg(stddeb,"RegSetValueX called with len=%ld != strlen(%s)+1=%d!\n", cbData,W2C(lpszData,0),2*strlenW(lpszData)+2 ); cbData=2*strlenW(lpszData)+2; } ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData); if (hkey!=xhkey) RegCloseKey(xhkey); return ret; } /* RegSetValueA [ADVAPI32.168] */ WINAPI DWORD RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType, LPCSTR lpszData, DWORD cbData ) { DWORD ret; HKEY xhkey; dprintf_reg(stddeb,"RegSetValueA(%lx,%s,%ld,%s,%ld)\n->", hkey,lpszSubKey,dwType,lpszData,cbData ); if (lpszSubKey && *lpszSubKey) { ret=RegCreateKey(hkey,lpszSubKey,&xhkey); if (ret!=ERROR_SUCCESS) return ret; } else xhkey=hkey; if (dwType!=REG_SZ) { dprintf_reg(stddeb,"RegSetValueA called with dwType=%ld!\n",dwType); dwType=REG_SZ; } if (cbData!=strlen(lpszData)+1) cbData=strlen(lpszData)+1; ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData); if (xhkey!=hkey) RegCloseKey(xhkey); return ret; } /* RegSetValue [KERNEL.221] [SHELL.5] */ WINAPI DWORD RegSetValue( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType, LPCSTR lpszData, DWORD cbData ) { DWORD ret; dprintf_reg(stddeb,"RegSetValue(%lx,%s,%ld,%s,%ld)\n->", hkey,lpszSubKey,dwType,lpszData,cbData ); ret=RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData); return ret; } /* * Key Enumeration * * Callpath: * RegEnumKey -> RegEnumKeyA -> RegEnumKeyExA \ * RegEnumKeyW -> RegEnumKeyExW */ /* RegEnumKeyExW [ADVAPI32.139] */ WINAPI DWORD RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, LPDWORD lpcchName, LPDWORD lpdwReserved, LPWSTR lpszClass, LPDWORD lpcchClass, FILETIME *ft ) { LPKEYSTRUCT lpkey,lpxkey; dprintf_reg(stddeb,"RegEnumKeyExW(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n", hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft ); lpkey=lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (!lpkey->nextsub) return ERROR_NO_MORE_ITEMS; lpxkey=lpkey->nextsub; while (iSubkey && lpxkey) { iSubkey--; lpxkey=lpxkey->next; } if (iSubkey || !lpxkey) return ERROR_NO_MORE_ITEMS; if (2*strlenW(lpxkey->keyname)+2>*lpcchName) return ERROR_MORE_DATA; memcpy(lpszName,lpxkey->keyname,strlenW(lpxkey->keyname)*2+2); if (lpszClass) { /* what should we write into it? */ *lpszClass = 0; *lpcchClass = 2; } return ERROR_SUCCESS; } /* RegEnumKeyW [ADVAPI32.140] */ WINAPI DWORD RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName, DWORD lpcchName ) { FILETIME ft; dprintf_reg(stddeb,"RegEnumKeyW(%lx,%ld,%p,%ld)\n->", hkey,iSubkey,lpszName,lpcchName ); return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft); } /* RegEnumKeyExA [ADVAPI32.138] */ WINAPI DWORD RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName, LPDWORD lpcchName, LPDWORD lpdwReserved, LPSTR lpszClass, LPDWORD lpcchClass, FILETIME *ft ) { DWORD ret,lpcchNameW,lpcchClassW; LPWSTR lpszNameW,lpszClassW; dprintf_reg(stddeb,"RegEnumKeyExA(%lx,%ld,%p,%ld,%p,%p,%p,%p)\n->", hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft ); if (lpszName) { lpszNameW = (LPWSTR)xmalloc(*lpcchName*2); lpcchNameW = *lpcchName*2; } else { lpszNameW = NULL; lpcchNameW = 0; } if (lpszClass) { lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2); lpcchClassW = *lpcchClass*2; } else { lpszClassW =0; lpcchClassW=0; } ret=RegEnumKeyExW( hkey, iSubkey, lpszNameW, &lpcchNameW, lpdwReserved, lpszClassW, &lpcchClassW, ft ); if (ret==ERROR_SUCCESS) { strcpyWA(lpszName,lpszNameW); *lpcchName=strlen(lpszName); if (lpszClassW) { strcpyWA(lpszClass,lpszClassW); *lpcchClass=strlen(lpszClass); } } if (lpszNameW) free(lpszNameW); if (lpszClassW) free(lpszClassW); return ret; } /* RegEnumKeyA [ADVAPI32.137] */ WINAPI DWORD RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName, DWORD lpcchName ) { FILETIME ft; dprintf_reg(stddeb,"RegEnumKeyA(%lx,%ld,%p,%ld)\n->", hkey,iSubkey,lpszName,lpcchName ); return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL, NULL, &ft ); } /* RegEnumKey [SHELL.7] [KERNEL.216] */ WINAPI DWORD RegEnumKey( HKEY hkey, DWORD iSubkey, LPSTR lpszName, DWORD lpcchName ) { dprintf_reg(stddeb,"RegEnumKey(%lx,%ld,%p,%ld)\n->", hkey,iSubkey,lpszName,lpcchName ); return RegEnumKeyA(hkey,iSubkey,lpszName,lpcchName); } /* * Enumerate Registry Values * * Callpath: * RegEnumValue -> RegEnumValueA -> RegEnumValueW */ /* RegEnumValueW [ADVAPI32.142] */ WINAPI DWORD RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue, LPDWORD lpcchValue, LPDWORD lpdReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { LPKEYSTRUCT lpkey; LPKEYVALUE val; dprintf_reg(stddeb,"RegEnumValueW(%ld,%ld,%p,%p,%p,%p,%p,%p)\n", hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData ); lpkey = lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (lpkey->nrofvaluesvalues+iValue; if (val->name) { if (strlenW(val->name)*2+2>*lpcchValue) { *lpcchValue = strlenW(val->name)*2+2; return ERROR_MORE_DATA; } memcpy(lpszValue,val->name,2*strlenW(val->name)+2); *lpcchValue=strlenW(val->name)*2+2; } else { /* how to handle NULL value? */ *lpszValue = 0; *lpcchValue = 2; } *lpdwType=val->type; if (lpbData) { if (val->len>*lpcbData) return ERROR_MORE_DATA; memcpy(lpbData,val->data,val->len); *lpcbData = val->len; } return SHELL_ERROR_SUCCESS; } /* RegEnumValueA [ADVAPI32.141] */ WINAPI DWORD RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue, LPDWORD lpcchValue, LPDWORD lpdReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { LPWSTR lpszValueW; LPBYTE lpbDataW; DWORD ret,lpcbDataW; dprintf_reg(stddeb,"RegEnumValueA(%ld,%ld,%p,%p,%p,%p,%p,%p)\n", hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData ); lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2); if (lpbData) { lpbDataW = (LPBYTE)xmalloc(*lpcbData*2); lpcbDataW = *lpcbData*2; } else lpbDataW = NULL; ret=RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue, lpdReserved, lpdwType, lpbDataW, &lpcbDataW ); if (ret==ERROR_SUCCESS) { strcpyWA(lpszValue,lpszValueW); if (lpbData) { if ((1<<*lpdwType) & UNICONVMASK) { strcpyWA(lpbData,(LPWSTR)lpbDataW); } else { if (lpcbDataW > *lpcbData) ret = ERROR_MORE_DATA; else memcpy(lpbData,lpbDataW,lpcbDataW); } *lpcbData = lpcbDataW; } } if (lpbDataW) free(lpbDataW); if (lpszValueW) free(lpszValueW); return ret; } /* RegEnumValue [KERNEL.223] */ WINAPI DWORD RegEnumValue( HKEY hkey, DWORD iValue, LPSTR lpszValue, LPDWORD lpcchValue, LPDWORD lpdReserved, LPDWORD lpdwType, LPBYTE lpbData, LPDWORD lpcbData ) { dprintf_reg(stddeb,"RegEnumValue(%ld,%ld,%p,%p,%p,%p,%p,%p)\n", hkey,iValue,lpszValue,lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData ); return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved, lpdwType, lpbData, lpcbData ); } /* * Close registry key */ /* RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126] */ WINAPI DWORD RegCloseKey(HKEY hkey) { dprintf_reg(stddeb,"RegCloseKey(%ld)\n",hkey); remove_handle(hkey); return ERROR_SUCCESS; } /* * Delete registry key * * Callpath: * RegDeleteKey -> RegDeleteKeyA -> RegDeleteKeyW */ /* RegDeleteKeyW [ADVAPI32.134] */ WINAPI DWORD RegDeleteKeyW(HKEY hkey,LPWSTR lpszSubKey) { LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey; LPWSTR *wps; int wpc,i; dprintf_reg(stddeb,"RegDeleteKeyW(%ld,%s)\n", hkey,W2C(lpszSubKey,0) ); lpNextKey = lookup_hkey(hkey); if (!lpNextKey) return SHELL_ERROR_BADKEY; /* we need to know the previous key in the hier. */ if (!lpszSubKey || !*lpszSubKey) return SHELL_ERROR_BADKEY; split_keypath(lpszSubKey,&wps,&wpc); i = 0; lpxkey = lpNextKey; while (inextsub; while (lpxkey) { if (!strcmpW(wps[i],lpxkey->keyname)) break; lpxkey=lpxkey->next; } if (!lpxkey) { FREE_KEY_PATH; /* not found is success */ return SHELL_ERROR_SUCCESS; } i++; lpNextKey = lpxkey; } lpxkey = lpNextKey->nextsub; lplpPrevKey = &(lpNextKey->nextsub); while (lpxkey) { if (!strcmpW(wps[i],lpxkey->keyname)) break; lplpPrevKey = &(lpxkey->next); lpxkey = lpxkey->next; } if (!lpxkey) return SHELL_ERROR_SUCCESS; if (lpxkey->nextsub) return SHELL_ERROR_CANTWRITE; *lplpPrevKey = lpxkey->next; free(lpxkey->keyname); if (lpxkey->class) free(lpxkey->class); if (lpxkey->values) free(lpxkey->values); free(lpxkey); FREE_KEY_PATH; return SHELL_ERROR_SUCCESS; } /* RegDeleteKeyA [ADVAPI32.133] */ WINAPI DWORD RegDeleteKeyA(HKEY hkey,LPCSTR lpszSubKey) { LPWSTR lpszSubKeyW; DWORD ret; dprintf_reg(stddeb,"RegDeleteKeyA(%ld,%s)\n", hkey,lpszSubKey ); lpszSubKeyW=strdupA2W(lpszSubKey); ret=RegDeleteKeyW(hkey,lpszSubKeyW); free(lpszSubKeyW); return ret; } /* RegDeleteKey [SHELL.4] [KERNEL.219] */ WINAPI DWORD RegDeleteKey(HKEY hkey,LPCSTR lpszSubKey) { dprintf_reg(stddeb,"RegDeleteKey(%ld,%s)\n", hkey,lpszSubKey ); return RegDeleteKeyA(hkey,lpszSubKey); } /* * Delete registry value * * Callpath: * RegDeleteValue -> RegDeleteValueA -> RegDeleteValueW */ /* RegDeleteValueW [ADVAPI32.136] */ WINAPI DWORD RegDeleteValueW(HKEY hkey,LPWSTR lpszValue) { DWORD i; LPKEYSTRUCT lpkey; LPKEYVALUE val; dprintf_reg(stddeb,"RegDeleteValueW(%ld,%s)\n", hkey,W2C(lpszValue,0) ); lpkey=lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (lpszValue) { for (i=0;inrofvalues;i++) if (!strcmpW(lpkey->values[i].name,lpszValue)) break; } else { for (i=0;inrofvalues;i++) if (lpkey->values[i].name==NULL) break; } if (i==lpkey->nrofvalues) return SHELL_ERROR_BADKEY;/*FIXME: correct errorcode? */ val = lpkey->values+i; if (val->name) free(val->name); if (val->data) free(val->data); memcpy( lpkey->values+i, lpkey->values+i+1, sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1) ); lpkey->values = (LPKEYVALUE)xrealloc( lpkey->values, (lpkey->nrofvalues-1)*sizeof(KEYVALUE) ); lpkey->nrofvalues--; return SHELL_ERROR_SUCCESS; } /* RegDeleteValueA [ADVAPI32.135] */ WINAPI DWORD RegDeleteValueA(HKEY hkey,LPSTR lpszValue) { LPWSTR lpszValueW; DWORD ret; dprintf_reg(stddeb,"RegDeleteValueA(%ld,%s)\n", hkey,lpszValue ); if (lpszValue) lpszValueW=strdupA2W(lpszValue); else lpszValueW=NULL; ret=RegDeleteValueW(hkey,lpszValueW); if (lpszValueW) free(lpszValueW); return ret; } /* RegDeleteValue [KERNEL.222] */ WINAPI DWORD RegDeleteValue(HKEY hkey,LPSTR lpszValue) { dprintf_reg(stddeb,"RegDeleteValue(%ld,%s)\n", hkey,lpszValue ); return RegDeleteValueA(hkey,lpszValue); } /* RegFlushKey [ADVAPI32.143] [KERNEL.227] */ WINAPI DWORD RegFlushKey(HKEY hkey) { dprintf_reg(stddeb,"RegFlushKey(%ld), STUB.\n",hkey); return SHELL_ERROR_SUCCESS; } /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */ /* RegQueryInfoKeyW [ADVAPI32.153] */ WINAPI DWORD RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass, LPDWORD lpcchClass, LPDWORD lpdwReserved, LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass, LPDWORD lpcValues, LPDWORD lpcchMaxValueName, LPDWORD lpccbMaxValueData, LPDWORD lpcbSecurityDescriptor, FILETIME *ft ) { LPKEYSTRUCT lpkey,lpxkey; int nrofkeys,maxsubkey,maxclass,maxvalues,maxvname,maxvdata; int i; dprintf_reg(stddeb,"RegQueryInfoKeyW(%lx,......)\n",hkey); lpkey=lookup_hkey(hkey); if (!lpkey) return SHELL_ERROR_BADKEY; if (lpszClass) { if (lpkey->class) { if (strlenW(lpkey->class)*2+2>*lpcchClass) { *lpcchClass=strlenW(lpkey->class)*2; return ERROR_MORE_DATA; } *lpcchClass=strlenW(lpkey->class)*2; memcpy(lpszClass,lpkey->class,strlenW(lpkey->class)); } else { *lpszClass = 0; *lpcchClass = 0; } } else { if (lpcchClass) *lpcchClass = strlenW(lpkey->class)*2; } lpxkey=lpkey->nextsub; nrofkeys=maxsubkey=maxclass=maxvalues=maxvname=maxvdata=0; while (lpxkey) { nrofkeys++; if (strlenW(lpxkey->keyname)>maxsubkey) maxsubkey=strlenW(lpxkey->keyname); if (lpxkey->class && strlenW(lpxkey->class)>maxclass) maxclass=strlenW(lpxkey->class); if (lpxkey->nrofvalues>maxvalues) maxvalues=lpxkey->nrofvalues; for (i=0;inrofvalues;i++) { LPKEYVALUE val=lpxkey->values+i; if (val->name && strlenW(val->name)>maxvname) maxvname=strlenW(val->name); if (val->len>maxvdata) maxvdata=val->len; } lpxkey=lpxkey->next; } if (!maxclass) maxclass = 1; if (!maxvname) maxvname = 1; if (lpcSubKeys) *lpcSubKeys = nrofkeys; if (lpcchMaxSubkey) *lpcchMaxSubkey = maxsubkey*2; if (lpcchMaxClass) *lpcchMaxClass = maxclass*2; if (lpcValues) *lpcValues = maxvalues; if (lpcchMaxValueName) *lpcchMaxValueName= maxvname; if (lpccbMaxValueData) *lpccbMaxValueData= maxvdata; return SHELL_ERROR_SUCCESS; } /* RegQueryInfoKeyA [ADVAPI32.152] */ WINAPI DWORD RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass, LPDWORD lpdwReserved, LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass, LPDWORD lpcValues, LPDWORD lpcchMaxValueName, LPDWORD lpccbMaxValueData, LPDWORD lpcbSecurityDescriptor, FILETIME *ft ) { LPWSTR lpszClassW; DWORD ret; dprintf_reg(stddeb,"RegQueryInfoKeyA(%lx,......)\n",hkey); if (lpszClass) { *lpcchClass*= 2; lpszClassW = (LPWSTR)xmalloc(*lpcchClass); } else lpszClassW = NULL; ret=RegQueryInfoKeyW( hkey, lpszClassW, lpcchClass, lpdwReserved, lpcSubKeys, lpcchMaxSubkey, lpcchMaxClass, lpcValues, lpcchMaxValueName, lpccbMaxValueData, lpcbSecurityDescriptor, ft ); if (ret==ERROR_SUCCESS) strcpyWA(lpszClass,lpszClassW); if (lpcchClass) *lpcchClass/=2; if (lpcchMaxSubkey) *lpcchMaxSubkey/=2; if (lpcchMaxClass) *lpcchMaxClass/=2; if (lpcchMaxValueName) *lpcchMaxValueName/=2; if (lpszClassW) free(lpszClassW); return ret; }