4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
19 * Time for RegEnumKey*, RegQueryInfoKey*
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
35 #include "wine/winbase16.h"
36 #include "wine/winestring.h"
40 #include "debugtools.h"
44 #include "winversion.h"
46 DECLARE_DEBUG_CHANNEL(reg)
47 DECLARE_DEBUG_CHANNEL(string)
49 static void REGISTRY_Init(void);
50 /* FIXME: following defines should be configured global ... */
52 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
53 #define WINE_PREFIX "/.wine"
54 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
55 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
57 /* relative in ~user/.wine/ : */
58 #define SAVE_CURRENT_USER "user.reg"
59 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
60 #define SAVE_LOCAL_MACHINE "system.reg"
62 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
63 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
65 /* one value of a key */
66 typedef struct tagKEYVALUE
68 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
69 DWORD type; /* type of value */
70 DWORD len; /* length of data in BYTEs */
71 DWORD lastmodified; /* time of seconds since 1.1.1970 */
72 LPBYTE data; /* content, may be strings, binaries, etc. */
73 } KEYVALUE,*LPKEYVALUE;
76 typedef struct tagKEYSTRUCT
78 LPWSTR keyname; /* name of THIS key (UNICODE) */
79 DWORD flags; /* flags. */
82 DWORD nrofvalues; /* nr of values in THIS key */
83 LPKEYVALUE values; /* values in THIS key */
84 /* key management pointers */
85 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
86 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
87 } KEYSTRUCT, *LPKEYSTRUCT;
90 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
91 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
92 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
93 static KEYSTRUCT *key_users=NULL; /* all users? */
95 /* dynamic, not saved */
96 static KEYSTRUCT *key_performance_data=NULL;
97 static KEYSTRUCT *key_current_config=NULL;
98 static KEYSTRUCT *key_dyn_data=NULL;
100 /* what valuetypes do we need to convert? */
101 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
104 static struct openhandle {
109 static int nrofopenhandles=0;
110 /* Starts after 1 because 0,1 are reserved for Win16 */
111 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
112 HKEYs for remote registry access */
113 static int currenthandle=2;
118 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
119 * If so, can we remove them?
121 * No, the memory handling functions are called very often in here,
122 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
123 * loading 100 times slower. -MM
125 static LPWSTR strdupA2W(LPCSTR src)
128 LPWSTR dest=xmalloc(2*strlen(src)+2);
129 lstrcpyAtoW(dest,src);
135 static LPWSTR strdupW(LPCWSTR a) {
140 len=sizeof(WCHAR)*(lstrlenW(a)+1);
141 b=(LPWSTR)xmalloc(len);
148 LPWSTR strcvtA2W(LPCSTR src, int nchars)
151 LPWSTR dest = xmalloc (2 * nchars + 2);
153 lstrcpynAtoW(dest,src,nchars+1);
158 * we need to convert A to W with '\0' in strings (MULTI_SZ)
161 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
164 TRACE_(reg)("\"%s\" %i\n",src, n);
166 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
170 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
173 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
175 while (n-- > 0) *p++ = (CHAR)*src++;
180 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
182 if (TRACE_ON(reg) && lpbData)
186 case HEX_REG_EXPAND_SZ:
189 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
190 debugstr_w(key->name),
191 debugstr_w((LPCWSTR)lpbData));
196 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key->name),
201 case HEX_REG_MULTI_SZ:
205 LPCWSTR ptr = (LPCWSTR)lpbData;
208 TRACE_(reg)(" Value %s, MULTI_SZ(%i=%s)\n",
209 debugstr_w(key->name),
213 ptr += lstrlenW(ptr)+1;
221 case HEX_REG_RESOURCE_LIST:
222 case HEX_REG_FULL_RESOURCE_DESCRIPTOR:
225 case REG_RESOURCE_LIST:
226 case REG_FULL_RESOURCE_DESCRIPTOR:
229 char szTemp[100]; /* 3*32 + 3 + 1 */
231 for ( i = 0; i < key->len ; i++)
233 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
236 sprintf (&(szTemp[i*3+3]),"...");
240 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
241 debugstr_w(key->name),
247 FIXME_(reg)(" Value %s, Unknown data type %ld\n",
248 debugstr_w(key->name),
255 /******************************************************************************
256 * is_standard_hkey [Internal]
257 * Determines if a hkey is a standard key
259 static BOOL is_standard_hkey( HKEY hkey )
264 case HKEY_CLASSES_ROOT:
265 case HKEY_CURRENT_CONFIG:
266 case HKEY_CURRENT_USER:
267 case HKEY_LOCAL_MACHINE:
269 case HKEY_PERFORMANCE_DATA:
277 /******************************************************************************
278 * add_handle [Internal]
280 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
284 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
285 /* Check for duplicates */
286 for (i=0;i<nrofopenhandles;i++) {
287 if (openhandles[i].lpkey==lpkey) {
288 /* This is not really an error - the user is allowed to create
289 two (or more) handles to the same key */
290 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
292 if (openhandles[i].hkey==hkey) {
293 WARN_(reg)("Adding handle %x twice\n",hkey);
296 openhandles=xrealloc( openhandles,
297 sizeof(struct openhandle)*(nrofopenhandles+1));
299 openhandles[i].lpkey = lpkey;
300 openhandles[i].hkey = hkey;
301 openhandles[i].accessmask = accessmask;
306 /******************************************************************************
307 * get_handle [Internal]
310 * Success: Pointer to key
313 static LPKEYSTRUCT get_handle( HKEY hkey )
317 for (i=0; i<nrofopenhandles; i++)
318 if (openhandles[i].hkey == hkey)
319 return openhandles[i].lpkey;
320 WARN_(reg)("Could not find handle 0x%x\n",hkey);
325 /******************************************************************************
326 * remove_handle [Internal]
329 * hkey [I] Handle of key to remove
332 * Success: ERROR_SUCCESS
333 * Failure: ERROR_INVALID_HANDLE
335 static DWORD remove_handle( HKEY hkey )
339 for (i=0;i<nrofopenhandles;i++)
340 if (openhandles[i].hkey==hkey)
343 if (i == nrofopenhandles) {
344 WARN_(reg)("Could not find handle 0x%x\n",hkey);
345 return ERROR_INVALID_HANDLE;
348 memcpy( openhandles+i,
350 sizeof(struct openhandle)*(nrofopenhandles-i-1)
352 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
354 return ERROR_SUCCESS;
357 /******************************************************************************
358 * lookup_hkey [Internal]
360 * Just as the name says. Creates the root keys on demand, so we can call the
361 * Reg* functions at any time.
364 * Success: Pointer to key structure
367 #define ADD_ROOT_KEY(xx) \
368 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
369 memset(xx,'\0',sizeof(KEYSTRUCT));\
370 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
372 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
375 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
376 * some programs. Do not remove those cases. -MM
380 case HKEY_CLASSES_ROOT:
382 if (!key_classes_root)
386 /* calls lookup_hkey recursively, TWICE */
390 &cl_r_hkey) != ERROR_SUCCESS)
392 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
396 key_classes_root = lookup_hkey(cl_r_hkey);
398 return key_classes_root;
401 case HKEY_CURRENT_USER:
402 if (!key_current_user) {
403 ADD_ROOT_KEY(key_current_user);
405 return key_current_user;
407 case HKEY_LOCAL_MACHINE:
408 if (!key_local_machine) {
409 ADD_ROOT_KEY(key_local_machine);
412 return key_local_machine;
416 ADD_ROOT_KEY(key_users);
420 case HKEY_PERFORMANCE_DATA:
421 if (!key_performance_data) {
422 ADD_ROOT_KEY(key_performance_data);
424 return key_performance_data;
428 ADD_ROOT_KEY(key_dyn_data);
432 case HKEY_CURRENT_CONFIG:
433 if (!key_current_config) {
434 ADD_ROOT_KEY(key_current_config);
436 return key_current_config;
439 return get_handle(hkey);
445 /* so we don't accidently access them ... */
446 #define key_current_config NULL NULL
447 #define key_current_user NULL NULL
448 #define key_users NULL NULL
449 #define key_local_machine NULL NULL
450 #define key_classes_root NULL NULL
451 #define key_dyn_data NULL NULL
452 #define key_performance_data NULL NULL
454 /******************************************************************************
455 * split_keypath [Internal]
456 * splits the unicode string 'wp' into an array of strings.
457 * the array is allocated by this function.
458 * Free the array using FREE_KEY_PATH
461 * wp [I] String to split up
462 * wpv [O] Array of pointers to strings
463 * wpc [O] Number of components
465 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
470 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
472 ws = HEAP_strdupW( SystemHeap, 0, wp );
474 /* We know we have at least one substring */
477 /* Replace each backslash with NULL, and increment the count */
478 for (i=0;ws[i];i++) {
487 /* Allocate the space for the array of pointers, leaving room for the
489 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
492 /* Assign each pointer to the appropriate character in the string */
497 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
502 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
507 /******************************************************************************
508 * REGISTRY_Init [Internal]
509 * Registry initialisation, allocates some default keys.
511 static void REGISTRY_Init(void) {
515 TRACE_(reg)("(void)\n");
517 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
520 /* This was an Open, but since it is called before the real registries
521 are loaded, it was changed to a Create - MTB 980507*/
522 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
523 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
526 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
530 * string RegisteredOwner
531 * string RegisteredOrganization
534 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
539 if (-1!=gethostname(buf,200)) {
540 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
541 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
547 /************************ SAVE Registry Function ****************************/
549 #define REGISTRY_SAVE_VERSION 0x00000001
551 /* Registry saveformat:
552 * If you change it, increase above number by 1, which will flush
553 * old registry database files.
556 * "WINE REGISTRY Version %d"
560 * valuename=lastmodified,type,data
564 * keyname,valuename,stringdata:
565 * the usual ascii characters from 0x00-0xff (well, not 0x00)
566 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
567 * ( "=\\\t" escaped in \uXXXX form.)
571 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
573 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
574 * SaveOnlyUpdatedKeys=yes
577 /******************************************************************************
578 * _save_check_tainted [Internal]
580 static int _save_check_tainted( LPKEYSTRUCT lpkey )
586 if (lpkey->flags & REG_OPTION_TAINTED)
591 if (_save_check_tainted(lpkey->nextsub)) {
592 lpkey->flags |= REG_OPTION_TAINTED;
600 /******************************************************************************
601 * _save_USTRING [Internal]
603 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
617 if (escapeeq && *s=='=')
620 fputc(*s,F); /* if \\ then put it twice. */
622 fprintf(F,"\\u%04x",*((unsigned short*)s));
629 /******************************************************************************
630 * _savesubkey [Internal]
633 * REG_MULTI_SZ is handled as binary (like in win95) (js)
635 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
642 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
643 (all || (lpxkey->flags & REG_OPTION_TAINTED))
645 for (tabs=level;tabs--;)
647 _save_USTRING(F,lpxkey->keyname,1);
649 for (i=0;i<lpxkey->nrofvalues;i++) {
650 LPKEYVALUE val=lpxkey->values+i;
652 for (tabs=level+1;tabs--;)
654 _save_USTRING(F,val->name,0);
656 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
657 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
658 _save_USTRING(F,(LPWSTR)val->data,0);
660 for (j=0;j<val->len;j++)
661 fprintf(F,"%02x",*((unsigned char*)val->data+j));
664 /* descend recursively */
665 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
674 /******************************************************************************
675 * _savesubreg [Internal]
677 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
679 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
680 _save_check_tainted(lpkey->nextsub);
681 return _savesubkey(F,lpkey->nextsub,0,all);
685 /******************************************************************************
686 * _savereg [Internal]
688 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
694 WARN_(reg)("Couldn't open %s for writing: %s\n",
699 if (!_savesubreg(F,lpkey,all)) {
702 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
710 /******************************************************************************
711 * SHELL_SaveRegistry [Internal]
713 void SHELL_SaveRegistry( void )
715 char *fn, *home, *tmp;
722 TRACE_(reg)("(void)\n");
725 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
734 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
739 &len)) || (type!=REG_SZ))
746 if (lstrcmpiA(buf,"yes")) all=1;
748 if (!(home = getenv( "HOME" )))
750 WARN_(reg)("Failed to get homedirectory of UID %d.\n",getuid());
754 * Save HKEY_CURRENT_USER
755 * Try first saving according to the defined location in .winerc
757 fn = xmalloc( MAX_PATHNAME_LEN );
758 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "", fn, MAX_PATHNAME_LEN - 1))
760 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
765 if (usedCfgUser != 1)
767 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
768 strlen(SAVE_CURRENT_USER) + 2 );
770 strcat(fn,WINE_PREFIX);
772 /* create the directory. don't care about errorcodes. */
773 mkdir(fn,0755); /* drwxr-xr-x */
774 strcat(fn,"/"SAVE_CURRENT_USER);
776 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
780 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
781 if (-1==rename(tmp,fn)) {
782 perror("rename tmp registry");
791 * Save HKEY_LOCAL_MACHINE
792 * Try first saving according to the defined location in .winerc
794 fn = xmalloc ( MAX_PATHNAME_LEN);
795 if (PROFILE_GetWineIniString ( "Registry", "LocalMachineFileName", "", fn,
796 MAX_PATHNAME_LEN - 1))
798 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
805 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
807 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
809 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
813 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
814 if (-1==rename(tmp,fn)) {
815 perror("rename tmp registry");
826 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
829 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
831 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
832 strcpy(tmp,fn);strcat(tmp,".tmp");
833 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
834 if (-1==rename(tmp,fn)) {
835 perror("rename tmp registry");
844 /************************ LOAD Registry Function ****************************/
848 /******************************************************************************
849 * _find_or_add_key [Internal]
851 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
853 LPKEYSTRUCT lpxkey,*lplpkey;
855 if ((!keyname) || (keyname[0]==0)) {
859 lplpkey= &(lpkey->nextsub);
862 if ( (lpxkey->keyname[0]==keyname[0]) &&
863 !lstrcmpiW(lpxkey->keyname,keyname)
866 lplpkey = &(lpxkey->next);
870 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
872 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
873 lpxkey->keyname = keyname;
879 /******************************************************************************
880 * _find_or_add_value [Internal]
882 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
883 LPBYTE data, DWORD len, DWORD lastmodified )
888 if (name && !*name) {/* empty string equals default (NULL) value */
893 for (i=0;i<lpkey->nrofvalues;i++) {
899 if ( val->name!=NULL &&
900 val->name[0]==name[0] &&
901 !lstrcmpiW(val->name,name)
906 if (i==lpkey->nrofvalues) {
907 lpkey->values = xrealloc(
909 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
912 memset(val,'\0',sizeof(KEYVALUE));
918 if (val->lastmodified<lastmodified) {
919 val->lastmodified=lastmodified;
922 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
924 data=xmalloc(sizeof(WCHAR));
925 memset(data,0,sizeof(WCHAR));
938 /******************************************************************************
939 * _wine_read_line [Internal]
941 * reads a line including dynamically enlarging the readbuffer and throwing
944 static int _wine_read_line( FILE *F, char **buf, int *len )
954 s=fgets(curread,mylen,F);
957 if (NULL==(s=strchr(curread,'\n'))) {
958 /* buffer wasn't large enough */
959 curoff = strlen(*buf);
960 *buf = xrealloc(*buf,*len*2);
961 curread = *buf + curoff;
962 mylen = *len; /* we filled up the buffer and
963 * got new '*len' bytes to fill
971 /* throw away comments */
972 if (**buf=='#' || **buf==';') {
977 if (s) /* got end of line */
984 /******************************************************************************
985 * _wine_read_USTRING [Internal]
987 * converts a char* into a UNICODE string (up to a special char)
988 * and returns the position exactly after that string
990 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
995 /* read up to "=" or "\0" or "\n" */
998 /* empty string is the win3.1 default value(NULL)*/
1002 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1004 while (*s && (*s!='\n') && (*s!='=')) {
1006 *ws++=*((unsigned char*)s++);
1010 /* Dangling \ ... may only happen if a registry
1011 * write was short. FIXME: What do to?
1021 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1029 memcpy(xbuf,s,4);xbuf[4]='\0';
1030 if (!sscanf(xbuf,"%x",&wc))
1031 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1033 *ws++ =(unsigned short)wc;
1040 *str = strdupW(*str);
1048 /******************************************************************************
1049 * _wine_loadsubkey [Internal]
1052 * It seems like this is returning a boolean. Should it?
1058 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1059 int *buflen, DWORD optflag )
1066 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1069 lpkey->flags |= optflag;
1071 /* Good. We already got a line here ... so parse it */
1081 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1084 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1088 /* let the caller handle this line */
1089 if (i<level || **buf=='\0')
1092 /* it can be: a value or a keyname. Parse the name first */
1093 s=_wine_read_USTRING(s,&name);
1095 /* switch() default: hack to avoid gotos */
1099 lpxkey=_find_or_add_key(lpkey,name);
1102 int len,lastmodified,type;
1105 WARN_(reg)("Unexpected character: %c\n",*s);
1109 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1110 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1114 s=strchr(s,',');s++;
1115 s=strchr(s,',');s++;
1116 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1117 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1119 len = lstrlenW((LPWSTR)data)*2+2;
1124 data = (LPBYTE)xmalloc(len+1);
1125 for (i=0;i<len;i++) {
1127 if (*s>='0' && *s<='9')
1128 data[i]=(*s-'0')<<4;
1129 if (*s>='a' && *s<='f')
1130 data[i]=(*s-'a'+'\xa')<<4;
1131 if (*s>='A' && *s<='F')
1132 data[i]=(*s-'A'+'\xa')<<4;
1134 if (*s>='0' && *s<='9')
1136 if (*s>='a' && *s<='f')
1137 data[i]|=*s-'a'+'\xa';
1138 if (*s>='A' && *s<='F')
1139 data[i]|=*s-'A'+'\xa';
1143 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1146 /* read the next line */
1147 if (!_wine_read_line(F,buf,buflen))
1154 /******************************************************************************
1155 * _wine_loadsubreg [Internal]
1157 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1163 buf=xmalloc(10);buflen=10;
1164 if (!_wine_read_line(F,&buf,&buflen)) {
1168 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1172 if (ver!=REGISTRY_SAVE_VERSION) {
1173 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1177 if (!_wine_read_line(F,&buf,&buflen)) {
1181 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1190 /******************************************************************************
1191 * _wine_loadreg [Internal]
1193 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1197 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1201 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1204 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1212 /******************************************************************************
1213 * _flush_registry [Internal]
1215 * This function allow to flush section of the internal registry. It is mainly
1216 * implements to fix a problem with the global HKU and the local HKU.
1217 * Those two files are read to build the HKU\.Default branch to finaly copy
1218 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1219 * all the global HKU are saved onto the user's personal version of HKU hive.
1223 /* Forward declaration of recusive agent */
1224 static void _flush_reg(LPKEYSTRUCT from);
1226 static void _flush_registry( LPKEYSTRUCT from )
1228 /* make sure we have something... */
1232 /* Launch the recusive agent on sub branches */
1233 _flush_reg( from->nextsub );
1234 _flush_reg( from->next );
1236 /* Initialize pointers */
1237 from->nextsub = NULL;
1240 static void _flush_reg( LPKEYSTRUCT from )
1244 /* make sure we have something... */
1249 * do the same for the child keys
1251 if (from->nextsub != NULL)
1252 _flush_reg(from->nextsub);
1255 * do the same for the sibling keys
1257 if (from->next != NULL)
1258 _flush_reg(from->next);
1261 * iterate through this key's values and delete them
1263 for (j=0;j<from->nrofvalues;j++)
1265 free( (from->values+j)->name);
1266 free( (from->values+j)->data);
1270 * free the structure
1277 /******************************************************************************
1278 * _copy_registry [Internal]
1280 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1288 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1290 for (j=0;j<from->nrofvalues;j++) {
1294 valfrom = from->values+j;
1296 if (name) name=strdupW(name);
1297 data=(LPBYTE)xmalloc(valfrom->len);
1298 memcpy(data,valfrom->data,valfrom->len);
1306 valfrom->lastmodified
1309 _copy_registry(from,lpxkey);
1315 /* WINDOWS 95 REGISTRY LOADER */
1317 * Structure of a win95 registry database.
1319 * 0 : "CREG" - magic
1321 * 8 : DWORD offset_of_RGDB_part
1322 * 0C..0F: ? (someone fill in please)
1323 * 10: WORD number of RGDB blocks
1325 * 14: WORD always 0000?
1326 * 16: WORD always 0001?
1327 * 18..1F: ? (someone fill in please)
1331 * 0 : "RGKN" - magic
1332 * 4 : DWORD offset to first RGDB section
1333 * 8 : DWORD offset to the root record
1334 * C..0x1B: ? (fill in)
1335 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1337 * Disk Key Entry Structure:
1338 * 00: DWORD - Free entry indicator(?)
1339 * 04: DWORD - Hash = sum of bytes of keyname
1340 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1341 * 0C: DWORD - disk address of PreviousLevel Key.
1342 * 10: DWORD - disk address of Next Sublevel Key.
1343 * 14: DWORD - disk address of Next Key (on same level).
1344 * DKEP>18: WORD - Nr, Low Significant part.
1345 * 1A: WORD - Nr, High Significant part.
1347 * The disk address always points to the nr part of the previous key entry
1348 * of the referenced key. Don't ask me why, or even if I got this correct
1349 * from staring at 1kg of hexdumps. (DKEP)
1351 * The High significant part of the structure seems to equal the number
1352 * of the RGDB section. The low significant part is a unique ID within
1355 * There are two minor corrections to the position of that structure.
1356 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1357 * the DKE reread from there.
1358 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1359 * CPS - I have not experienced the above phenomenon in my registry files
1362 * 00: "RGDB" - magic
1363 * 04: DWORD offset to next RGDB section
1365 * 0C: WORD always 000d?
1366 * 0E: WORD RGDB block number
1367 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1369 * 20.....: disk keys
1372 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1373 * 08: WORD nrLS - low significant part of NR
1374 * 0A: WORD nrHS - high significant part of NR
1375 * 0C: DWORD bytesused - bytes used in this structure.
1376 * 10: WORD name_len - length of name in bytes. without \0
1377 * 12: WORD nr_of_values - number of values.
1378 * 14: char name[name_len] - name string. No \0.
1379 * 14+name_len: disk values
1380 * nextkeyoffset: ... next disk key
1383 * 00: DWORD type - value type (hmm, could be WORD too)
1384 * 04: DWORD - unknown, usually 0
1385 * 08: WORD namelen - length of Name. 0 means name=NULL
1386 * 0C: WORD datalen - length of Data.
1387 * 10: char name[namelen] - name, no \0
1388 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1389 * 10+namelen+datalen: next values or disk key
1391 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1392 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1393 * structure) and reading another RGDB_section.
1394 * repeat until end of file.
1396 * An interesting relationship exists in RGDB_section. The value at offset
1397 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1398 * idea at the moment what this means. (Kevin Cozens)
1400 * FIXME: this description needs some serious help, yes.
1403 struct _w95keyvalue {
1405 unsigned short datalen;
1407 unsigned char *data;
1415 struct _w95keyvalue *values;
1416 struct _w95key *prevlvl;
1417 struct _w95key *nextsub;
1418 struct _w95key *next;
1432 /******************************************************************************
1433 * _w95_processKey [Internal]
1435 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1436 int nrLS, int nrMS, struct _w95_info *info )
1439 /* Disk Key Header structure (RGDB part) */
1441 unsigned long nextkeyoff;
1442 unsigned short nrLS;
1443 unsigned short nrMS;
1444 unsigned long bytesused;
1445 unsigned short keynamelen;
1446 unsigned short values;
1449 /* disk key values or nothing */
1451 /* Disk Key Value structure */
1455 unsigned short valnamelen;
1456 unsigned short valdatalen;
1457 /* valname, valdata */
1463 char *rgdbdata = info->rgdbbuffer;
1464 int nbytes = info->rgdbsize;
1465 char *curdata = rgdbdata;
1466 char *end = rgdbdata + nbytes;
1468 char *next = rgdbdata;
1474 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1476 memcpy(&off_next_rgdb,curdata+4,4);
1477 next = curdata + off_next_rgdb;
1478 nrgdb = (int) *((short *)curdata + 7);
1480 } while (nrgdb != nrMS && (next < end));
1482 /* curdata now points to the start of the right RGDB section */
1485 #define XREAD(whereto,len) \
1486 if ((curdata + len) <= end) {\
1487 memcpy(whereto,curdata,len);\
1492 while (curdata < next) {
1493 struct dkh *xdkh = (struct dkh*)curdata;
1495 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1496 if (xdkh->nrLS == nrLS) {
1497 memcpy(&dkh,xdkh,sizeof(dkh));
1498 curdata += sizeof(dkh);
1501 curdata += xdkh->nextkeyoff;
1504 if (dkh.nrLS != nrLS) return (NULL);
1506 if (nrgdb != dkh.nrMS)
1509 assert((dkh.keynamelen<2) || curdata[0]);
1510 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1511 curdata += dkh.keynamelen;
1513 for (i=0;i< dkh.values; i++) {
1519 XREAD(&dkv,sizeof(dkv));
1521 name = strcvtA2W(curdata, dkv.valnamelen);
1522 curdata += dkv.valnamelen;
1524 if ((1 << dkv.type) & UNICONVMASK) {
1525 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1526 len = 2*(dkv.valdatalen + 1);
1528 /* I don't think we want to NULL terminate all data */
1529 data = xmalloc(dkv.valdatalen);
1530 memcpy (data, curdata, dkv.valdatalen);
1531 len = dkv.valdatalen;
1534 curdata += dkv.valdatalen;
1548 /******************************************************************************
1549 * _w95_walkrgkn [Internal]
1551 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1552 struct _w95_info *info )
1555 /* Disk Key Entry structure (RGKN part) */
1559 unsigned long x3;/*usually 0xFFFFFFFF */
1560 unsigned long prevlvl;
1561 unsigned long nextsub;
1563 unsigned short nrLS;
1564 unsigned short nrMS;
1565 } *dke = (struct dke *)off;
1569 dke = (struct dke *) ((char *)info->rgknbuffer);
1572 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1573 /* XXX <-- This is a hack*/
1578 if (dke->nextsub != -1 &&
1579 ((dke->nextsub - 0x20) < info->rgknsize)
1580 && (dke->nextsub > 0x20)) {
1582 _w95_walkrgkn(lpxkey,
1583 info->rgknbuffer + dke->nextsub - 0x20,
1587 if (dke->next != -1 &&
1588 ((dke->next - 0x20) < info->rgknsize) &&
1589 (dke->next > 0x20)) {
1590 _w95_walkrgkn(prevkey,
1591 info->rgknbuffer + dke->next - 0x20,
1599 /******************************************************************************
1600 * _w95_loadreg [Internal]
1602 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1606 unsigned long where,version,rgdbsection,end;
1607 struct _w95_info info;
1609 BY_HANDLE_FILE_INFORMATION hfdinfo;
1611 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1612 hfd=OpenFile(fn,&ofs,OF_READ);
1613 if (hfd==HFILE_ERROR)
1616 if (4!=_lread(hfd,magic,4))
1618 if (strcmp(magic,"CREG")) {
1619 WARN_(reg)("%s is not a w95 registry.\n",fn);
1622 if (4!=_lread(hfd,&version,4))
1624 if (4!=_lread(hfd,&rgdbsection,4))
1626 if (-1==_llseek(hfd,0x20,SEEK_SET))
1628 if (4!=_lread(hfd,magic,4))
1630 if (strcmp(magic,"RGKN")) {
1631 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1635 /* STEP 1: Keylink structures */
1636 if (-1==_llseek(hfd,0x40,SEEK_SET))
1641 info.rgknsize = end - where;
1642 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1643 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1646 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1649 end = hfdinfo.nFileSizeLow;
1650 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1652 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1655 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1656 info.rgdbsize = end - rgdbsection;
1658 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1662 _w95_walkrgkn(lpkey, NULL, &info);
1664 free (info.rgdbbuffer);
1665 free (info.rgknbuffer);
1669 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1672 reghack - windows 3.11 registry data format demo program.
1674 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1675 a combined hash table and tree description, and finally a text table.
1677 The header is obvious from the struct header. The taboff1 and taboff2
1678 fields are always 0x20, and their usage is unknown.
1680 The 8-byte entry table has various entry types.
1682 tabent[0] is a root index. The second word has the index of the root of
1684 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1685 the index of the key/value that has that hash. Data with the same
1686 hash value are on a circular list. The other three words in the
1687 hash entry are always zero.
1688 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1689 entry: dirent and keyent/valent. They are identified by context.
1690 tabent[freeidx] is the first free entry. The first word in a free entry
1691 is the index of the next free entry. The last has 0 as a link.
1692 The other three words in the free list are probably irrelevant.
1694 Entries in text table are preceeded by a word at offset-2. This word
1695 has the value (2*index)+1, where index is the referring keyent/valent
1696 entry in the table. I have no suggestion for the 2* and the +1.
1697 Following the word, there are N bytes of data, as per the keyent/valent
1698 entry length. The offset of the keyent/valent entry is from the start
1699 of the text table to the first data byte.
1701 This information is not available from Microsoft. The data format is
1702 deduced from the reg.dat file by me. Mistakes may
1703 have been made. I claim no rights and give no guarantees for this program.
1705 Tor Sjøwall, tor@sn.no
1708 /* reg.dat header format */
1709 struct _w31_header {
1710 char cookie[8]; /* 'SHCC3.10' */
1711 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1712 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1713 unsigned long tabcnt; /* number of entries in index table */
1714 unsigned long textoff; /* offset of text part */
1715 unsigned long textsize; /* byte size of text part */
1716 unsigned short hashsize; /* hash size */
1717 unsigned short freeidx; /* free index */
1720 /* generic format of table entries */
1721 struct _w31_tabent {
1722 unsigned short w0, w1, w2, w3;
1725 /* directory tabent: */
1726 struct _w31_dirent {
1727 unsigned short sibling_idx; /* table index of sibling dirent */
1728 unsigned short child_idx; /* table index of child dirent */
1729 unsigned short key_idx; /* table index of key keyent */
1730 unsigned short value_idx; /* table index of value valent */
1734 struct _w31_keyent {
1735 unsigned short hash_idx; /* hash chain index for string */
1736 unsigned short refcnt; /* reference count */
1737 unsigned short length; /* length of string */
1738 unsigned short string_off; /* offset of string in text table */
1742 struct _w31_valent {
1743 unsigned short hash_idx; /* hash chain index for string */
1744 unsigned short refcnt; /* reference count */
1745 unsigned short length; /* length of string */
1746 unsigned short string_off; /* offset of string in text table */
1749 /* recursive helper function to display a directory tree */
1751 __w31_dumptree( unsigned short idx,
1753 struct _w31_tabent *tab,
1754 struct _w31_header *head,
1756 time_t lastmodified,
1759 struct _w31_dirent *dir;
1760 struct _w31_keyent *key;
1761 struct _w31_valent *val;
1762 LPKEYSTRUCT xlpkey = NULL;
1764 static char tail[400];
1767 dir=(struct _w31_dirent*)&tab[idx];
1770 key = (struct _w31_keyent*)&tab[dir->key_idx];
1772 memcpy(tail,&txt[key->string_off],key->length);
1773 tail[key->length]='\0';
1774 /* all toplevel entries AND the entries in the
1775 * toplevel subdirectory belong to \SOFTWARE\Classes
1777 if (!level && !lstrcmpA(tail,".classes")) {
1778 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1779 idx=dir->sibling_idx;
1782 name=strdupA2W(tail);
1784 xlpkey=_find_or_add_key(lpkey,name);
1786 /* only add if leaf node or valued node */
1787 if (dir->value_idx!=0||dir->child_idx==0) {
1788 if (dir->value_idx) {
1789 val=(struct _w31_valent*)&tab[dir->value_idx];
1790 memcpy(tail,&txt[val->string_off],val->length);
1791 tail[val->length]='\0';
1792 value=strdupA2W(tail);
1793 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1797 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1799 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1800 idx=dir->sibling_idx;
1805 /******************************************************************************
1806 * _w31_loadreg [Internal]
1808 void _w31_loadreg(void) {
1810 struct _w31_header head;
1811 struct _w31_tabent *tab;
1815 BY_HANDLE_FILE_INFORMATION hfinfo;
1816 time_t lastmodified;
1819 TRACE_(reg)("(void)\n");
1821 hf = OpenFile("reg.dat",&ofs,OF_READ);
1822 if (hf==HFILE_ERROR)
1825 /* read & dump header */
1826 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1827 ERR_(reg)("reg.dat is too short.\n");
1831 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1832 ERR_(reg)("reg.dat has bad signature.\n");
1837 len = head.tabcnt * sizeof(struct _w31_tabent);
1838 /* read and dump index table */
1840 if (len!=_lread(hf,tab,len)) {
1841 ERR_(reg)("couldn't read %d bytes.\n",len);
1848 txt = xmalloc(head.textsize);
1849 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1850 ERR_(reg)("couldn't seek to textblock.\n");
1856 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1857 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1864 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1865 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1871 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1872 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1873 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1881 /**********************************************************************************
1882 * SHELL_LoadRegistry [Internal]
1884 void SHELL_LoadRegistry( void )
1887 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1890 TRACE_(reg)("(void)\n");
1892 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1893 HKU = lookup_hkey(HKEY_USERS);
1894 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1896 /* Load windows 3.1 entries */
1898 /* Load windows 95 entries */
1899 _w95_loadreg("C:\\system.1st", HKLM);
1900 _w95_loadreg("system.dat", HKLM);
1901 _w95_loadreg("user.dat", HKU);
1904 * Load the global HKU hive directly from /usr/local/etc
1906 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1909 * Load the global machine defaults directly form /usr/local/etc
1911 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1914 * Load the user saved registries
1916 if ((home = getenv( "HOME" )))
1919 * Load user's personal versions of global HKU/.Default keys
1923 strlen(WINE_PREFIX)+
1924 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1927 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1928 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1932 * Load HKCU, attempt to get the registry location from the config
1933 * file first, if exist, load and keep going.
1935 fn = xmalloc( MAX_PATHNAME_LEN );
1936 if ( PROFILE_GetWineIniString(
1941 MAX_PATHNAME_LEN - 1))
1943 _wine_loadreg(HKCU,fn,0);
1949 strlen(WINE_PREFIX)+
1950 strlen(SAVE_CURRENT_USER)+2);
1953 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1954 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1958 * Load HKLM, attempt to get the registry location from the config
1959 * file first, if exist, load and keep going.
1961 fn = xmalloc ( MAX_PATHNAME_LEN);
1962 if ( PROFILE_GetWineIniString(
1964 "LocalMachineFileName",
1967 MAX_PATHNAME_LEN - 1))
1969 _wine_loadreg(HKLM, fn, 0);
1975 strlen(WINE_PREFIX)+
1976 strlen(SAVE_LOCAL_MACHINE)+2);
1979 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1980 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
1985 WARN_(reg)("Failed to get homedirectory of UID %d.\n",getuid());
1989 * Obtain the handle of the HKU\.Default key.
1990 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1992 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1993 lpkey = lookup_hkey(hkey);
1995 WARN_(reg)("Could not create global user default key\n");
1997 _copy_registry(lpkey, HKCU );
2002 * Since HKU is built from the global HKU and the local user HKU file we must
2003 * flush the HKU tree we have built at this point otherwise the part brought
2004 * in from the global HKU is saved into the local HKU. To avoid this
2005 * useless dupplication of HKU keys we reread the local HKU key.
2008 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2009 _flush_registry(HKU);
2011 /* Reload user's local HKU hive */
2014 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2015 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2018 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2020 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2026 * Make sure the update mode is there
2028 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2030 DWORD junk,type,len;
2034 if (( RegQueryValueExA(
2040 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2042 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2050 /********************* API FUNCTIONS ***************************************/
2054 * All functions are stubs to RegOpenKeyEx32W where all the
2058 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2059 * RegOpenKey32W -> RegOpenKeyEx32W
2063 /******************************************************************************
2064 * RegOpenKeyEx32W [ADVAPI32.150]
2065 * Opens the specified key
2067 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2070 * hkey [I] Handle of open key
2071 * lpszSubKey [I] Name of subkey to open
2072 * dwReserved [I] Reserved - must be zero
2073 * samDesired [I] Security access mask
2074 * retkey [O] Address of handle of open key
2077 * Success: ERROR_SUCCESS
2078 * Failure: Error code
2080 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2081 REGSAM samDesired, LPHKEY retkey )
2083 LPKEYSTRUCT lpNextKey,lpxkey;
2087 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2090 lpNextKey = lookup_hkey( hkey );
2092 return ERROR_INVALID_HANDLE;
2094 if (!lpszSubKey || !*lpszSubKey) {
2095 /* Either NULL or pointer to empty string, so return a new handle
2096 to the original hkey */
2098 add_handle(currenthandle,lpNextKey,samDesired);
2099 *retkey=currenthandle;
2100 return ERROR_SUCCESS;
2103 if (lpszSubKey[0] == '\\') {
2104 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2105 return ERROR_BAD_PATHNAME;
2108 split_keypath(lpszSubKey,&wps,&wpc);
2110 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2114 lpxkey=lpNextKey->nextsub;
2116 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2119 lpxkey=lpxkey->next;
2123 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2125 return ERROR_FILE_NOT_FOUND;
2132 add_handle(currenthandle,lpxkey,samDesired);
2133 *retkey = currenthandle;
2134 TRACE_(reg)(" Returning %x\n", currenthandle);
2136 return ERROR_SUCCESS;
2140 /******************************************************************************
2141 * RegOpenKeyEx32A [ADVAPI32.149]
2143 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2144 REGSAM samDesired, LPHKEY retkey )
2146 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2149 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2151 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2157 /******************************************************************************
2158 * RegOpenKey32W [ADVAPI32.151]
2161 * hkey [I] Handle of open key
2162 * lpszSubKey [I] Address of name of subkey to open
2163 * retkey [O] Address of handle of open key
2166 * Success: ERROR_SUCCESS
2167 * Failure: Error code
2169 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2171 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2172 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2176 /******************************************************************************
2177 * RegOpenKey32A [ADVAPI32.148]
2179 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2182 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2183 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2184 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2190 /******************************************************************************
2191 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2193 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2195 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2196 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2203 * All those functions convert their respective
2204 * arguments and call RegCreateKeyExW at the end.
2206 * We stay away from the Ex functions as long as possible because there are
2207 * differences in the return values
2210 * RegCreateKeyEx32A \
2211 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2215 /******************************************************************************
2216 * RegCreateKeyEx32W [ADVAPI32.131]
2219 * hkey [I] Handle of an open key
2220 * lpszSubKey [I] Address of subkey name
2221 * dwReserved [I] Reserved - must be 0
2222 * lpszClass [I] Address of class string
2223 * fdwOptions [I] Special options flag
2224 * samDesired [I] Desired security access
2225 * lpSecAttribs [I] Address of key security structure
2226 * retkey [O] Address of buffer for opened handle
2227 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2229 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2230 DWORD dwReserved, LPWSTR lpszClass,
2231 DWORD fdwOptions, REGSAM samDesired,
2232 LPSECURITY_ATTRIBUTES lpSecAttribs,
2233 LPHKEY retkey, LPDWORD lpDispos )
2235 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2239 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2240 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2241 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2243 lpNextKey = lookup_hkey(hkey);
2245 return ERROR_INVALID_HANDLE;
2247 /* Check for valid options */
2248 switch(fdwOptions) {
2249 case REG_OPTION_NON_VOLATILE:
2250 case REG_OPTION_VOLATILE:
2251 case REG_OPTION_BACKUP_RESTORE:
2254 return ERROR_INVALID_PARAMETER;
2257 /* Sam has to be a combination of the following */
2259 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2260 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2261 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2262 return ERROR_INVALID_PARAMETER;
2264 if (!lpszSubKey || !*lpszSubKey) {
2266 add_handle(currenthandle,lpNextKey,samDesired);
2267 *retkey=currenthandle;
2268 TRACE_(reg)("Returning %x\n", currenthandle);
2269 lpNextKey->flags|=REG_OPTION_TAINTED;
2270 return ERROR_SUCCESS;
2273 if (lpszSubKey[0] == '\\') {
2274 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2275 return ERROR_BAD_PATHNAME;
2278 split_keypath(lpszSubKey,&wps,&wpc);
2280 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2283 lpxkey=lpNextKey->nextsub;
2285 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2287 lpxkey=lpxkey->next;
2296 add_handle(currenthandle,lpxkey,samDesired);
2297 lpxkey->flags |= REG_OPTION_TAINTED;
2298 *retkey = currenthandle;
2299 TRACE_(reg)("Returning %x\n", currenthandle);
2301 *lpDispos = REG_OPENED_EXISTING_KEY;
2303 return ERROR_SUCCESS;
2306 /* Good. Now the hard part */
2308 lplpPrevKey = &(lpNextKey->nextsub);
2309 lpxkey = *lplpPrevKey;
2311 lplpPrevKey = &(lpxkey->next);
2312 lpxkey = *lplpPrevKey;
2314 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2315 if (!*lplpPrevKey) {
2317 TRACE_(reg)("Returning OUTOFMEMORY\n");
2318 return ERROR_OUTOFMEMORY;
2320 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2321 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2322 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2323 (*lplpPrevKey)->next = NULL;
2324 (*lplpPrevKey)->nextsub = NULL;
2325 (*lplpPrevKey)->values = NULL;
2326 (*lplpPrevKey)->nrofvalues = 0;
2327 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2329 (*lplpPrevKey)->class = strdupW(lpszClass);
2331 (*lplpPrevKey)->class = NULL;
2332 lpNextKey = *lplpPrevKey;
2336 add_handle(currenthandle,lpNextKey,samDesired);
2338 /*FIXME: flag handling correct? */
2339 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2341 lpNextKey->class = strdupW(lpszClass);
2343 lpNextKey->class = NULL;
2344 *retkey = currenthandle;
2345 TRACE_(reg)("Returning %x\n", currenthandle);
2347 *lpDispos = REG_CREATED_NEW_KEY;
2349 return ERROR_SUCCESS;
2353 /******************************************************************************
2354 * RegCreateKeyEx32A [ADVAPI32.130]
2356 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2357 LPSTR lpszClass, DWORD fdwOptions,
2359 LPSECURITY_ATTRIBUTES lpSecAttribs,
2360 LPHKEY retkey, LPDWORD lpDispos )
2362 LPWSTR lpszSubKeyW, lpszClassW;
2365 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2366 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2369 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2370 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2372 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2373 fdwOptions, samDesired, lpSecAttribs, retkey,
2376 if(lpszSubKeyW) free(lpszSubKeyW);
2377 if(lpszClassW) free(lpszClassW);
2383 /******************************************************************************
2384 * RegCreateKey32W [ADVAPI32.132]
2386 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2389 LPKEYSTRUCT lpNextKey;
2391 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2393 /* This check is here because the return value is different than the
2394 one from the Ex functions */
2395 lpNextKey = lookup_hkey(hkey);
2397 return ERROR_BADKEY;
2399 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2400 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2405 /******************************************************************************
2406 * RegCreateKey32A [ADVAPI32.129]
2408 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2413 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2414 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2415 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2416 if(lpszSubKeyW) free(lpszSubKeyW);
2421 /******************************************************************************
2422 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2424 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2426 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2427 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2432 * Query Value Functions
2433 * Win32 differs between keynames and valuenames.
2434 * multiple values may belong to one key, the special value
2435 * with name NULL is the default value used by the win31
2439 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2440 * RegQueryValue32W -> RegQueryValueEx32W
2444 /******************************************************************************
2445 * RegQueryValueEx32W [ADVAPI32.158]
2446 * Retrieves type and data for a specified name associated with an open key
2449 * hkey [I] Handle of key to query
2450 * lpValueName [I] Name of value to query
2451 * lpdwReserved [I] Reserved - must be NULL
2452 * lpdwType [O] Address of buffer for value type. If NULL, the type
2454 * lpbData [O] Address of data buffer. If NULL, the actual data is
2456 * lpcbData [I/O] Address of data buffer size
2459 * ERROR_SUCCESS: Success
2460 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2461 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2463 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2464 LPDWORD lpdwReserved, LPDWORD lpdwType,
2465 LPBYTE lpbData, LPDWORD lpcbData )
2471 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2472 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2474 lpkey = lookup_hkey(hkey);
2477 return ERROR_INVALID_HANDLE;
2479 if ((lpbData && ! lpcbData) || lpdwReserved)
2480 return ERROR_INVALID_PARAMETER;
2482 /* An empty name string is equivalent to NULL */
2483 if (lpValueName && !*lpValueName)
2486 if (lpValueName==NULL)
2487 { /* Use key's unnamed or default value, if any */
2488 for (i=0;i<lpkey->nrofvalues;i++)
2489 if (lpkey->values[i].name==NULL)
2493 { /* Search for the key name */
2494 for (i=0;i<lpkey->nrofvalues;i++)
2495 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2499 if (i==lpkey->nrofvalues)
2500 { TRACE_(reg)(" Key not found\n");
2501 if (lpValueName==NULL)
2502 { /* Empty keyname not found */
2504 { *(WCHAR*)lpbData = 0;
2509 TRACE_(reg)(" Returning an empty string\n");
2510 return ERROR_SUCCESS;
2512 return ERROR_FILE_NOT_FOUND;
2515 ret = ERROR_SUCCESS;
2517 if (lpdwType) /* type required ?*/
2518 *lpdwType = lpkey->values[i].type;
2520 if (lpbData) /* data required ?*/
2521 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2522 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2524 ret = ERROR_MORE_DATA;
2527 if (lpcbData) /* size required ?*/
2528 { *lpcbData = lpkey->values[i].len;
2531 debug_print_value ( lpbData, &lpkey->values[i]);
2533 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2539 /******************************************************************************
2540 * RegQueryValue32W [ADVAPI32.159]
2542 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2548 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2549 lpcbData?*lpcbData:0);
2551 /* Only open subkey, if we really do descend */
2552 if (lpszSubKey && *lpszSubKey) {
2553 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2554 if (ret != ERROR_SUCCESS) {
2555 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2562 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2570 /******************************************************************************
2571 * RegQueryValueEx32A [ADVAPI32.157]
2574 * the documantation is wrong: if the buffer is to small it remains untouched
2576 * FIXME: check returnvalue (len) for an empty key
2578 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2579 LPDWORD lpdwReserved, LPDWORD lpdwType,
2580 LPBYTE lpbData, LPDWORD lpcbData )
2582 LPWSTR lpszValueNameW;
2583 LPBYTE mybuf = NULL;
2584 DWORD ret, mytype, mylen = 0;
2586 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2587 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2589 if (!lpcbData && lpbData) /* buffer without size is illegal */
2590 { return ERROR_INVALID_PARAMETER;
2593 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2595 /* get just the type first */
2596 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2598 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2599 { if(lpszValueNameW) free(lpszValueNameW);
2603 if (lpcbData) /* at least length requested? */
2604 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2605 { if (lpbData ) /* value requested? */
2606 { mylen = 2*( *lpcbData );
2607 mybuf = (LPBYTE)xmalloc( mylen );
2610 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2612 if (ret == ERROR_SUCCESS )
2614 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2618 *lpcbData = mylen/2; /* size is in byte! */
2620 else /* no strings, call it straight */
2621 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2625 if (lpdwType) /* type when requested */
2626 { *lpdwType = mytype;
2629 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2631 if(mybuf) free(mybuf);
2632 if(lpszValueNameW) free(lpszValueNameW);
2637 /******************************************************************************
2638 * RegQueryValueEx16 [KERNEL.225]
2640 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2641 LPDWORD lpdwReserved, LPDWORD lpdwType,
2642 LPBYTE lpbData, LPDWORD lpcbData )
2644 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2645 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2646 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2647 lpbData, lpcbData );
2651 /******************************************************************************
2652 * RegQueryValue32A [ADVAPI32.156]
2654 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2660 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2661 lpcbData?*lpcbData:0);
2663 if (lpszSubKey && *lpszSubKey) {
2664 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2665 if( ret != ERROR_SUCCESS )
2671 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2674 RegCloseKey( xhkey );
2679 /******************************************************************************
2680 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2683 * Is this HACK still applicable?
2686 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2687 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2690 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2693 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2694 lpcbData?*lpcbData:0);
2697 *lpcbData &= 0xFFFF;
2698 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2703 * Setting values of Registry keys
2706 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2707 * RegSetValue32W -> RegSetValueEx32W
2711 /******************************************************************************
2712 * RegSetValueEx32W [ADVAPI32.170]
2713 * Sets the data and type of a value under a register key
2716 * hkey [I] Handle of key to set value for
2717 * lpszValueName [I] Name of value to set
2718 * dwReserved [I] Reserved - must be zero
2719 * dwType [I] Flag for value type
2720 * lpbData [I] Address of value data
2721 * cbData [I] Size of value data
2724 * Success: ERROR_SUCCESS
2725 * Failure: Error code
2728 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2730 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2731 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2737 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2738 dwReserved, dwType, lpbData, cbData);
2740 lpkey = lookup_hkey( hkey );
2743 return ERROR_INVALID_HANDLE;
2745 lpkey->flags |= REG_OPTION_TAINTED;
2747 if (lpszValueName==NULL) {
2748 /* Sets type and name for key's unnamed or default value */
2749 for (i=0;i<lpkey->nrofvalues;i++)
2750 if (lpkey->values[i].name==NULL)
2753 for (i=0;i<lpkey->nrofvalues;i++)
2754 if ( lpkey->values[i].name &&
2755 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2759 if (i==lpkey->nrofvalues) {
2760 lpkey->values = (LPKEYVALUE)xrealloc(
2762 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2764 lpkey->nrofvalues++;
2765 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2767 if (lpkey->values[i].name==NULL) {
2769 lpkey->values[i].name = strdupW(lpszValueName);
2771 lpkey->values[i].name = NULL;
2774 if (dwType == REG_SZ)
2775 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2777 lpkey->values[i].len = cbData;
2778 lpkey->values[i].type = dwType;
2779 if (lpkey->values[i].data !=NULL)
2780 free(lpkey->values[i].data);
2781 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2782 lpkey->values[i].lastmodified = time(NULL);
2783 memcpy(lpkey->values[i].data,lpbData,cbData);
2784 return ERROR_SUCCESS;
2788 /******************************************************************************
2789 * RegSetValueEx32A [ADVAPI32.169]
2792 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2794 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2795 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2799 LPWSTR lpszValueNameW;
2803 return (ERROR_INVALID_PARAMETER);
2805 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2806 dwReserved,dwType,lpbData,cbData);
2808 if ((1<<dwType) & UNICONVMASK)
2809 { if (dwType == REG_SZ)
2810 cbData = strlen ((LPCSTR)lpbData)+1;
2812 buf = (LPBYTE)xmalloc( cbData *2 );
2813 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2820 lpszValueNameW = strdupA2W(lpszValueName);
2822 lpszValueNameW = NULL;
2824 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2827 free(lpszValueNameW);
2836 /******************************************************************************
2837 * RegSetValueEx16 [KERNEL.226]
2839 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2840 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2842 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2843 dwReserved,dwType,lpbData,cbData);
2844 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2849 /******************************************************************************
2850 * RegSetValue32W [ADVAPI32.171]
2852 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2853 LPCWSTR lpszData, DWORD cbData )
2858 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2859 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2861 if (lpszSubKey && *lpszSubKey) {
2862 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2863 if (ret!=ERROR_SUCCESS)
2867 if (dwType!=REG_SZ) {
2868 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2871 if (cbData!=2*lstrlenW(lpszData)+2) {
2872 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2873 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2875 cbData=2*lstrlenW(lpszData)+2;
2877 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2884 /******************************************************************************
2885 * RegSetValue32A [ADVAPI32.168]
2888 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2889 LPCSTR lpszData, DWORD cbData )
2894 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2895 if (lpszSubKey && *lpszSubKey) {
2896 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2897 if (ret!=ERROR_SUCCESS)
2902 if (dwType!=REG_SZ) {
2903 TRACE_(reg)("dwType=%ld!\n",dwType);
2906 if (cbData!=strlen(lpszData)+1)
2907 cbData=strlen(lpszData)+1;
2908 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2915 /******************************************************************************
2916 * RegSetValue16 [KERNEL.221] [SHELL.5]
2918 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2919 LPCSTR lpszData, DWORD cbData )
2921 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2922 debugstr_a(lpszData),cbData);
2923 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2931 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2932 * RegEnumKey32W -> RegEnumKeyEx32W
2936 /******************************************************************************
2937 * RegEnumKeyEx32W [ADVAPI32.139]
2940 * hkey [I] Handle to key to enumerate
2941 * iSubKey [I] Index of subkey to enumerate
2942 * lpszName [O] Buffer for subkey name
2943 * lpcchName [O] Size of subkey buffer
2944 * lpdwReserved [I] Reserved
2945 * lpszClass [O] Buffer for class string
2946 * lpcchClass [O] Size of class buffer
2947 * ft [O] Time key last written to
2949 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2950 LPDWORD lpcchName, LPDWORD lpdwReserved,
2951 LPWSTR lpszClass, LPDWORD lpcchClass,
2954 LPKEYSTRUCT lpkey,lpxkey;
2956 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2957 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2959 lpkey = lookup_hkey( hkey );
2961 return ERROR_INVALID_HANDLE;
2963 if (!lpkey->nextsub)
2964 return ERROR_NO_MORE_ITEMS;
2965 lpxkey=lpkey->nextsub;
2967 /* Traverse the subkeys */
2968 while (iSubkey && lpxkey) {
2970 lpxkey=lpxkey->next;
2973 if (iSubkey || !lpxkey)
2974 return ERROR_NO_MORE_ITEMS;
2975 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
2976 return ERROR_MORE_DATA;
2977 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
2980 *lpcchName = lstrlenW(lpszName);
2983 /* FIXME: what should we write into it? */
2987 return ERROR_SUCCESS;
2991 /******************************************************************************
2992 * RegEnumKey32W [ADVAPI32.140]
2994 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2999 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3000 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3004 /******************************************************************************
3005 * RegEnumKeyEx32A [ADVAPI32.138]
3007 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3008 LPDWORD lpcchName, LPDWORD lpdwReserved,
3009 LPSTR lpszClass, LPDWORD lpcchClass,
3012 DWORD ret,lpcchNameW,lpcchClassW;
3013 LPWSTR lpszNameW,lpszClassW;
3016 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3017 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3020 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3021 lpcchNameW = *lpcchName;
3027 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3028 lpcchClassW = *lpcchClass;
3043 if (ret==ERROR_SUCCESS) {
3044 lstrcpyWtoA(lpszName,lpszNameW);
3045 *lpcchName=strlen(lpszName);
3047 lstrcpyWtoA(lpszClass,lpszClassW);
3048 *lpcchClass=strlen(lpszClass);
3059 /******************************************************************************
3060 * RegEnumKey32A [ADVAPI32.137]
3062 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3067 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3068 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3073 /******************************************************************************
3074 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3076 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3079 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3080 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3085 * Enumerate Registry Values
3088 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3092 /******************************************************************************
3093 * RegEnumValue32W [ADVAPI32.142]
3096 * hkey [I] Handle to key to query
3097 * iValue [I] Index of value to query
3098 * lpszValue [O] Value string
3099 * lpcchValue [I/O] Size of value buffer (in wchars)
3100 * lpdReserved [I] Reserved
3101 * lpdwType [O] Type code
3102 * lpbData [O] Value data
3103 * lpcbData [I/O] Size of data buffer (in bytes)
3105 * Note: wide character functions that take and/or return "character counts"
3106 * use TCHAR (that is unsigned short or char) not byte counts.
3108 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3109 LPDWORD lpcchValue, LPDWORD lpdReserved,
3110 LPDWORD lpdwType, LPBYTE lpbData,
3116 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3117 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3119 lpkey = lookup_hkey( hkey );
3121 if (!lpcbData && lpbData)
3122 return ERROR_INVALID_PARAMETER;
3125 return ERROR_INVALID_HANDLE;
3127 if (lpkey->nrofvalues <= iValue)
3128 return ERROR_NO_MORE_ITEMS;
3130 val = &(lpkey->values[iValue]);
3133 if (lstrlenW(val->name)+1>*lpcchValue) {
3134 *lpcchValue = lstrlenW(val->name)+1;
3135 return ERROR_MORE_DATA;
3137 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3138 *lpcchValue=lstrlenW(val->name);
3144 /* Can be NULL if the type code is not required */
3146 *lpdwType = val->type;
3149 if (val->len>*lpcbData)
3150 return ERROR_MORE_DATA;
3151 memcpy(lpbData,val->data,val->len);
3152 *lpcbData = val->len;
3155 debug_print_value ( val->data, val );
3156 return ERROR_SUCCESS;
3160 /******************************************************************************
3161 * RegEnumValue32A [ADVAPI32.141]
3163 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3164 LPDWORD lpcchValue, LPDWORD lpdReserved,
3165 LPDWORD lpdwType, LPBYTE lpbData,
3170 DWORD ret,lpcbDataW;
3173 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3174 lpdReserved,lpdwType,lpbData,lpcbData);
3176 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3178 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3179 lpcbDataW = *lpcbData;
3183 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3184 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3189 if (ret==ERROR_SUCCESS) {
3190 lstrcpyWtoA(lpszValue,lpszValueW);
3192 if ((1<<dwType) & UNICONVMASK) {
3193 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3195 if (lpcbDataW > *lpcbData)
3196 ret = ERROR_MORE_DATA;
3198 memcpy(lpbData,lpbDataW,lpcbDataW);
3200 *lpcbData = lpcbDataW;
3203 if (lpbDataW) free(lpbDataW);
3204 if (lpszValueW) free(lpszValueW);
3209 /******************************************************************************
3210 * RegEnumValue16 [KERNEL.223]
3212 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3213 LPDWORD lpcchValue, LPDWORD lpdReserved,
3214 LPDWORD lpdwType, LPBYTE lpbData,
3217 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3218 lpdReserved,lpdwType,lpbData,lpcbData);
3219 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3220 lpdwType, lpbData, lpcbData );
3224 /******************************************************************************
3225 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3226 * Releases the handle of the specified key
3229 * hkey [I] Handle of key to close
3232 * Success: ERROR_SUCCESS
3233 * Failure: Error code
3235 DWORD WINAPI RegCloseKey( HKEY hkey )
3237 TRACE_(reg)("(%x)\n",hkey);
3239 /* The standard handles are allowed to succeed, even though they are not
3241 if (is_standard_hkey(hkey))
3242 return ERROR_SUCCESS;
3244 return remove_handle(hkey);
3249 * Delete registry key
3252 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3256 /******************************************************************************
3257 * RegDeleteKey32W [ADVAPI32.134]
3260 * hkey [I] Handle to open key
3261 * lpszSubKey [I] Name of subkey to delete
3264 * Success: ERROR_SUCCESS
3265 * Failure: Error code
3267 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3269 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3273 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3275 lpNextKey = lookup_hkey(hkey);
3277 return ERROR_INVALID_HANDLE;
3279 /* Subkey param cannot be NULL */
3280 if (!lpszSubKey || !*lpszSubKey)
3281 return ERROR_BADKEY;
3283 /* We need to know the previous key in the hier. */
3284 split_keypath(lpszSubKey,&wps,&wpc);
3288 lpxkey=lpNextKey->nextsub;
3290 TRACE_(reg)(" Scanning [%s]\n",
3291 debugstr_w(lpxkey->keyname));
3292 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3294 lpxkey=lpxkey->next;
3298 TRACE_(reg)(" Not found.\n");
3299 /* not found is success */
3300 return ERROR_SUCCESS;
3305 lpxkey = lpNextKey->nextsub;
3306 lplpPrevKey = &(lpNextKey->nextsub);
3308 TRACE_(reg)(" Scanning [%s]\n",
3309 debugstr_w(lpxkey->keyname));
3310 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3312 lplpPrevKey = &(lpxkey->next);
3313 lpxkey = lpxkey->next;
3318 WARN_(reg)(" Not found.\n");
3319 return ERROR_FILE_NOT_FOUND;
3322 if (lpxkey->nextsub) {
3324 WARN_(reg)(" Not empty.\n");
3325 return ERROR_CANTWRITE;
3327 *lplpPrevKey = lpxkey->next;
3328 free(lpxkey->keyname);
3330 free(lpxkey->class);
3332 free(lpxkey->values);
3335 TRACE_(reg)(" Done.\n");
3336 return ERROR_SUCCESS;
3340 /******************************************************************************
3341 * RegDeleteKey32A [ADVAPI32.133]
3343 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3348 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3349 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3350 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3351 if(lpszSubKeyW) free(lpszSubKeyW);
3356 /******************************************************************************
3357 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3359 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3361 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3362 return RegDeleteKeyA( hkey, lpszSubKey );
3367 * Delete registry value
3370 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3374 /******************************************************************************
3375 * RegDeleteValue32W [ADVAPI32.136]
3383 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3389 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3391 lpkey = lookup_hkey( hkey );
3393 return ERROR_INVALID_HANDLE;
3396 for (i=0;i<lpkey->nrofvalues;i++)
3397 if ( lpkey->values[i].name &&
3398 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3402 for (i=0;i<lpkey->nrofvalues;i++)
3403 if (lpkey->values[i].name==NULL)
3407 if (i == lpkey->nrofvalues)
3408 return ERROR_FILE_NOT_FOUND;
3410 val = lpkey->values+i;
3411 if (val->name) free(val->name);
3412 if (val->data) free(val->data);
3416 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3418 lpkey->values = (LPKEYVALUE)xrealloc(
3420 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3422 lpkey->nrofvalues--;
3423 return ERROR_SUCCESS;
3427 /******************************************************************************
3428 * RegDeleteValue32A [ADVAPI32.135]
3430 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3435 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3436 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3437 ret = RegDeleteValueW( hkey, lpszValueW );
3438 if(lpszValueW) free(lpszValueW);
3443 /******************************************************************************
3444 * RegDeleteValue16 [KERNEL.222]
3446 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3448 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3449 return RegDeleteValueA( hkey, lpszValue );
3453 /******************************************************************************
3454 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3455 * Writes key to registry
3458 * hkey [I] Handle of key to write
3461 * Success: ERROR_SUCCESS
3462 * Failure: Error code
3464 DWORD WINAPI RegFlushKey( HKEY hkey )
3469 TRACE_(reg)("(%x)\n", hkey);
3471 lpkey = lookup_hkey( hkey );
3473 return ERROR_BADKEY;
3475 ERR_(reg)("What is the correct filename?\n");
3477 ret = _savereg( lpkey, "foo.bar", TRUE);
3480 return ERROR_SUCCESS;
3482 return ERROR_UNKNOWN; /* FIXME */
3486 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3489 /******************************************************************************
3490 * RegQueryInfoKey32W [ADVAPI32.153]
3493 * hkey [I] Handle to key to query
3494 * lpszClass [O] Buffer for class string
3495 * lpcchClass [O] Size of class string buffer
3496 * lpdwReserved [I] Reserved
3497 * lpcSubKeys [I] Buffer for number of subkeys
3498 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3499 * lpcchMaxClass [O] Buffer for longest class string length
3500 * lpcValues [O] Buffer for number of value entries
3501 * lpcchMaxValueName [O] Buffer for longest value name length
3502 * lpccbMaxValueData [O] Buffer for longest value data length
3503 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3505 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3506 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3507 * lpcchClass is NULL
3508 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3509 * (it's hard to test validity, so test !NULL instead)
3511 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3512 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3513 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3514 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3515 LPDWORD lpcchMaxValueName,
3516 LPDWORD lpccbMaxValueData,
3517 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3519 LPKEYSTRUCT lpkey,lpxkey;
3520 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3523 TRACE_(reg)("(%x,%p,...)\n",hkey,lpszClass);
3524 lpkey = lookup_hkey(hkey);
3526 return ERROR_INVALID_HANDLE;
3528 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3529 return ERROR_INVALID_PARAMETER;
3531 /* either lpcchClass is valid or this is win95 and lpcchClass
3534 DWORD classLen = lstrlenW(lpkey->class);
3536 if (lpcchClass && classLen+1>*lpcchClass) {
3537 *lpcchClass=classLen+1;
3538 return ERROR_MORE_DATA;
3541 *lpcchClass=classLen;
3542 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3550 *lpcchClass = lstrlenW(lpkey->class);
3552 lpxkey=lpkey->nextsub;
3553 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3556 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3557 maxsubkey=lstrlenW(lpxkey->keyname);
3558 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3559 maxclass=lstrlenW(lpxkey->class);
3560 lpxkey=lpxkey->next;
3562 for (i=0;i<lpkey->nrofvalues;i++) {
3563 LPKEYVALUE val=lpkey->values+i;
3565 if (val->name && lstrlenW(val->name)>maxvname)
3566 maxvname=lstrlenW(val->name);
3567 if (val->len>maxvdata)
3570 if (!maxclass) maxclass = 1;
3571 if (!maxvname) maxvname = 1;
3573 *lpcValues = lpkey->nrofvalues;
3575 *lpcSubKeys = nrofkeys;
3577 *lpcchMaxSubkey = maxsubkey;
3579 *lpcchMaxClass = maxclass;
3580 if (lpcchMaxValueName)
3581 *lpcchMaxValueName= maxvname;
3582 if (lpccbMaxValueData)
3583 *lpccbMaxValueData= maxvdata;
3584 return ERROR_SUCCESS;
3588 /******************************************************************************
3589 * RegQueryInfoKey32A [ADVAPI32.152]
3591 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3592 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3593 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3594 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3595 LPDWORD lpccbMaxValueData,
3596 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3598 LPWSTR lpszClassW = NULL;
3601 TRACE_(reg)("(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3604 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3605 } else if (VERSION_GetVersion() == WIN95) {
3606 /* win95 allows lpcchClass to be null */
3607 /* we don't know how big lpszClass is, would
3608 MAX_PATHNAME_LEN be the correct default? */
3609 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3614 ret=RegQueryInfoKeyW(
3625 lpcbSecurityDescriptor,
3628 if (ret==ERROR_SUCCESS && lpszClass)
3629 lstrcpyWtoA(lpszClass,lpszClassW);
3636 /******************************************************************************
3637 * RegConnectRegistry32W [ADVAPI32.128]
3640 * lpMachineName [I] Address of name of remote computer
3641 * hHey [I] Predefined registry handle
3642 * phkResult [I] Address of buffer for remote registry handle
3644 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3647 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3649 if (!lpMachineName || !*lpMachineName) {
3650 /* Use the local machine name */
3651 return RegOpenKey16( hKey, "", phkResult );
3654 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3655 return ERROR_BAD_NETPATH;
3659 /******************************************************************************
3660 * RegConnectRegistry32A [ADVAPI32.127]
3662 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3665 LPWSTR machineW = strdupA2W(machine);
3666 ret = RegConnectRegistryW( machineW, hkey, reskey );
3672 /******************************************************************************
3673 * RegGetKeySecurity [ADVAPI32.144]
3674 * Retrieves a copy of security descriptor protecting the registry key
3677 * hkey [I] Open handle of key to set
3678 * SecurityInformation [I] Descriptor contents
3679 * pSecurityDescriptor [O] Address of descriptor for key
3680 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3683 * Success: ERROR_SUCCESS
3684 * Failure: Error code
3686 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3687 SECURITY_INFORMATION SecurityInformation,
3688 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3689 LPDWORD lpcbSecurityDescriptor )
3693 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3694 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3696 lpkey = lookup_hkey( hkey );
3698 return ERROR_INVALID_HANDLE;
3700 /* FIXME: Check for valid SecurityInformation values */
3702 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3703 return ERROR_INSUFFICIENT_BUFFER;
3705 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3706 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3708 return ERROR_SUCCESS;
3712 /******************************************************************************
3713 * RegLoadKey32W [ADVAPI32.???]
3716 * hkey [I] Handle of open key
3717 * lpszSubKey [I] Address of name of subkey
3718 * lpszFile [I] Address of filename for registry information
3720 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3723 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3725 /* Do this check before the hkey check */
3726 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3727 return ERROR_INVALID_PARAMETER;
3729 lpkey = lookup_hkey( hkey );
3731 return ERROR_INVALID_HANDLE;
3733 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3734 debugstr_w(lpszFile));
3736 return ERROR_SUCCESS;
3740 /******************************************************************************
3741 * RegLoadKey32A [ADVAPI32.???]
3743 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3746 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3747 LPWSTR lpszFileW = strdupA2W(lpszFile);
3748 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3749 if(lpszFileW) free(lpszFileW);
3750 if(lpszSubKeyW) free(lpszSubKeyW);
3755 /******************************************************************************
3756 * RegNotifyChangeKeyValue [ADVAPI32.???]
3759 * hkey [I] Handle of key to watch
3760 * fWatchSubTree [I] Flag for subkey notification
3761 * fdwNotifyFilter [I] Changes to be reported
3762 * hEvent [I] Handle of signaled event
3763 * fAsync [I] Flag for asynchronous reporting
3765 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3766 DWORD fdwNotifyFilter, HANDLE hEvent,
3770 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3773 lpkey = lookup_hkey( hkey );
3775 return ERROR_INVALID_HANDLE;
3777 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3780 return ERROR_SUCCESS;
3784 /******************************************************************************
3785 * RegUnLoadKey32W [ADVAPI32.173]
3788 * hkey [I] Handle of open key
3789 * lpSubKey [I] Address of name of subkey to unload
3791 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3793 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3794 return ERROR_SUCCESS;
3798 /******************************************************************************
3799 * RegUnLoadKey32A [ADVAPI32.172]
3801 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3804 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3805 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3806 if(lpSubKeyW) free(lpSubKeyW);
3811 /******************************************************************************
3812 * RegSetKeySecurity [ADVAPI32.167]
3815 * hkey [I] Open handle of key to set
3816 * SecurityInfo [I] Descriptor contents
3817 * pSecurityDesc [I] Address of descriptor for key
3819 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3820 PSECURITY_DESCRIPTOR pSecurityDesc )
3824 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3826 /* It seems to perform this check before the hkey check */
3827 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3828 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3829 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3830 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3833 return ERROR_INVALID_PARAMETER;
3836 return ERROR_INVALID_PARAMETER;
3838 lpkey = lookup_hkey( hkey );
3840 return ERROR_INVALID_HANDLE;
3842 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3844 return ERROR_SUCCESS;
3848 /******************************************************************************
3849 * RegSaveKey32W [ADVAPI32.166]
3852 * hkey [I] Handle of key where save begins
3853 * lpFile [I] Address of filename to save to
3854 * sa [I] Address of security structure
3856 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3857 LPSECURITY_ATTRIBUTES sa )
3861 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3863 /* It appears to do this check before the hkey check */
3864 if (!lpFile || !*lpFile)
3865 return ERROR_INVALID_PARAMETER;
3867 lpkey = lookup_hkey( hkey );
3869 return ERROR_INVALID_HANDLE;
3871 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3873 return ERROR_SUCCESS;
3877 /******************************************************************************
3878 * RegSaveKey32A [ADVAPI32.165]
3880 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3881 LPSECURITY_ATTRIBUTES sa )
3884 LPWSTR lpFileW = strdupA2W(lpFile);
3885 ret = RegSaveKeyW( hkey, lpFileW, sa );
3891 /******************************************************************************
3892 * RegRestoreKey32W [ADVAPI32.164]
3895 * hkey [I] Handle of key where restore begins
3896 * lpFile [I] Address of filename containing saved tree
3897 * dwFlags [I] Optional flags
3899 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3903 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3905 /* It seems to do this check before the hkey check */
3906 if (!lpFile || !*lpFile)
3907 return ERROR_INVALID_PARAMETER;
3909 lpkey = lookup_hkey( hkey );
3911 return ERROR_INVALID_HANDLE;
3913 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3915 /* Check for file existence */
3917 return ERROR_SUCCESS;
3921 /******************************************************************************
3922 * RegRestoreKey32A [ADVAPI32.163]
3924 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3927 LPWSTR lpFileW = strdupA2W(lpFile);
3928 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3929 if(lpFileW) free(lpFileW);
3934 /******************************************************************************
3935 * RegReplaceKey32W [ADVAPI32.162]
3938 * hkey [I] Handle of open key
3939 * lpSubKey [I] Address of name of subkey
3940 * lpNewFile [I] Address of filename for file with new data
3941 * lpOldFile [I] Address of filename for backup file
3943 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3948 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3949 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3951 lpkey = lookup_hkey( hkey );
3953 return ERROR_INVALID_HANDLE;
3955 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3956 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3958 return ERROR_SUCCESS;
3962 /******************************************************************************
3963 * RegReplaceKey32A [ADVAPI32.161]
3965 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3969 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3970 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3971 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3972 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );