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>
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
45 #include "winversion.h"
47 DECLARE_DEBUG_CHANNEL(reg)
48 DECLARE_DEBUG_CHANNEL(string)
50 static void REGISTRY_Init(void);
51 /* FIXME: following defines should be configured global ... */
53 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
54 #define WINE_PREFIX "/.wine"
55 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
56 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
58 /* relative in ~user/.wine/ : */
59 #define SAVE_CURRENT_USER "user.reg"
60 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
61 #define SAVE_LOCAL_MACHINE "system.reg"
63 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
64 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
66 /* one value of a key */
67 typedef struct tagKEYVALUE
69 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
70 DWORD type; /* type of value */
71 DWORD len; /* length of data in BYTEs */
72 DWORD lastmodified; /* time of seconds since 1.1.1970 */
73 LPBYTE data; /* content, may be strings, binaries, etc. */
74 } KEYVALUE,*LPKEYVALUE;
77 typedef struct tagKEYSTRUCT
79 LPWSTR keyname; /* name of THIS key (UNICODE) */
80 DWORD flags; /* flags. */
83 DWORD nrofvalues; /* nr of values in THIS key */
84 LPKEYVALUE values; /* values in THIS key */
85 /* key management pointers */
86 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
87 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
88 } KEYSTRUCT, *LPKEYSTRUCT;
91 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
92 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
93 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
94 static KEYSTRUCT *key_users=NULL; /* all users? */
96 /* dynamic, not saved */
97 static KEYSTRUCT *key_performance_data=NULL;
98 static KEYSTRUCT *key_current_config=NULL;
99 static KEYSTRUCT *key_dyn_data=NULL;
101 /* what valuetypes do we need to convert? */
102 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
105 static struct openhandle {
110 static int nrofopenhandles=0;
111 /* Starts after 1 because 0,1 are reserved for Win16 */
112 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
113 HKEYs for remote registry access */
114 static int currenthandle=2;
119 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
120 * If so, can we remove them?
122 * No, the memory handling functions are called very often in here,
123 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
124 * loading 100 times slower. -MM
126 static LPWSTR strdupA2W(LPCSTR src)
129 LPWSTR dest=xmalloc(2*strlen(src)+2);
130 lstrcpyAtoW(dest,src);
136 static LPWSTR strdupW(LPCWSTR a) {
141 len=sizeof(WCHAR)*(lstrlenW(a)+1);
142 b=(LPWSTR)xmalloc(len);
149 LPWSTR strcvtA2W(LPCSTR src, int nchars)
152 LPWSTR dest = xmalloc (2 * nchars + 2);
154 lstrcpynAtoW(dest,src,nchars+1);
159 * we need to convert A to W with '\0' in strings (MULTI_SZ)
162 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
165 TRACE(reg,"\"%s\" %i\n",src, n);
167 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
171 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
174 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
176 while (n-- > 0) *p++ = (CHAR)*src++;
181 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
183 if (TRACE_ON(reg) && lpbData)
187 case HEX_REG_EXPAND_SZ:
190 TRACE(reg," Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
197 TRACE(reg," Value %s, Data(dword)=0x%08lx\n",
198 debugstr_w(key->name),
202 case HEX_REG_MULTI_SZ:
206 LPCWSTR ptr = (LPCWSTR)lpbData;
209 TRACE(reg, " Value %s, MULTI_SZ(%i=%s)\n",
210 debugstr_w(key->name),
214 ptr += lstrlenW(ptr)+1;
222 case HEX_REG_RESOURCE_LIST:
223 case HEX_REG_FULL_RESOURCE_DESCRIPTOR:
226 case REG_RESOURCE_LIST:
227 case REG_FULL_RESOURCE_DESCRIPTOR:
230 char szTemp[100]; /* 3*32 + 3 + 1 */
232 for ( i = 0; i < key->len ; i++)
234 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
237 sprintf (&(szTemp[i*3+3]),"...");
241 TRACE(reg," Value %s, Data(raw)=(%s)\n",
242 debugstr_w(key->name),
248 FIXME(reg, " Value %s, Unknown data type %ld\n",
249 debugstr_w(key->name),
256 /******************************************************************************
257 * is_standard_hkey [Internal]
258 * Determines if a hkey is a standard key
260 static BOOL is_standard_hkey( HKEY hkey )
265 case HKEY_CLASSES_ROOT:
266 case HKEY_CURRENT_CONFIG:
267 case HKEY_CURRENT_USER:
268 case HKEY_LOCAL_MACHINE:
270 case HKEY_PERFORMANCE_DATA:
278 /******************************************************************************
279 * add_handle [Internal]
281 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
285 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
286 /* Check for duplicates */
287 for (i=0;i<nrofopenhandles;i++) {
288 if (openhandles[i].lpkey==lpkey) {
289 /* This is not really an error - the user is allowed to create
290 two (or more) handles to the same key */
291 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
293 if (openhandles[i].hkey==hkey) {
294 WARN(reg, "Adding handle %x twice\n",hkey);
297 openhandles=xrealloc( openhandles,
298 sizeof(struct openhandle)*(nrofopenhandles+1));
300 openhandles[i].lpkey = lpkey;
301 openhandles[i].hkey = hkey;
302 openhandles[i].accessmask = accessmask;
307 /******************************************************************************
308 * get_handle [Internal]
311 * Success: Pointer to key
314 static LPKEYSTRUCT get_handle( HKEY hkey )
318 for (i=0; i<nrofopenhandles; i++)
319 if (openhandles[i].hkey == hkey)
320 return openhandles[i].lpkey;
321 WARN(reg, "Could not find handle 0x%x\n",hkey);
326 /******************************************************************************
327 * remove_handle [Internal]
330 * hkey [I] Handle of key to remove
333 * Success: ERROR_SUCCESS
334 * Failure: ERROR_INVALID_HANDLE
336 static DWORD remove_handle( HKEY hkey )
340 for (i=0;i<nrofopenhandles;i++)
341 if (openhandles[i].hkey==hkey)
344 if (i == nrofopenhandles) {
345 WARN(reg, "Could not find handle 0x%x\n",hkey);
346 return ERROR_INVALID_HANDLE;
349 memcpy( openhandles+i,
351 sizeof(struct openhandle)*(nrofopenhandles-i-1)
353 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
355 return ERROR_SUCCESS;
358 /******************************************************************************
359 * lookup_hkey [Internal]
361 * Just as the name says. Creates the root keys on demand, so we can call the
362 * Reg* functions at any time.
365 * Success: Pointer to key structure
368 #define ADD_ROOT_KEY(xx) \
369 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
370 memset(xx,'\0',sizeof(KEYSTRUCT));\
371 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
373 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
376 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
377 * some programs. Do not remove those cases. -MM
381 case HKEY_CLASSES_ROOT:
383 if (!key_classes_root)
387 /* calls lookup_hkey recursively, TWICE */
391 &cl_r_hkey) != ERROR_SUCCESS)
395 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
399 key_classes_root = lookup_hkey(cl_r_hkey);
401 return key_classes_root;
404 case HKEY_CURRENT_USER:
405 if (!key_current_user) {
406 ADD_ROOT_KEY(key_current_user);
408 return key_current_user;
410 case HKEY_LOCAL_MACHINE:
411 if (!key_local_machine) {
412 ADD_ROOT_KEY(key_local_machine);
415 return key_local_machine;
419 ADD_ROOT_KEY(key_users);
423 case HKEY_PERFORMANCE_DATA:
424 if (!key_performance_data) {
425 ADD_ROOT_KEY(key_performance_data);
427 return key_performance_data;
431 ADD_ROOT_KEY(key_dyn_data);
435 case HKEY_CURRENT_CONFIG:
436 if (!key_current_config) {
437 ADD_ROOT_KEY(key_current_config);
439 return key_current_config;
442 return get_handle(hkey);
448 /* so we don't accidently access them ... */
449 #define key_current_config NULL NULL
450 #define key_current_user NULL NULL
451 #define key_users NULL NULL
452 #define key_local_machine NULL NULL
453 #define key_classes_root NULL NULL
454 #define key_dyn_data NULL NULL
455 #define key_performance_data NULL NULL
457 /******************************************************************************
458 * split_keypath [Internal]
459 * splits the unicode string 'wp' into an array of strings.
460 * the array is allocated by this function.
461 * Free the array using FREE_KEY_PATH
464 * wp [I] String to split up
465 * wpv [O] Array of pointers to strings
466 * wpc [O] Number of components
468 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
473 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
475 ws = HEAP_strdupW( SystemHeap, 0, wp );
477 /* We know we have at least one substring */
480 /* Replace each backslash with NULL, and increment the count */
481 for (i=0;ws[i];i++) {
490 /* Allocate the space for the array of pointers, leaving room for the
492 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
495 /* Assign each pointer to the appropriate character in the string */
500 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
505 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
510 /******************************************************************************
511 * REGISTRY_Init [Internal]
512 * Registry initialisation, allocates some default keys.
514 static void REGISTRY_Init(void) {
518 TRACE(reg,"(void)\n");
520 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
523 /* This was an Open, but since it is called before the real registries
524 are loaded, it was changed to a Create - MTB 980507*/
525 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
526 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
529 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
533 * string RegisteredOwner
534 * string RegisteredOrganization
537 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
542 if (-1!=gethostname(buf,200)) {
543 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
544 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
550 /************************ SAVE Registry Function ****************************/
552 #define REGISTRY_SAVE_VERSION 0x00000001
554 /* Registry saveformat:
555 * If you change it, increase above number by 1, which will flush
556 * old registry database files.
559 * "WINE REGISTRY Version %d"
563 * valuename=lastmodified,type,data
567 * keyname,valuename,stringdata:
568 * the usual ascii characters from 0x00-0xff (well, not 0x00)
569 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
570 * ( "=\\\t" escaped in \uXXXX form.)
574 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
576 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
577 * SaveOnlyUpdatedKeys=yes
580 /******************************************************************************
581 * _save_check_tainted [Internal]
583 static int _save_check_tainted( LPKEYSTRUCT lpkey )
589 if (lpkey->flags & REG_OPTION_TAINTED)
594 if (_save_check_tainted(lpkey->nextsub)) {
595 lpkey->flags |= REG_OPTION_TAINTED;
603 /******************************************************************************
604 * _save_USTRING [Internal]
606 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
620 if (escapeeq && *s=='=')
623 fputc(*s,F); /* if \\ then put it twice. */
625 fprintf(F,"\\u%04x",*((unsigned short*)s));
632 /******************************************************************************
633 * _savesubkey [Internal]
636 * REG_MULTI_SZ is handled as binary (like in win95) (js)
638 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
645 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
646 (all || (lpxkey->flags & REG_OPTION_TAINTED))
648 for (tabs=level;tabs--;)
650 _save_USTRING(F,lpxkey->keyname,1);
652 for (i=0;i<lpxkey->nrofvalues;i++) {
653 LPKEYVALUE val=lpxkey->values+i;
655 for (tabs=level+1;tabs--;)
657 _save_USTRING(F,val->name,0);
659 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
660 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
661 _save_USTRING(F,(LPWSTR)val->data,0);
663 for (j=0;j<val->len;j++)
664 fprintf(F,"%02x",*((unsigned char*)val->data+j));
667 /* descend recursively */
668 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
677 /******************************************************************************
678 * _savesubreg [Internal]
680 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
682 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
683 _save_check_tainted(lpkey->nextsub);
684 return _savesubkey(F,lpkey->nextsub,0,all);
688 /******************************************************************************
689 * _savereg [Internal]
691 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
697 WARN(reg,"Couldn't open %s for writing: %s\n",
702 if (!_savesubreg(F,lpkey,all)) {
705 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
713 /******************************************************************************
714 * SHELL_SaveRegistry [Internal]
716 void SHELL_SaveRegistry( void )
726 TRACE(reg,"(void)\n");
729 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
738 if ( (ERROR_SUCCESS!=RegQueryValueExA(
744 &len)) || (type!=REG_SZ))
751 if (lstrcmpiA(buf,"yes"))
754 pwd=getpwuid(getuid());
755 if ( (pwd!=NULL) && (pwd->pw_dir!=NULL))
759 * Save HKEY_CURRENT_USER
760 * Try first saving according to the defined location in .winerc
762 fn = xmalloc( MAX_PATHNAME_LEN );
763 if (PROFILE_GetWineIniString (
768 MAX_PATHNAME_LEN - 1))
770 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
775 if (usedCfgUser != 1)
778 strlen(pwd->pw_dir) +
779 strlen(WINE_PREFIX) +
780 strlen(SAVE_CURRENT_USER) + 2 );
782 strcpy(fn,pwd->pw_dir);
783 strcat(fn,WINE_PREFIX);
785 /* create the directory. don't care about errorcodes. */
786 mkdir(fn,0755); /* drwxr-xr-x */
787 strcat(fn,"/"SAVE_CURRENT_USER);
789 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
793 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
794 if (-1==rename(tmp,fn)) {
795 perror("rename tmp registry");
804 * Save HKEY_LOCAL_MACHINE
805 * Try first saving according to the defined location in .winerc
807 fn = xmalloc ( MAX_PATHNAME_LEN);
808 if (PROFILE_GetWineIniString (
810 "LocalMachineFileName",
813 MAX_PATHNAME_LEN - 1))
815 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
825 strlen(SAVE_LOCAL_MACHINE)+2);
827 strcpy(fn,pwd->pw_dir);
828 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
830 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
834 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
835 if (-1==rename(tmp,fn)) {
836 perror("rename tmp registry");
850 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
852 strcpy(fn,pwd->pw_dir);
853 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
855 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
856 strcpy(tmp,fn);strcat(tmp,".tmp");
857 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
858 if (-1==rename(tmp,fn)) {
859 perror("rename tmp registry");
868 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
873 /************************ LOAD Registry Function ****************************/
877 /******************************************************************************
878 * _find_or_add_key [Internal]
880 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
882 LPKEYSTRUCT lpxkey,*lplpkey;
884 if ((!keyname) || (keyname[0]==0)) {
888 lplpkey= &(lpkey->nextsub);
891 if ( (lpxkey->keyname[0]==keyname[0]) &&
892 !lstrcmpiW(lpxkey->keyname,keyname)
895 lplpkey = &(lpxkey->next);
899 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
901 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
902 lpxkey->keyname = keyname;
908 /******************************************************************************
909 * _find_or_add_value [Internal]
911 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
912 LPBYTE data, DWORD len, DWORD lastmodified )
917 if (name && !*name) {/* empty string equals default (NULL) value */
922 for (i=0;i<lpkey->nrofvalues;i++) {
928 if ( val->name!=NULL &&
929 val->name[0]==name[0] &&
930 !lstrcmpiW(val->name,name)
935 if (i==lpkey->nrofvalues) {
936 lpkey->values = xrealloc(
938 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
941 memset(val,'\0',sizeof(KEYVALUE));
947 if (val->lastmodified<lastmodified) {
948 val->lastmodified=lastmodified;
959 /******************************************************************************
960 * _wine_read_line [Internal]
962 * reads a line including dynamically enlarging the readbuffer and throwing
965 static int _wine_read_line( FILE *F, char **buf, int *len )
975 s=fgets(curread,mylen,F);
978 if (NULL==(s=strchr(curread,'\n'))) {
979 /* buffer wasn't large enough */
980 curoff = strlen(*buf);
981 *buf = xrealloc(*buf,*len*2);
982 curread = *buf + curoff;
983 mylen = *len; /* we filled up the buffer and
984 * got new '*len' bytes to fill
992 /* throw away comments */
993 if (**buf=='#' || **buf==';') {
998 if (s) /* got end of line */
1005 /******************************************************************************
1006 * _wine_read_USTRING [Internal]
1008 * converts a char* into a UNICODE string (up to a special char)
1009 * and returns the position exactly after that string
1011 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1016 /* read up to "=" or "\0" or "\n" */
1019 /* empty string is the win3.1 default value(NULL)*/
1023 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1025 while (*s && (*s!='\n') && (*s!='=')) {
1027 *ws++=*((unsigned char*)s++);
1031 /* Dangling \ ... may only happen if a registry
1032 * write was short. FIXME: What do to?
1042 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1050 memcpy(xbuf,s,4);xbuf[4]='\0';
1051 if (!sscanf(xbuf,"%x",&wc))
1052 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
1054 *ws++ =(unsigned short)wc;
1061 *str = strdupW(*str);
1069 /******************************************************************************
1070 * _wine_loadsubkey [Internal]
1073 * It seems like this is returning a boolean. Should it?
1079 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1080 int *buflen, DWORD optflag )
1087 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1090 lpkey->flags |= optflag;
1092 /* Good. We already got a line here ... so parse it */
1102 WARN(reg,"Got a subhierarchy without resp. key?\n");
1105 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1109 /* let the caller handle this line */
1110 if (i<level || **buf=='\0')
1113 /* it can be: a value or a keyname. Parse the name first */
1114 s=_wine_read_USTRING(s,&name);
1116 /* switch() default: hack to avoid gotos */
1120 lpxkey=_find_or_add_key(lpkey,name);
1123 int len,lastmodified,type;
1126 WARN(reg,"Unexpected character: %c\n",*s);
1130 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1131 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1135 s=strchr(s,',');s++;
1136 s=strchr(s,',');s++;
1137 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1138 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1140 len = lstrlenW((LPWSTR)data)*2+2;
1145 data = (LPBYTE)xmalloc(len+1);
1146 for (i=0;i<len;i++) {
1148 if (*s>='0' && *s<='9')
1149 data[i]=(*s-'0')<<4;
1150 if (*s>='a' && *s<='f')
1151 data[i]=(*s-'a'+'\xa')<<4;
1152 if (*s>='A' && *s<='F')
1153 data[i]=(*s-'A'+'\xa')<<4;
1155 if (*s>='0' && *s<='9')
1157 if (*s>='a' && *s<='f')
1158 data[i]|=*s-'a'+'\xa';
1159 if (*s>='A' && *s<='F')
1160 data[i]|=*s-'A'+'\xa';
1164 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1167 /* read the next line */
1168 if (!_wine_read_line(F,buf,buflen))
1175 /******************************************************************************
1176 * _wine_loadsubreg [Internal]
1178 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1184 buf=xmalloc(10);buflen=10;
1185 if (!_wine_read_line(F,&buf,&buflen)) {
1189 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1193 if (ver!=REGISTRY_SAVE_VERSION) {
1194 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1198 if (!_wine_read_line(F,&buf,&buflen)) {
1202 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1211 /******************************************************************************
1212 * _wine_loadreg [Internal]
1214 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1218 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1222 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1225 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1233 /******************************************************************************
1234 * _flush_registry [Internal]
1236 * This function allow to flush section of the internal registry. It is mainly
1237 * implements to fix a problem with the global HKU and the local HKU.
1238 * Those two files are read to build the HKU\.Default branch to finaly copy
1239 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1240 * all the global HKU are saved onto the user's personal version of HKU hive.
1244 /* Forward declaration of recusive agent */
1245 static void _flush_reg(LPKEYSTRUCT from);
1247 static void _flush_registry( LPKEYSTRUCT from )
1249 /* make sure we have something... */
1253 /* Launch the recusive agent on sub branches */
1254 _flush_reg( from->nextsub );
1255 _flush_reg( from->next );
1257 /* Initialize pointers */
1258 from->nextsub = NULL;
1261 static void _flush_reg( LPKEYSTRUCT from )
1265 /* make sure we have something... */
1270 * do the same for the child keys
1272 if (from->nextsub != NULL)
1273 _flush_reg(from->nextsub);
1276 * do the same for the sibling keys
1278 if (from->next != NULL)
1279 _flush_reg(from->next);
1282 * iterate through this key's values and delete them
1284 for (j=0;j<from->nrofvalues;j++)
1286 free( (from->values+j)->name);
1287 free( (from->values+j)->data);
1291 * free the structure
1298 /******************************************************************************
1299 * _copy_registry [Internal]
1301 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1309 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1311 for (j=0;j<from->nrofvalues;j++) {
1315 valfrom = from->values+j;
1317 if (name) name=strdupW(name);
1318 data=(LPBYTE)xmalloc(valfrom->len);
1319 memcpy(data,valfrom->data,valfrom->len);
1327 valfrom->lastmodified
1330 _copy_registry(from,lpxkey);
1336 /* WINDOWS 95 REGISTRY LOADER */
1338 * Structure of a win95 registry database.
1340 * 0 : "CREG" - magic
1342 * 8 : DWORD offset_of_RGDB_part
1343 * 0C..0F: ? (someone fill in please)
1344 * 10: WORD number of RGDB blocks
1346 * 14: WORD always 0000?
1347 * 16: WORD always 0001?
1348 * 18..1F: ? (someone fill in please)
1352 * 0 : "RGKN" - magic
1353 * 4 : DWORD offset to first RGDB section
1354 * 8 : DWORD offset to the root record
1355 * C..0x1B: ? (fill in)
1356 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1358 * Disk Key Entry Structure:
1359 * 00: DWORD - Free entry indicator(?)
1360 * 04: DWORD - Hash = sum of bytes of keyname
1361 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1362 * 0C: DWORD - disk address of PreviousLevel Key.
1363 * 10: DWORD - disk address of Next Sublevel Key.
1364 * 14: DWORD - disk address of Next Key (on same level).
1365 * DKEP>18: WORD - Nr, Low Significant part.
1366 * 1A: WORD - Nr, High Significant part.
1368 * The disk address always points to the nr part of the previous key entry
1369 * of the referenced key. Don't ask me why, or even if I got this correct
1370 * from staring at 1kg of hexdumps. (DKEP)
1372 * The High significant part of the structure seems to equal the number
1373 * of the RGDB section. The low significant part is a unique ID within
1376 * There are two minor corrections to the position of that structure.
1377 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1378 * the DKE reread from there.
1379 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1380 * CPS - I have not experienced the above phenomenon in my registry files
1383 * 00: "RGDB" - magic
1384 * 04: DWORD offset to next RGDB section
1386 * 0C: WORD always 000d?
1387 * 0E: WORD RGDB block number
1388 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1390 * 20.....: disk keys
1393 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1394 * 08: WORD nrLS - low significant part of NR
1395 * 0A: WORD nrHS - high significant part of NR
1396 * 0C: DWORD bytesused - bytes used in this structure.
1397 * 10: WORD name_len - length of name in bytes. without \0
1398 * 12: WORD nr_of_values - number of values.
1399 * 14: char name[name_len] - name string. No \0.
1400 * 14+name_len: disk values
1401 * nextkeyoffset: ... next disk key
1404 * 00: DWORD type - value type (hmm, could be WORD too)
1405 * 04: DWORD - unknown, usually 0
1406 * 08: WORD namelen - length of Name. 0 means name=NULL
1407 * 0C: WORD datalen - length of Data.
1408 * 10: char name[namelen] - name, no \0
1409 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1410 * 10+namelen+datalen: next values or disk key
1412 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1413 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1414 * structure) and reading another RGDB_section.
1415 * repeat until end of file.
1417 * An interesting relationship exists in RGDB_section. The value at offset
1418 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1419 * idea at the moment what this means. (Kevin Cozens)
1421 * FIXME: this description needs some serious help, yes.
1424 struct _w95keyvalue {
1426 unsigned short datalen;
1428 unsigned char *data;
1436 struct _w95keyvalue *values;
1437 struct _w95key *prevlvl;
1438 struct _w95key *nextsub;
1439 struct _w95key *next;
1453 /******************************************************************************
1454 * _w95_processKey [Internal]
1456 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1457 int nrLS, int nrMS, struct _w95_info *info )
1460 /* Disk Key Header structure (RGDB part) */
1462 unsigned long nextkeyoff;
1463 unsigned short nrLS;
1464 unsigned short nrMS;
1465 unsigned long bytesused;
1466 unsigned short keynamelen;
1467 unsigned short values;
1470 /* disk key values or nothing */
1472 /* Disk Key Value structure */
1476 unsigned short valnamelen;
1477 unsigned short valdatalen;
1478 /* valname, valdata */
1484 char *rgdbdata = info->rgdbbuffer;
1485 int nbytes = info->rgdbsize;
1486 char *curdata = rgdbdata;
1487 char *end = rgdbdata + nbytes;
1489 char *next = rgdbdata;
1495 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1497 memcpy(&off_next_rgdb,curdata+4,4);
1498 next = curdata + off_next_rgdb;
1499 nrgdb = (int) *((short *)curdata + 7);
1501 } while (nrgdb != nrMS && (next < end));
1503 /* curdata now points to the start of the right RGDB section */
1506 #define XREAD(whereto,len) \
1507 if ((curdata + len) <= end) {\
1508 memcpy(whereto,curdata,len);\
1513 while (curdata < next) {
1514 struct dkh *xdkh = (struct dkh*)curdata;
1516 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1517 if (xdkh->nrLS == nrLS) {
1518 memcpy(&dkh,xdkh,sizeof(dkh));
1519 curdata += sizeof(dkh);
1522 curdata += xdkh->nextkeyoff;
1525 if (dkh.nrLS != nrLS) return (NULL);
1527 if (nrgdb != dkh.nrMS)
1530 assert((dkh.keynamelen<2) || curdata[0]);
1531 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1532 curdata += dkh.keynamelen;
1534 for (i=0;i< dkh.values; i++) {
1540 XREAD(&dkv,sizeof(dkv));
1542 name = strcvtA2W(curdata, dkv.valnamelen);
1543 curdata += dkv.valnamelen;
1545 if ((1 << dkv.type) & UNICONVMASK) {
1546 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1547 len = 2*(dkv.valdatalen + 1);
1549 /* I don't think we want to NULL terminate all data */
1550 data = xmalloc(dkv.valdatalen);
1551 memcpy (data, curdata, dkv.valdatalen);
1552 len = dkv.valdatalen;
1555 curdata += dkv.valdatalen;
1569 /******************************************************************************
1570 * _w95_walkrgkn [Internal]
1572 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1573 struct _w95_info *info )
1576 /* Disk Key Entry structure (RGKN part) */
1580 unsigned long x3;/*usually 0xFFFFFFFF */
1581 unsigned long prevlvl;
1582 unsigned long nextsub;
1584 unsigned short nrLS;
1585 unsigned short nrMS;
1586 } *dke = (struct dke *)off;
1590 dke = (struct dke *) ((char *)info->rgknbuffer);
1593 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1594 /* XXX <-- This is a hack*/
1599 if (dke->nextsub != -1 &&
1600 ((dke->nextsub - 0x20) < info->rgknsize)
1601 && (dke->nextsub > 0x20)) {
1603 _w95_walkrgkn(lpxkey,
1604 info->rgknbuffer + dke->nextsub - 0x20,
1608 if (dke->next != -1 &&
1609 ((dke->next - 0x20) < info->rgknsize) &&
1610 (dke->next > 0x20)) {
1611 _w95_walkrgkn(prevkey,
1612 info->rgknbuffer + dke->next - 0x20,
1620 /******************************************************************************
1621 * _w95_loadreg [Internal]
1623 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1627 unsigned long where,version,rgdbsection,end;
1628 struct _w95_info info;
1630 BY_HANDLE_FILE_INFORMATION hfdinfo;
1632 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1633 hfd=OpenFile(fn,&ofs,OF_READ);
1634 if (hfd==HFILE_ERROR)
1637 if (4!=_lread(hfd,magic,4))
1639 if (strcmp(magic,"CREG")) {
1640 WARN(reg,"%s is not a w95 registry.\n",fn);
1643 if (4!=_lread(hfd,&version,4))
1645 if (4!=_lread(hfd,&rgdbsection,4))
1647 if (-1==_llseek(hfd,0x20,SEEK_SET))
1649 if (4!=_lread(hfd,magic,4))
1651 if (strcmp(magic,"RGKN")) {
1652 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1656 /* STEP 1: Keylink structures */
1657 if (-1==_llseek(hfd,0x40,SEEK_SET))
1662 info.rgknsize = end - where;
1663 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1664 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1667 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1670 end = hfdinfo.nFileSizeLow;
1671 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1673 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1676 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1677 info.rgdbsize = end - rgdbsection;
1679 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1683 _w95_walkrgkn(lpkey, NULL, &info);
1685 free (info.rgdbbuffer);
1686 free (info.rgknbuffer);
1690 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1693 reghack - windows 3.11 registry data format demo program.
1695 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1696 a combined hash table and tree description, and finally a text table.
1698 The header is obvious from the struct header. The taboff1 and taboff2
1699 fields are always 0x20, and their usage is unknown.
1701 The 8-byte entry table has various entry types.
1703 tabent[0] is a root index. The second word has the index of the root of
1705 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1706 the index of the key/value that has that hash. Data with the same
1707 hash value are on a circular list. The other three words in the
1708 hash entry are always zero.
1709 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1710 entry: dirent and keyent/valent. They are identified by context.
1711 tabent[freeidx] is the first free entry. The first word in a free entry
1712 is the index of the next free entry. The last has 0 as a link.
1713 The other three words in the free list are probably irrelevant.
1715 Entries in text table are preceeded by a word at offset-2. This word
1716 has the value (2*index)+1, where index is the referring keyent/valent
1717 entry in the table. I have no suggestion for the 2* and the +1.
1718 Following the word, there are N bytes of data, as per the keyent/valent
1719 entry length. The offset of the keyent/valent entry is from the start
1720 of the text table to the first data byte.
1722 This information is not available from Microsoft. The data format is
1723 deduced from the reg.dat file by me. Mistakes may
1724 have been made. I claim no rights and give no guarantees for this program.
1726 Tor Sjøwall, tor@sn.no
1729 /* reg.dat header format */
1730 struct _w31_header {
1731 char cookie[8]; /* 'SHCC3.10' */
1732 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1733 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1734 unsigned long tabcnt; /* number of entries in index table */
1735 unsigned long textoff; /* offset of text part */
1736 unsigned long textsize; /* byte size of text part */
1737 unsigned short hashsize; /* hash size */
1738 unsigned short freeidx; /* free index */
1741 /* generic format of table entries */
1742 struct _w31_tabent {
1743 unsigned short w0, w1, w2, w3;
1746 /* directory tabent: */
1747 struct _w31_dirent {
1748 unsigned short sibling_idx; /* table index of sibling dirent */
1749 unsigned short child_idx; /* table index of child dirent */
1750 unsigned short key_idx; /* table index of key keyent */
1751 unsigned short value_idx; /* table index of value valent */
1755 struct _w31_keyent {
1756 unsigned short hash_idx; /* hash chain index for string */
1757 unsigned short refcnt; /* reference count */
1758 unsigned short length; /* length of string */
1759 unsigned short string_off; /* offset of string in text table */
1763 struct _w31_valent {
1764 unsigned short hash_idx; /* hash chain index for string */
1765 unsigned short refcnt; /* reference count */
1766 unsigned short length; /* length of string */
1767 unsigned short string_off; /* offset of string in text table */
1770 /* recursive helper function to display a directory tree */
1772 __w31_dumptree( unsigned short idx,
1774 struct _w31_tabent *tab,
1775 struct _w31_header *head,
1777 time_t lastmodified,
1780 struct _w31_dirent *dir;
1781 struct _w31_keyent *key;
1782 struct _w31_valent *val;
1783 LPKEYSTRUCT xlpkey = NULL;
1785 static char tail[400];
1788 dir=(struct _w31_dirent*)&tab[idx];
1791 key = (struct _w31_keyent*)&tab[dir->key_idx];
1793 memcpy(tail,&txt[key->string_off],key->length);
1794 tail[key->length]='\0';
1795 /* all toplevel entries AND the entries in the
1796 * toplevel subdirectory belong to \SOFTWARE\Classes
1798 if (!level && !lstrcmpA(tail,".classes")) {
1799 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1800 idx=dir->sibling_idx;
1803 name=strdupA2W(tail);
1805 xlpkey=_find_or_add_key(lpkey,name);
1807 /* only add if leaf node or valued node */
1808 if (dir->value_idx!=0||dir->child_idx==0) {
1809 if (dir->value_idx) {
1810 val=(struct _w31_valent*)&tab[dir->value_idx];
1811 memcpy(tail,&txt[val->string_off],val->length);
1812 tail[val->length]='\0';
1813 value=strdupA2W(tail);
1814 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1818 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1820 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1821 idx=dir->sibling_idx;
1826 /******************************************************************************
1827 * _w31_loadreg [Internal]
1829 void _w31_loadreg(void) {
1831 struct _w31_header head;
1832 struct _w31_tabent *tab;
1836 BY_HANDLE_FILE_INFORMATION hfinfo;
1837 time_t lastmodified;
1840 TRACE(reg,"(void)\n");
1842 hf = OpenFile("reg.dat",&ofs,OF_READ);
1843 if (hf==HFILE_ERROR)
1846 /* read & dump header */
1847 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1848 ERR(reg, "reg.dat is too short.\n");
1852 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1853 ERR(reg, "reg.dat has bad signature.\n");
1858 len = head.tabcnt * sizeof(struct _w31_tabent);
1859 /* read and dump index table */
1861 if (len!=_lread(hf,tab,len)) {
1862 ERR(reg,"couldn't read %d bytes.\n",len);
1869 txt = xmalloc(head.textsize);
1870 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1871 ERR(reg,"couldn't seek to textblock.\n");
1877 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1878 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1885 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1886 ERR(reg,"GetFileInformationByHandle failed?.\n");
1892 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1893 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1894 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1902 /**********************************************************************************
1903 * SHELL_LoadRegistry [Internal]
1905 void SHELL_LoadRegistry( void )
1909 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1912 TRACE(reg,"(void)\n");
1914 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1915 HKU = lookup_hkey(HKEY_USERS);
1916 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1918 /* Load windows 3.1 entries */
1920 /* Load windows 95 entries */
1921 _w95_loadreg("C:\\system.1st", HKLM);
1922 _w95_loadreg("system.dat", HKLM);
1923 _w95_loadreg("user.dat", HKU);
1926 * Load the global HKU hive directly from /usr/local/etc
1928 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1931 * Load the global machine defaults directly form /usr/local/etc
1933 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1935 /* Get current user info */
1936 pwd=getpwuid(getuid());
1939 * Load the user saved registries
1941 if ( (pwd != NULL) &&
1942 (pwd->pw_dir != NULL) )
1945 * Load user's personal versions of global HKU/.Default keys
1948 strlen(pwd->pw_dir)+
1949 strlen(WINE_PREFIX)+
1950 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1952 strcpy(fn, pwd->pw_dir);
1953 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1954 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1958 * Load HKCU, 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(
1967 MAX_PATHNAME_LEN - 1))
1969 _wine_loadreg(HKCU,fn,0);
1974 strlen(pwd->pw_dir)+
1975 strlen(WINE_PREFIX)+
1976 strlen(SAVE_CURRENT_USER)+2);
1978 strcpy(fn, pwd->pw_dir);
1979 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1980 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1984 * Load HKLM, attempt to get the registry location from the config
1985 * file first, if exist, load and keep going.
1987 fn = xmalloc ( MAX_PATHNAME_LEN);
1988 if ( PROFILE_GetWineIniString(
1990 "LocalMachineFileName",
1993 MAX_PATHNAME_LEN - 1))
1995 _wine_loadreg(HKLM, fn, 0);
2000 strlen(pwd->pw_dir)+
2001 strlen(WINE_PREFIX)+
2002 strlen(SAVE_LOCAL_MACHINE)+2);
2004 strcpy(fn,pwd->pw_dir);
2005 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2006 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2011 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
2015 * Obtain the handle of the HKU\.Default key.
2016 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2018 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2019 lpkey = lookup_hkey(hkey);
2021 WARN(reg,"Could not create global user default key\n");
2023 _copy_registry(lpkey, HKCU );
2028 * Since HKU is built from the global HKU and the local user HKU file we must
2029 * flush the HKU tree we have built at this point otherwise the part brought
2030 * in from the global HKU is saved into the local HKU. To avoid this
2031 * useless dupplication of HKU keys we reread the local HKU key.
2034 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2035 _flush_registry(HKU);
2037 /* Reload user's local HKU hive */
2039 strlen(pwd->pw_dir)+
2040 strlen(WINE_PREFIX)+
2041 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2043 strcpy(fn,pwd->pw_dir);
2044 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2046 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2051 * Make sure the update mode is there
2053 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2055 DWORD junk,type,len;
2059 if (( RegQueryValueExA(
2065 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2067 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2075 /********************* API FUNCTIONS ***************************************/
2079 * All functions are stubs to RegOpenKeyEx32W where all the
2083 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2084 * RegOpenKey32W -> RegOpenKeyEx32W
2088 /******************************************************************************
2089 * RegOpenKeyEx32W [ADVAPI32.150]
2090 * Opens the specified key
2092 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2095 * hkey [I] Handle of open key
2096 * lpszSubKey [I] Name of subkey to open
2097 * dwReserved [I] Reserved - must be zero
2098 * samDesired [I] Security access mask
2099 * retkey [O] Address of handle of open key
2102 * Success: ERROR_SUCCESS
2103 * Failure: Error code
2105 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2106 REGSAM samDesired, LPHKEY retkey )
2108 LPKEYSTRUCT lpNextKey,lpxkey;
2112 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2115 lpNextKey = lookup_hkey( hkey );
2117 return ERROR_INVALID_HANDLE;
2119 if (!lpszSubKey || !*lpszSubKey) {
2120 /* Either NULL or pointer to empty string, so return a new handle
2121 to the original hkey */
2123 add_handle(currenthandle,lpNextKey,samDesired);
2124 *retkey=currenthandle;
2125 return ERROR_SUCCESS;
2128 if (lpszSubKey[0] == '\\') {
2129 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2130 return ERROR_BAD_PATHNAME;
2133 split_keypath(lpszSubKey,&wps,&wpc);
2135 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2139 lpxkey=lpNextKey->nextsub;
2141 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2144 lpxkey=lpxkey->next;
2148 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
2150 return ERROR_FILE_NOT_FOUND;
2157 add_handle(currenthandle,lpxkey,samDesired);
2158 *retkey = currenthandle;
2159 TRACE(reg," Returning %x\n", currenthandle);
2161 return ERROR_SUCCESS;
2165 /******************************************************************************
2166 * RegOpenKeyEx32A [ADVAPI32.149]
2168 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2169 REGSAM samDesired, LPHKEY retkey )
2171 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2174 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2176 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2182 /******************************************************************************
2183 * RegOpenKey32W [ADVAPI32.151]
2186 * hkey [I] Handle of open key
2187 * lpszSubKey [I] Address of name of subkey to open
2188 * retkey [O] Address of handle of open key
2191 * Success: ERROR_SUCCESS
2192 * Failure: Error code
2194 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2196 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2197 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2201 /******************************************************************************
2202 * RegOpenKey32A [ADVAPI32.148]
2204 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2207 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2208 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2209 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2215 /******************************************************************************
2216 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2218 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2220 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2221 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2228 * All those functions convert their respective
2229 * arguments and call RegCreateKeyExW at the end.
2231 * We stay away from the Ex functions as long as possible because there are
2232 * differences in the return values
2235 * RegCreateKeyEx32A \
2236 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2240 /******************************************************************************
2241 * RegCreateKeyEx32W [ADVAPI32.131]
2244 * hkey [I] Handle of an open key
2245 * lpszSubKey [I] Address of subkey name
2246 * dwReserved [I] Reserved - must be 0
2247 * lpszClass [I] Address of class string
2248 * fdwOptions [I] Special options flag
2249 * samDesired [I] Desired security access
2250 * lpSecAttribs [I] Address of key security structure
2251 * retkey [O] Address of buffer for opened handle
2252 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2254 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2255 DWORD dwReserved, LPWSTR lpszClass,
2256 DWORD fdwOptions, REGSAM samDesired,
2257 LPSECURITY_ATTRIBUTES lpSecAttribs,
2258 LPHKEY retkey, LPDWORD lpDispos )
2260 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2264 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2265 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2266 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2268 lpNextKey = lookup_hkey(hkey);
2270 return ERROR_INVALID_HANDLE;
2272 /* Check for valid options */
2273 switch(fdwOptions) {
2274 case REG_OPTION_NON_VOLATILE:
2275 case REG_OPTION_VOLATILE:
2276 case REG_OPTION_BACKUP_RESTORE:
2279 return ERROR_INVALID_PARAMETER;
2282 /* Sam has to be a combination of the following */
2284 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2285 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2286 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2287 return ERROR_INVALID_PARAMETER;
2289 if (!lpszSubKey || !*lpszSubKey) {
2291 add_handle(currenthandle,lpNextKey,samDesired);
2292 *retkey=currenthandle;
2293 TRACE(reg, "Returning %x\n", currenthandle);
2294 lpNextKey->flags|=REG_OPTION_TAINTED;
2295 return ERROR_SUCCESS;
2298 if (lpszSubKey[0] == '\\') {
2299 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2300 return ERROR_BAD_PATHNAME;
2303 split_keypath(lpszSubKey,&wps,&wpc);
2305 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2308 lpxkey=lpNextKey->nextsub;
2310 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2312 lpxkey=lpxkey->next;
2321 add_handle(currenthandle,lpxkey,samDesired);
2322 lpxkey->flags |= REG_OPTION_TAINTED;
2323 *retkey = currenthandle;
2324 TRACE(reg, "Returning %x\n", currenthandle);
2326 *lpDispos = REG_OPENED_EXISTING_KEY;
2328 return ERROR_SUCCESS;
2331 /* Good. Now the hard part */
2333 lplpPrevKey = &(lpNextKey->nextsub);
2334 lpxkey = *lplpPrevKey;
2336 lplpPrevKey = &(lpxkey->next);
2337 lpxkey = *lplpPrevKey;
2339 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2340 if (!*lplpPrevKey) {
2342 TRACE(reg, "Returning OUTOFMEMORY\n");
2343 return ERROR_OUTOFMEMORY;
2345 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2346 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2347 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2348 (*lplpPrevKey)->next = NULL;
2349 (*lplpPrevKey)->nextsub = NULL;
2350 (*lplpPrevKey)->values = NULL;
2351 (*lplpPrevKey)->nrofvalues = 0;
2352 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2354 (*lplpPrevKey)->class = strdupW(lpszClass);
2356 (*lplpPrevKey)->class = NULL;
2357 lpNextKey = *lplpPrevKey;
2361 add_handle(currenthandle,lpNextKey,samDesired);
2363 /*FIXME: flag handling correct? */
2364 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2366 lpNextKey->class = strdupW(lpszClass);
2368 lpNextKey->class = NULL;
2369 *retkey = currenthandle;
2370 TRACE(reg, "Returning %x\n", currenthandle);
2372 *lpDispos = REG_CREATED_NEW_KEY;
2374 return ERROR_SUCCESS;
2378 /******************************************************************************
2379 * RegCreateKeyEx32A [ADVAPI32.130]
2381 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2382 LPSTR lpszClass, DWORD fdwOptions,
2384 LPSECURITY_ATTRIBUTES lpSecAttribs,
2385 LPHKEY retkey, LPDWORD lpDispos )
2387 LPWSTR lpszSubKeyW, lpszClassW;
2390 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2391 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2394 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2395 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2397 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2398 fdwOptions, samDesired, lpSecAttribs, retkey,
2401 if(lpszSubKeyW) free(lpszSubKeyW);
2402 if(lpszClassW) free(lpszClassW);
2408 /******************************************************************************
2409 * RegCreateKey32W [ADVAPI32.132]
2411 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2414 LPKEYSTRUCT lpNextKey;
2416 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2418 /* This check is here because the return value is different than the
2419 one from the Ex functions */
2420 lpNextKey = lookup_hkey(hkey);
2422 return ERROR_BADKEY;
2424 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2425 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2430 /******************************************************************************
2431 * RegCreateKey32A [ADVAPI32.129]
2433 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2438 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2439 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2440 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2441 if(lpszSubKeyW) free(lpszSubKeyW);
2446 /******************************************************************************
2447 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2449 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2451 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2452 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2457 * Query Value Functions
2458 * Win32 differs between keynames and valuenames.
2459 * multiple values may belong to one key, the special value
2460 * with name NULL is the default value used by the win31
2464 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2465 * RegQueryValue32W -> RegQueryValueEx32W
2469 /******************************************************************************
2470 * RegQueryValueEx32W [ADVAPI32.158]
2471 * Retrieves type and data for a specified name associated with an open key
2474 * hkey [I] Handle of key to query
2475 * lpValueName [I] Name of value to query
2476 * lpdwReserved [I] Reserved - must be NULL
2477 * lpdwType [O] Address of buffer for value type. If NULL, the type
2479 * lpbData [O] Address of data buffer. If NULL, the actual data is
2481 * lpcbData [I/O] Address of data buffer size
2484 * ERROR_SUCCESS: Success
2485 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2486 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2488 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2489 LPDWORD lpdwReserved, LPDWORD lpdwType,
2490 LPBYTE lpbData, LPDWORD lpcbData )
2496 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2497 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2499 lpkey = lookup_hkey(hkey);
2502 return ERROR_INVALID_HANDLE;
2504 if ((lpbData && ! lpcbData) || lpdwReserved)
2505 return ERROR_INVALID_PARAMETER;
2507 if (lpbData && lpcbData)
2508 memset(lpbData,0,*lpcbData);
2510 /* An empty name string is equivalent to NULL */
2511 if (lpValueName && !*lpValueName)
2514 if (lpValueName==NULL)
2515 { /* Use key's unnamed or default value, if any */
2516 for (i=0;i<lpkey->nrofvalues;i++)
2517 if (lpkey->values[i].name==NULL)
2521 { /* Search for the key name */
2522 for (i=0;i<lpkey->nrofvalues;i++)
2523 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2527 if (i==lpkey->nrofvalues)
2528 { TRACE(reg," Key not found\n");
2529 if (lpValueName==NULL)
2530 { /* Empty keyname not found */
2532 { *(WCHAR*)lpbData = 0;
2537 TRACE(reg, " Returning an empty string\n");
2538 return ERROR_SUCCESS;
2540 return ERROR_FILE_NOT_FOUND;
2543 ret = ERROR_SUCCESS;
2545 if (lpdwType) /* type required ?*/
2546 *lpdwType = lpkey->values[i].type;
2548 if (lpbData) /* data required ?*/
2549 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2550 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2552 ret = ERROR_MORE_DATA;
2555 if (lpcbData) /* size required ?*/
2556 { *lpcbData = lpkey->values[i].len;
2559 debug_print_value ( lpbData, &lpkey->values[i]);
2561 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2567 /******************************************************************************
2568 * RegQueryValue32W [ADVAPI32.159]
2570 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2576 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2577 lpcbData?*lpcbData:0);
2579 if (lpszData && lpcbData)
2580 memset(lpszData,0,*lpcbData);
2582 /* Only open subkey, if we really do descend */
2583 if (lpszSubKey && *lpszSubKey) {
2584 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2585 if (ret != ERROR_SUCCESS) {
2586 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2593 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2601 /******************************************************************************
2602 * RegQueryValueEx32A [ADVAPI32.157]
2605 * the documantation is wrong: if the buffer is to small it remains untouched
2607 * FIXME: check returnvalue (len) for an empty key
2609 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2610 LPDWORD lpdwReserved, LPDWORD lpdwType,
2611 LPBYTE lpbData, LPDWORD lpcbData )
2613 LPWSTR lpszValueNameW;
2614 LPBYTE mybuf = NULL;
2615 DWORD ret, mytype, mylen = 0;
2617 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2618 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2620 if (!lpcbData && lpbData) /* buffer without size is illegal */
2621 { return ERROR_INVALID_PARAMETER;
2624 if (lpbData && lpcbData)
2625 memset(lpbData,0,*lpcbData);
2627 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2629 /* get just the type first */
2630 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2632 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2633 { if(lpszValueNameW) free(lpszValueNameW);
2637 if (lpcbData) /* at least length requested? */
2638 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2639 { if (lpbData ) /* value requested? */
2640 { mylen = 2*( *lpcbData );
2641 mybuf = (LPBYTE)xmalloc( mylen );
2644 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2646 if (ret == ERROR_SUCCESS )
2648 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2652 *lpcbData = mylen/2; /* size is in byte! */
2654 else /* no strings, call it straight */
2655 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2659 if (lpdwType) /* type when requested */
2660 { *lpdwType = mytype;
2663 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2665 if(mybuf) free(mybuf);
2666 if(lpszValueNameW) free(lpszValueNameW);
2671 /******************************************************************************
2672 * RegQueryValueEx16 [KERNEL.225]
2674 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2675 LPDWORD lpdwReserved, LPDWORD lpdwType,
2676 LPBYTE lpbData, LPDWORD lpcbData )
2678 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2679 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2680 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2681 lpbData, lpcbData );
2685 /******************************************************************************
2686 * RegQueryValue32A [ADVAPI32.156]
2688 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2694 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2695 lpcbData?*lpcbData:0);
2697 if (lpszData && lpcbData)
2698 memset(lpszData,0,*lpcbData);
2700 if (lpszSubKey && *lpszSubKey) {
2701 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2702 if( ret != ERROR_SUCCESS )
2708 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2711 RegCloseKey( xhkey );
2716 /******************************************************************************
2717 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2720 * Is this HACK still applicable?
2723 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2724 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2727 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2730 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2731 lpcbData?*lpcbData:0);
2734 *lpcbData &= 0xFFFF;
2735 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2740 * Setting values of Registry keys
2743 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2744 * RegSetValue32W -> RegSetValueEx32W
2748 /******************************************************************************
2749 * RegSetValueEx32W [ADVAPI32.170]
2750 * Sets the data and type of a value under a register key
2753 * hkey [I] Handle of key to set value for
2754 * lpszValueName [I] Name of value to set
2755 * dwReserved [I] Reserved - must be zero
2756 * dwType [I] Flag for value type
2757 * lpbData [I] Address of value data
2758 * cbData [I] Size of value data
2761 * Success: ERROR_SUCCESS
2762 * Failure: Error code
2765 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2767 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2768 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2774 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2775 dwReserved, dwType, lpbData, cbData);
2777 lpkey = lookup_hkey( hkey );
2780 return ERROR_INVALID_HANDLE;
2782 lpkey->flags |= REG_OPTION_TAINTED;
2784 if (lpszValueName==NULL) {
2785 /* Sets type and name for key's unnamed or default value */
2786 for (i=0;i<lpkey->nrofvalues;i++)
2787 if (lpkey->values[i].name==NULL)
2790 for (i=0;i<lpkey->nrofvalues;i++)
2791 if ( lpkey->values[i].name &&
2792 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2796 if (i==lpkey->nrofvalues) {
2797 lpkey->values = (LPKEYVALUE)xrealloc(
2799 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2801 lpkey->nrofvalues++;
2802 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2804 if (lpkey->values[i].name==NULL) {
2806 lpkey->values[i].name = strdupW(lpszValueName);
2808 lpkey->values[i].name = NULL;
2811 if (dwType == REG_SZ)
2812 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2814 lpkey->values[i].len = cbData;
2815 lpkey->values[i].type = dwType;
2816 if (lpkey->values[i].data !=NULL)
2817 free(lpkey->values[i].data);
2818 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2819 lpkey->values[i].lastmodified = time(NULL);
2820 memcpy(lpkey->values[i].data,lpbData,cbData);
2821 return ERROR_SUCCESS;
2825 /******************************************************************************
2826 * RegSetValueEx32A [ADVAPI32.169]
2829 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2831 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2832 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2836 LPWSTR lpszValueNameW;
2840 return (ERROR_INVALID_PARAMETER);
2842 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2843 dwReserved,dwType,lpbData,cbData);
2845 if ((1<<dwType) & UNICONVMASK)
2846 { if (dwType == REG_SZ)
2847 cbData = strlen ((LPCSTR)lpbData)+1;
2849 buf = (LPBYTE)xmalloc( cbData *2 );
2850 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2857 lpszValueNameW = strdupA2W(lpszValueName);
2859 lpszValueNameW = NULL;
2861 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2864 free(lpszValueNameW);
2873 /******************************************************************************
2874 * RegSetValueEx16 [KERNEL.226]
2876 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2877 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2879 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2880 dwReserved,dwType,lpbData,cbData);
2881 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2886 /******************************************************************************
2887 * RegSetValue32W [ADVAPI32.171]
2889 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2890 LPCWSTR lpszData, DWORD cbData )
2895 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2896 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2898 if (lpszSubKey && *lpszSubKey) {
2899 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2900 if (ret!=ERROR_SUCCESS)
2904 if (dwType!=REG_SZ) {
2905 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2908 if (cbData!=2*lstrlenW(lpszData)+2) {
2909 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2910 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2912 cbData=2*lstrlenW(lpszData)+2;
2914 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2921 /******************************************************************************
2922 * RegSetValue32A [ADVAPI32.168]
2925 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2926 LPCSTR lpszData, DWORD cbData )
2931 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2932 if (lpszSubKey && *lpszSubKey) {
2933 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2934 if (ret!=ERROR_SUCCESS)
2939 if (dwType!=REG_SZ) {
2940 TRACE(reg,"dwType=%ld!\n",dwType);
2943 if (cbData!=strlen(lpszData)+1)
2944 cbData=strlen(lpszData)+1;
2945 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2952 /******************************************************************************
2953 * RegSetValue16 [KERNEL.221] [SHELL.5]
2955 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2956 LPCSTR lpszData, DWORD cbData )
2958 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2959 debugstr_a(lpszData),cbData);
2960 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2968 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2969 * RegEnumKey32W -> RegEnumKeyEx32W
2973 /******************************************************************************
2974 * RegEnumKeyEx32W [ADVAPI32.139]
2977 * hkey [I] Handle to key to enumerate
2978 * iSubKey [I] Index of subkey to enumerate
2979 * lpszName [O] Buffer for subkey name
2980 * lpcchName [O] Size of subkey buffer
2981 * lpdwReserved [I] Reserved
2982 * lpszClass [O] Buffer for class string
2983 * lpcchClass [O] Size of class buffer
2984 * ft [O] Time key last written to
2986 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2987 LPDWORD lpcchName, LPDWORD lpdwReserved,
2988 LPWSTR lpszClass, LPDWORD lpcchClass,
2991 LPKEYSTRUCT lpkey,lpxkey;
2993 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2994 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2996 lpkey = lookup_hkey( hkey );
2998 return ERROR_INVALID_HANDLE;
3000 if (!lpkey->nextsub)
3001 return ERROR_NO_MORE_ITEMS;
3002 lpxkey=lpkey->nextsub;
3004 /* Traverse the subkeys */
3005 while (iSubkey && lpxkey) {
3007 lpxkey=lpxkey->next;
3010 if (iSubkey || !lpxkey)
3011 return ERROR_NO_MORE_ITEMS;
3012 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
3013 return ERROR_MORE_DATA;
3014 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3017 *lpcchName = lstrlenW(lpszName);
3020 /* FIXME: what should we write into it? */
3024 return ERROR_SUCCESS;
3028 /******************************************************************************
3029 * RegEnumKey32W [ADVAPI32.140]
3031 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3036 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3037 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3041 /******************************************************************************
3042 * RegEnumKeyEx32A [ADVAPI32.138]
3044 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3045 LPDWORD lpcchName, LPDWORD lpdwReserved,
3046 LPSTR lpszClass, LPDWORD lpcchClass,
3049 DWORD ret,lpcchNameW,lpcchClassW;
3050 LPWSTR lpszNameW,lpszClassW;
3053 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3054 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3057 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3058 lpcchNameW = *lpcchName;
3064 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3065 lpcchClassW = *lpcchClass;
3080 if (ret==ERROR_SUCCESS) {
3081 lstrcpyWtoA(lpszName,lpszNameW);
3082 *lpcchName=strlen(lpszName);
3084 lstrcpyWtoA(lpszClass,lpszClassW);
3085 *lpcchClass=strlen(lpszClass);
3096 /******************************************************************************
3097 * RegEnumKey32A [ADVAPI32.137]
3099 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3104 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3105 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3110 /******************************************************************************
3111 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3113 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3116 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3117 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3122 * Enumerate Registry Values
3125 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3129 /******************************************************************************
3130 * RegEnumValue32W [ADVAPI32.142]
3133 * hkey [I] Handle to key to query
3134 * iValue [I] Index of value to query
3135 * lpszValue [O] Value string
3136 * lpcchValue [I/O] Size of value buffer (in wchars)
3137 * lpdReserved [I] Reserved
3138 * lpdwType [O] Type code
3139 * lpbData [O] Value data
3140 * lpcbData [I/O] Size of data buffer (in bytes)
3142 * Note: wide character functions that take and/or return "character counts"
3143 * use TCHAR (that is unsigned short or char) not byte counts.
3145 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3146 LPDWORD lpcchValue, LPDWORD lpdReserved,
3147 LPDWORD lpdwType, LPBYTE lpbData,
3153 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3154 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3156 lpkey = lookup_hkey( hkey );
3158 if (!lpcbData && lpbData)
3159 return ERROR_INVALID_PARAMETER;
3162 return ERROR_INVALID_HANDLE;
3164 if (lpkey->nrofvalues <= iValue)
3165 return ERROR_NO_MORE_ITEMS;
3167 val = &(lpkey->values[iValue]);
3170 if (lstrlenW(val->name)+1>*lpcchValue) {
3171 *lpcchValue = lstrlenW(val->name)+1;
3172 return ERROR_MORE_DATA;
3174 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3175 *lpcchValue=lstrlenW(val->name);
3181 /* Can be NULL if the type code is not required */
3183 *lpdwType = val->type;
3186 if (val->len>*lpcbData)
3187 return ERROR_MORE_DATA;
3188 memcpy(lpbData,val->data,val->len);
3189 *lpcbData = val->len;
3192 debug_print_value ( val->data, val );
3193 return ERROR_SUCCESS;
3197 /******************************************************************************
3198 * RegEnumValue32A [ADVAPI32.141]
3200 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3201 LPDWORD lpcchValue, LPDWORD lpdReserved,
3202 LPDWORD lpdwType, LPBYTE lpbData,
3207 DWORD ret,lpcbDataW;
3210 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3211 lpdReserved,lpdwType,lpbData,lpcbData);
3213 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3215 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3216 lpcbDataW = *lpcbData;
3220 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3221 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3226 if (ret==ERROR_SUCCESS) {
3227 lstrcpyWtoA(lpszValue,lpszValueW);
3229 if ((1<<dwType) & UNICONVMASK) {
3230 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3232 if (lpcbDataW > *lpcbData)
3233 ret = ERROR_MORE_DATA;
3235 memcpy(lpbData,lpbDataW,lpcbDataW);
3237 *lpcbData = lpcbDataW;
3240 if (lpbDataW) free(lpbDataW);
3241 if (lpszValueW) free(lpszValueW);
3246 /******************************************************************************
3247 * RegEnumValue16 [KERNEL.223]
3249 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3250 LPDWORD lpcchValue, LPDWORD lpdReserved,
3251 LPDWORD lpdwType, LPBYTE lpbData,
3254 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3255 lpdReserved,lpdwType,lpbData,lpcbData);
3256 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3257 lpdwType, lpbData, lpcbData );
3261 /******************************************************************************
3262 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3263 * Releases the handle of the specified key
3266 * hkey [I] Handle of key to close
3269 * Success: ERROR_SUCCESS
3270 * Failure: Error code
3272 DWORD WINAPI RegCloseKey( HKEY hkey )
3274 TRACE(reg,"(%x)\n",hkey);
3276 /* The standard handles are allowed to succeed, even though they are not
3278 if (is_standard_hkey(hkey))
3279 return ERROR_SUCCESS;
3281 return remove_handle(hkey);
3286 * Delete registry key
3289 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3293 /******************************************************************************
3294 * RegDeleteKey32W [ADVAPI32.134]
3297 * hkey [I] Handle to open key
3298 * lpszSubKey [I] Name of subkey to delete
3301 * Success: ERROR_SUCCESS
3302 * Failure: Error code
3304 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3306 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3310 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3312 lpNextKey = lookup_hkey(hkey);
3314 return ERROR_INVALID_HANDLE;
3316 /* Subkey param cannot be NULL */
3317 if (!lpszSubKey || !*lpszSubKey)
3318 return ERROR_BADKEY;
3320 /* We need to know the previous key in the hier. */
3321 split_keypath(lpszSubKey,&wps,&wpc);
3325 lpxkey=lpNextKey->nextsub;
3327 TRACE(reg, " Scanning [%s]\n",
3328 debugstr_w(lpxkey->keyname));
3329 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3331 lpxkey=lpxkey->next;
3335 TRACE(reg, " Not found.\n");
3336 /* not found is success */
3337 return ERROR_SUCCESS;
3342 lpxkey = lpNextKey->nextsub;
3343 lplpPrevKey = &(lpNextKey->nextsub);
3345 TRACE(reg, " Scanning [%s]\n",
3346 debugstr_w(lpxkey->keyname));
3347 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3349 lplpPrevKey = &(lpxkey->next);
3350 lpxkey = lpxkey->next;
3355 WARN(reg , " Not found.\n");
3356 return ERROR_FILE_NOT_FOUND;
3359 if (lpxkey->nextsub) {
3361 WARN(reg , " Not empty.\n");
3362 return ERROR_CANTWRITE;
3364 *lplpPrevKey = lpxkey->next;
3365 free(lpxkey->keyname);
3367 free(lpxkey->class);
3369 free(lpxkey->values);
3372 TRACE(reg, " Done.\n");
3373 return ERROR_SUCCESS;
3377 /******************************************************************************
3378 * RegDeleteKey32A [ADVAPI32.133]
3380 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3385 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3386 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3387 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3388 if(lpszSubKeyW) free(lpszSubKeyW);
3393 /******************************************************************************
3394 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3396 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3398 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3399 return RegDeleteKeyA( hkey, lpszSubKey );
3404 * Delete registry value
3407 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3411 /******************************************************************************
3412 * RegDeleteValue32W [ADVAPI32.136]
3420 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3426 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3428 lpkey = lookup_hkey( hkey );
3430 return ERROR_INVALID_HANDLE;
3433 for (i=0;i<lpkey->nrofvalues;i++)
3434 if ( lpkey->values[i].name &&
3435 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3439 for (i=0;i<lpkey->nrofvalues;i++)
3440 if (lpkey->values[i].name==NULL)
3444 if (i == lpkey->nrofvalues)
3445 return ERROR_FILE_NOT_FOUND;
3447 val = lpkey->values+i;
3448 if (val->name) free(val->name);
3449 if (val->data) free(val->data);
3453 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3455 lpkey->values = (LPKEYVALUE)xrealloc(
3457 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3459 lpkey->nrofvalues--;
3460 return ERROR_SUCCESS;
3464 /******************************************************************************
3465 * RegDeleteValue32A [ADVAPI32.135]
3467 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3472 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3473 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3474 ret = RegDeleteValueW( hkey, lpszValueW );
3475 if(lpszValueW) free(lpszValueW);
3480 /******************************************************************************
3481 * RegDeleteValue16 [KERNEL.222]
3483 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3485 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3486 return RegDeleteValueA( hkey, lpszValue );
3490 /******************************************************************************
3491 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3492 * Writes key to registry
3495 * hkey [I] Handle of key to write
3498 * Success: ERROR_SUCCESS
3499 * Failure: Error code
3501 DWORD WINAPI RegFlushKey( HKEY hkey )
3506 TRACE(reg, "(%x)\n", hkey);
3508 lpkey = lookup_hkey( hkey );
3510 return ERROR_BADKEY;
3512 ERR(reg, "What is the correct filename?\n");
3514 ret = _savereg( lpkey, "foo.bar", TRUE);
3517 return ERROR_SUCCESS;
3519 return ERROR_UNKNOWN; /* FIXME */
3523 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3526 /******************************************************************************
3527 * RegQueryInfoKey32W [ADVAPI32.153]
3530 * hkey [I] Handle to key to query
3531 * lpszClass [O] Buffer for class string
3532 * lpcchClass [O] Size of class string buffer
3533 * lpdwReserved [I] Reserved
3534 * lpcSubKeys [I] Buffer for number of subkeys
3535 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3536 * lpcchMaxClass [O] Buffer for longest class string length
3537 * lpcValues [O] Buffer for number of value entries
3538 * lpcchMaxValueName [O] Buffer for longest value name length
3539 * lpccbMaxValueData [O] Buffer for longest value data length
3540 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3542 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3543 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3544 * lpcchClass is NULL
3545 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3546 * (it's hard to test validity, so test !NULL instead)
3548 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3549 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3550 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3551 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3552 LPDWORD lpcchMaxValueName,
3553 LPDWORD lpccbMaxValueData,
3554 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3556 LPKEYSTRUCT lpkey,lpxkey;
3557 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3560 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3561 lpkey = lookup_hkey(hkey);
3563 return ERROR_INVALID_HANDLE;
3565 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3566 return ERROR_INVALID_PARAMETER;
3568 /* either lpcchClass is valid or this is win95 and lpcchClass
3571 DWORD classLen = lstrlenW(lpkey->class);
3573 if (lpcchClass && classLen+1>*lpcchClass) {
3574 *lpcchClass=classLen+1;
3575 return ERROR_MORE_DATA;
3578 *lpcchClass=classLen;
3579 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3587 *lpcchClass = lstrlenW(lpkey->class);
3589 lpxkey=lpkey->nextsub;
3590 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3593 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3594 maxsubkey=lstrlenW(lpxkey->keyname);
3595 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3596 maxclass=lstrlenW(lpxkey->class);
3597 lpxkey=lpxkey->next;
3599 for (i=0;i<lpkey->nrofvalues;i++) {
3600 LPKEYVALUE val=lpkey->values+i;
3602 if (val->name && lstrlenW(val->name)>maxvname)
3603 maxvname=lstrlenW(val->name);
3604 if (val->len>maxvdata)
3607 if (!maxclass) maxclass = 1;
3608 if (!maxvname) maxvname = 1;
3610 *lpcValues = lpkey->nrofvalues;
3612 *lpcSubKeys = nrofkeys;
3614 *lpcchMaxSubkey = maxsubkey;
3616 *lpcchMaxClass = maxclass;
3617 if (lpcchMaxValueName)
3618 *lpcchMaxValueName= maxvname;
3619 if (lpccbMaxValueData)
3620 *lpccbMaxValueData= maxvdata;
3621 return ERROR_SUCCESS;
3625 /******************************************************************************
3626 * RegQueryInfoKey32A [ADVAPI32.152]
3628 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3629 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3630 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3631 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3632 LPDWORD lpccbMaxValueData,
3633 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3635 LPWSTR lpszClassW = NULL;
3638 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3641 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3642 } else if (VERSION_GetVersion() == WIN95) {
3643 /* win95 allows lpcchClass to be null */
3644 /* we don't know how big lpszClass is, would
3645 MAX_PATHNAME_LEN be the correct default? */
3646 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3651 ret=RegQueryInfoKeyW(
3662 lpcbSecurityDescriptor,
3665 if (ret==ERROR_SUCCESS && lpszClass)
3666 lstrcpyWtoA(lpszClass,lpszClassW);
3673 /******************************************************************************
3674 * RegConnectRegistry32W [ADVAPI32.128]
3677 * lpMachineName [I] Address of name of remote computer
3678 * hHey [I] Predefined registry handle
3679 * phkResult [I] Address of buffer for remote registry handle
3681 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3684 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3686 if (!lpMachineName || !*lpMachineName) {
3687 /* Use the local machine name */
3688 return RegOpenKey16( hKey, "", phkResult );
3691 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3692 return ERROR_BAD_NETPATH;
3696 /******************************************************************************
3697 * RegConnectRegistry32A [ADVAPI32.127]
3699 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3702 LPWSTR machineW = strdupA2W(machine);
3703 ret = RegConnectRegistryW( machineW, hkey, reskey );
3709 /******************************************************************************
3710 * RegGetKeySecurity [ADVAPI32.144]
3711 * Retrieves a copy of security descriptor protecting the registry key
3714 * hkey [I] Open handle of key to set
3715 * SecurityInformation [I] Descriptor contents
3716 * pSecurityDescriptor [O] Address of descriptor for key
3717 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3720 * Success: ERROR_SUCCESS
3721 * Failure: Error code
3723 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3724 SECURITY_INFORMATION SecurityInformation,
3725 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3726 LPDWORD lpcbSecurityDescriptor )
3730 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3731 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3733 lpkey = lookup_hkey( hkey );
3735 return ERROR_INVALID_HANDLE;
3737 /* FIXME: Check for valid SecurityInformation values */
3739 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3740 return ERROR_INSUFFICIENT_BUFFER;
3742 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3743 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3745 return ERROR_SUCCESS;
3749 /******************************************************************************
3750 * RegLoadKey32W [ADVAPI32.???]
3753 * hkey [I] Handle of open key
3754 * lpszSubKey [I] Address of name of subkey
3755 * lpszFile [I] Address of filename for registry information
3757 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3760 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3762 /* Do this check before the hkey check */
3763 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3764 return ERROR_INVALID_PARAMETER;
3766 lpkey = lookup_hkey( hkey );
3768 return ERROR_INVALID_HANDLE;
3770 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3771 debugstr_w(lpszFile));
3773 return ERROR_SUCCESS;
3777 /******************************************************************************
3778 * RegLoadKey32A [ADVAPI32.???]
3780 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3783 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3784 LPWSTR lpszFileW = strdupA2W(lpszFile);
3785 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3786 if(lpszFileW) free(lpszFileW);
3787 if(lpszSubKeyW) free(lpszSubKeyW);
3792 /******************************************************************************
3793 * RegNotifyChangeKeyValue [ADVAPI32.???]
3796 * hkey [I] Handle of key to watch
3797 * fWatchSubTree [I] Flag for subkey notification
3798 * fdwNotifyFilter [I] Changes to be reported
3799 * hEvent [I] Handle of signaled event
3800 * fAsync [I] Flag for asynchronous reporting
3802 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3803 DWORD fdwNotifyFilter, HANDLE hEvent,
3807 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3810 lpkey = lookup_hkey( hkey );
3812 return ERROR_INVALID_HANDLE;
3814 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3817 return ERROR_SUCCESS;
3821 /******************************************************************************
3822 * RegUnLoadKey32W [ADVAPI32.173]
3825 * hkey [I] Handle of open key
3826 * lpSubKey [I] Address of name of subkey to unload
3828 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3830 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3831 return ERROR_SUCCESS;
3835 /******************************************************************************
3836 * RegUnLoadKey32A [ADVAPI32.172]
3838 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3841 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3842 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3843 if(lpSubKeyW) free(lpSubKeyW);
3848 /******************************************************************************
3849 * RegSetKeySecurity [ADVAPI32.167]
3852 * hkey [I] Open handle of key to set
3853 * SecurityInfo [I] Descriptor contents
3854 * pSecurityDesc [I] Address of descriptor for key
3856 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3857 PSECURITY_DESCRIPTOR pSecurityDesc )
3861 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3863 /* It seems to perform this check before the hkey check */
3864 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3865 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3866 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3867 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3870 return ERROR_INVALID_PARAMETER;
3873 return ERROR_INVALID_PARAMETER;
3875 lpkey = lookup_hkey( hkey );
3877 return ERROR_INVALID_HANDLE;
3879 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3881 return ERROR_SUCCESS;
3885 /******************************************************************************
3886 * RegSaveKey32W [ADVAPI32.166]
3889 * hkey [I] Handle of key where save begins
3890 * lpFile [I] Address of filename to save to
3891 * sa [I] Address of security structure
3893 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3894 LPSECURITY_ATTRIBUTES sa )
3898 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3900 /* It appears to do this check before the hkey check */
3901 if (!lpFile || !*lpFile)
3902 return ERROR_INVALID_PARAMETER;
3904 lpkey = lookup_hkey( hkey );
3906 return ERROR_INVALID_HANDLE;
3908 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3910 return ERROR_SUCCESS;
3914 /******************************************************************************
3915 * RegSaveKey32A [ADVAPI32.165]
3917 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3918 LPSECURITY_ATTRIBUTES sa )
3921 LPWSTR lpFileW = strdupA2W(lpFile);
3922 ret = RegSaveKeyW( hkey, lpFileW, sa );
3928 /******************************************************************************
3929 * RegRestoreKey32W [ADVAPI32.164]
3932 * hkey [I] Handle of key where restore begins
3933 * lpFile [I] Address of filename containing saved tree
3934 * dwFlags [I] Optional flags
3936 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3940 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3942 /* It seems to do this check before the hkey check */
3943 if (!lpFile || !*lpFile)
3944 return ERROR_INVALID_PARAMETER;
3946 lpkey = lookup_hkey( hkey );
3948 return ERROR_INVALID_HANDLE;
3950 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3952 /* Check for file existence */
3954 return ERROR_SUCCESS;
3958 /******************************************************************************
3959 * RegRestoreKey32A [ADVAPI32.163]
3961 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3964 LPWSTR lpFileW = strdupA2W(lpFile);
3965 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3966 if(lpFileW) free(lpFileW);
3971 /******************************************************************************
3972 * RegReplaceKey32W [ADVAPI32.162]
3975 * hkey [I] Handle of open key
3976 * lpSubKey [I] Address of name of subkey
3977 * lpNewFile [I] Address of filename for file with new data
3978 * lpOldFile [I] Address of filename for backup file
3980 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3985 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3986 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3988 lpkey = lookup_hkey( hkey );
3990 return ERROR_INVALID_HANDLE;
3992 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3993 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3995 return ERROR_SUCCESS;
3999 /******************************************************************************
4000 * RegReplaceKey32A [ADVAPI32.161]
4002 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4006 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4007 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4008 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4009 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );