4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
7 * December 21, 1997 - Kevin Cozens
8 * Fixed bugs in the _w95_loadreg() function. Added extra information
9 * regarding the format of the Windows '95 registry files.
12 * When changing this file, please re-run the regtest program to ensure
13 * the conditions are handled properly.
18 * Time for RegEnumKey*, RegQueryInfoKey*
26 #include <sys/errno.h>
27 #include <sys/types.h>
28 #include <sys/fcntl.h>
41 #include "winversion.h"
43 static void REGISTRY_Init(void);
44 /* FIXME: following defines should be configured global ... */
46 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
47 #define WINE_PREFIX "/.wine"
48 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
49 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
51 /* relative in ~user/.wine/ : */
52 #define SAVE_CURRENT_USER "user.reg"
53 #define SAVE_LOCAL_MACHINE "system.reg"
55 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
56 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
58 /* one value of a key */
59 typedef struct tagKEYVALUE
61 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
62 DWORD type; /* type of value */
63 DWORD len; /* length of data in BYTEs */
64 DWORD lastmodified; /* time of seconds since 1.1.1970 */
65 LPBYTE data; /* content, may be strings, binaries, etc. */
66 } KEYVALUE,*LPKEYVALUE;
69 typedef struct tagKEYSTRUCT
71 LPWSTR keyname; /* name of THIS key (UNICODE) */
72 DWORD flags; /* flags. */
75 DWORD nrofvalues; /* nr of values in THIS key */
76 LPKEYVALUE values; /* values in THIS key */
77 /* key management pointers */
78 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
79 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
80 } KEYSTRUCT, *LPKEYSTRUCT;
83 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
84 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
85 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
86 static KEYSTRUCT *key_users=NULL; /* all users? */
88 /* dynamic, not saved */
89 static KEYSTRUCT *key_performance_data=NULL;
90 static KEYSTRUCT *key_current_config=NULL;
91 static KEYSTRUCT *key_dyn_data=NULL;
93 /* what valuetypes do we need to convert? */
94 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
97 static struct openhandle {
102 static int nrofopenhandles=0;
103 /* Starts after 1 because 0,1 are reserved for Win16 */
104 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
105 HKEYs for remote registry access */
106 static int currenthandle=2;
111 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
112 * If so, can we remove them?
114 * No, the memory handling functions are called very often in here,
115 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
116 * loading 100 times slower. -MM
118 static LPWSTR strdupA2W(LPCSTR src)
121 LPWSTR dest=xmalloc(2*strlen(src)+2);
122 lstrcpyAtoW(dest,src);
128 static LPWSTR strdupW(LPCWSTR a) {
133 len=sizeof(WCHAR)*(lstrlen32W(a)+1);
134 b=(LPWSTR)xmalloc(len);
141 LPWSTR strcvtA2W(LPCSTR src, int nchars)
144 LPWSTR dest = xmalloc (2 * nchars + 2);
146 lstrcpynAtoW(dest,src,nchars+1);
151 * we need to convert A to W with '\0' in strings (MULTI_SZ)
154 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT32 n )
157 TRACE(reg,"\"%s\" %i\n",src, n);
159 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
163 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT32 n )
166 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
168 while (n-- > 0) *p++ = (CHAR)*src++;
173 static void debug_print_value (LPBYTE lpbData, DWORD type, DWORD len)
174 { if (TRACE_ON(reg) && lpbData)
177 TRACE(reg," Data(sz)=%s\n",debugstr_w((LPCWSTR)lpbData));
181 TRACE(reg," Data(dword)=0x%08lx\n",(DWORD)*lpbData);
186 LPCWSTR ptr = (LPCWSTR)lpbData;
188 { TRACE(reg, " MULTI_SZ(%i=%s)\n", i, debugstr_w(ptr));
189 ptr += lstrlen32W(ptr)+1;
195 { char szTemp[100]; /* 3*32 + 3 + 1 */
197 for ( i = 0; i < len ; i++)
198 { sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
200 { sprintf (&(szTemp[i*3+3]),"...");
204 TRACE(reg," Data(raw)=(%s)\n", szTemp);
209 FIXME(reg, " Unknown data type %ld\n", type);
216 /******************************************************************************
217 * is_standard_hkey [Internal]
218 * Determines if a hkey is a standard key
220 static BOOL32 is_standard_hkey( HKEY hkey )
225 case HKEY_CLASSES_ROOT:
226 case HKEY_CURRENT_CONFIG:
227 case HKEY_CURRENT_USER:
228 case HKEY_LOCAL_MACHINE:
230 case HKEY_PERFORMANCE_DATA:
238 /******************************************************************************
239 * add_handle [Internal]
241 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
245 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
246 /* Check for duplicates */
247 for (i=0;i<nrofopenhandles;i++) {
248 if (openhandles[i].lpkey==lpkey) {
249 /* This is not really an error - the user is allowed to create
250 two (or more) handles to the same key */
251 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
253 if (openhandles[i].hkey==hkey) {
254 WARN(reg, "Adding handle %x twice\n",hkey);
257 openhandles=xrealloc( openhandles,
258 sizeof(struct openhandle)*(nrofopenhandles+1));
260 openhandles[i].lpkey = lpkey;
261 openhandles[i].hkey = hkey;
262 openhandles[i].accessmask = accessmask;
267 /******************************************************************************
268 * get_handle [Internal]
271 * Success: Pointer to key
274 static LPKEYSTRUCT get_handle( HKEY hkey )
278 for (i=0; i<nrofopenhandles; i++)
279 if (openhandles[i].hkey == hkey)
280 return openhandles[i].lpkey;
281 WARN(reg, "Could not find handle 0x%x\n",hkey);
286 /******************************************************************************
287 * remove_handle [Internal]
290 * hkey [I] Handle of key to remove
293 * Success: ERROR_SUCCESS
294 * Failure: ERROR_INVALID_HANDLE
296 static DWORD remove_handle( HKEY hkey )
300 for (i=0;i<nrofopenhandles;i++)
301 if (openhandles[i].hkey==hkey)
304 if (i == nrofopenhandles) {
305 WARN(reg, "Could not find handle 0x%x\n",hkey);
306 return ERROR_INVALID_HANDLE;
309 memcpy( openhandles+i,
311 sizeof(struct openhandle)*(nrofopenhandles-i-1)
313 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
315 return ERROR_SUCCESS;
318 /******************************************************************************
319 * lookup_hkey [Internal]
321 * Just as the name says. Creates the root keys on demand, so we can call the
322 * Reg* functions at any time.
325 * Success: Pointer to key structure
328 #define ADD_ROOT_KEY(xx) \
329 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
330 memset(xx,'\0',sizeof(KEYSTRUCT));\
331 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
333 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
336 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
337 * some programs. Do not remove those cases. -MM
341 case HKEY_CLASSES_ROOT: {
342 if (!key_classes_root) {
345 /* calls lookup_hkey recursively, TWICE */
346 if (RegCreateKey16(HKEY_LOCAL_MACHINE,"SOFTWARE\\Classes",&cl_r_hkey)!=ERROR_SUCCESS) {
347 ERR(reg,"Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
350 key_classes_root = lookup_hkey(cl_r_hkey);
352 return key_classes_root;
354 case HKEY_CURRENT_USER:
355 if (!key_current_user) {
359 pwd=getpwuid(getuid());
360 /* calls lookup_hkey recursively, TWICE */
361 if (pwd && pwd->pw_name) {
362 if (RegCreateKey16(HKEY_USERS,pwd->pw_name,&c_u_hkey)!=ERROR_SUCCESS) {
363 ERR(reg,"Could not create HU\\%s. This is impossible.\n",pwd->pw_name);
366 key_current_user = lookup_hkey(c_u_hkey);
368 /* nothing found, use standalone */
369 ADD_ROOT_KEY(key_current_user);
372 return key_current_user;
373 case HKEY_LOCAL_MACHINE:
374 if (!key_local_machine) {
375 ADD_ROOT_KEY(key_local_machine);
378 return key_local_machine;
381 ADD_ROOT_KEY(key_users);
384 case HKEY_PERFORMANCE_DATA:
385 if (!key_performance_data) {
386 ADD_ROOT_KEY(key_performance_data);
388 return key_performance_data;
391 ADD_ROOT_KEY(key_dyn_data);
394 case HKEY_CURRENT_CONFIG:
395 if (!key_current_config) {
396 ADD_ROOT_KEY(key_current_config);
398 return key_current_config;
400 return get_handle(hkey);
405 /* so we don't accidently access them ... */
406 #define key_current_config NULL NULL
407 #define key_current_user NULL NULL
408 #define key_users NULL NULL
409 #define key_local_machine NULL NULL
410 #define key_classes_root NULL NULL
411 #define key_dyn_data NULL NULL
412 #define key_performance_data NULL NULL
414 /******************************************************************************
415 * split_keypath [Internal]
416 * splits the unicode string 'wp' into an array of strings.
417 * the array is allocated by this function.
418 * Free the array using FREE_KEY_PATH
421 * wp [I] String to split up
422 * wpv [O] Array of pointers to strings
423 * wpc [O] Number of components
425 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
430 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
432 ws = HEAP_strdupW( SystemHeap, 0, wp );
434 /* We know we have at least one substring */
437 /* Replace each backslash with NULL, and increment the count */
438 for (i=0;ws[i];i++) {
447 /* Allocate the space for the array of pointers, leaving room for the
449 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
452 /* Assign each pointer to the appropriate character in the string */
457 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
462 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
467 /******************************************************************************
468 * REGISTRY_Init [Internal]
469 * Registry initialisation, allocates some default keys.
471 static void REGISTRY_Init(void) {
475 TRACE(reg,"(void)\n");
477 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
480 /* This was an Open, but since it is called before the real registries
481 are loaded, it was changed to a Create - MTB 980507*/
482 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
483 RegSetValueEx32A(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
486 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
490 * string RegisteredOwner
491 * string RegisteredOrganization
494 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
499 if (-1!=gethostname(buf,200)) {
500 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
501 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
507 /************************ SAVE Registry Function ****************************/
509 #define REGISTRY_SAVE_VERSION 0x00000001
511 /* Registry saveformat:
512 * If you change it, increase above number by 1, which will flush
513 * old registry database files.
516 * "WINE REGISTRY Version %d"
520 * valuename=lastmodified,type,data
524 * keyname,valuename,stringdata:
525 * the usual ascii characters from 0x00-0xff (well, not 0x00)
526 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
527 * ( "=\\\t" escaped in \uXXXX form.)
531 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
533 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
534 * SaveOnlyUpdatedKeys=yes
537 /******************************************************************************
538 * _save_check_tainted [Internal]
540 static int _save_check_tainted( LPKEYSTRUCT lpkey )
546 if (lpkey->flags & REG_OPTION_TAINTED)
551 if (_save_check_tainted(lpkey->nextsub)) {
552 lpkey->flags |= REG_OPTION_TAINTED;
560 /******************************************************************************
561 * _save_USTRING [Internal]
563 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
577 if (escapeeq && *s=='=')
580 fputc(*s,F); /* if \\ then put it twice. */
582 fprintf(F,"\\u%04x",*((unsigned short*)s));
589 /******************************************************************************
590 * _savesubkey [Internal]
593 * REG_MULTI_SZ is handled as binary (like in win95) (js)
595 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
602 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
603 (all || (lpxkey->flags & REG_OPTION_TAINTED))
605 for (tabs=level;tabs--;)
607 _save_USTRING(F,lpxkey->keyname,1);
609 for (i=0;i<lpxkey->nrofvalues;i++) {
610 LPKEYVALUE val=lpxkey->values+i;
612 for (tabs=level+1;tabs--;)
614 _save_USTRING(F,val->name,0);
616 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
617 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
618 _save_USTRING(F,(LPWSTR)val->data,0);
620 for (j=0;j<val->len;j++)
621 fprintf(F,"%02x",*((unsigned char*)val->data+j));
624 /* descend recursively */
625 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
634 /******************************************************************************
635 * _savesubreg [Internal]
637 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
639 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
640 _save_check_tainted(lpkey->nextsub);
641 return _savesubkey(F,lpkey->nextsub,0,all);
645 /******************************************************************************
646 * _savereg [Internal]
648 static BOOL32 _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
654 WARN(reg,"Couldn't open %s for writing: %s\n",
659 if (!_savesubreg(F,lpkey,all)) {
662 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
670 /******************************************************************************
671 * SHELL_SaveRegistry [Internal]
673 void SHELL_SaveRegistry( void )
681 TRACE(reg,"(void)\n");
684 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS) {
690 if ( (ERROR_SUCCESS!=RegQueryValueEx32A(
702 if (lstrcmpi32A(buf,"yes"))
704 pwd=getpwuid(getuid());
705 if (pwd!=NULL && pwd->pw_dir!=NULL)
709 fn=(char*)xmalloc( strlen(pwd->pw_dir) + strlen(WINE_PREFIX) +
710 strlen(SAVE_CURRENT_USER) + 2 );
711 strcpy(fn,pwd->pw_dir);
712 strcat(fn,WINE_PREFIX);
713 /* create the directory. don't care about errorcodes. */
714 mkdir(fn,0755); /* drwxr-xr-x */
715 strcat(fn,"/"SAVE_CURRENT_USER);
716 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
717 strcpy(tmp,fn);strcat(tmp,".tmp");
718 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
719 if (-1==rename(tmp,fn)) {
720 perror("rename tmp registry");
726 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
727 strcpy(fn,pwd->pw_dir);
728 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
729 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
730 strcpy(tmp,fn);strcat(tmp,".tmp");
731 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
732 if (-1==rename(tmp,fn)) {
733 perror("rename tmp registry");
740 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
744 /************************ LOAD Registry Function ****************************/
748 /******************************************************************************
749 * _find_or_add_key [Internal]
751 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
753 LPKEYSTRUCT lpxkey,*lplpkey;
755 if ((!keyname) || (keyname[0]==0)) {
759 lplpkey= &(lpkey->nextsub);
762 if ( (lpxkey->keyname[0]==keyname[0]) &&
763 !lstrcmpi32W(lpxkey->keyname,keyname)
766 lplpkey = &(lpxkey->next);
770 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
772 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
773 lpxkey->keyname = keyname;
779 /******************************************************************************
780 * _find_or_add_value [Internal]
782 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
783 LPBYTE data, DWORD len, DWORD lastmodified )
788 if (name && !*name) {/* empty string equals default (NULL) value */
793 for (i=0;i<lpkey->nrofvalues;i++) {
799 if ( val->name!=NULL &&
800 val->name[0]==name[0] &&
801 !lstrcmpi32W(val->name,name)
806 if (i==lpkey->nrofvalues) {
807 lpkey->values = xrealloc(
809 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
812 memset(val,'\0',sizeof(KEYVALUE));
818 if (val->lastmodified<lastmodified) {
819 val->lastmodified=lastmodified;
830 /******************************************************************************
831 * _wine_read_line [Internal]
833 * reads a line including dynamically enlarging the readbuffer and throwing
836 static int _wine_read_line( FILE *F, char **buf, int *len )
846 s=fgets(curread,mylen,F);
849 if (NULL==(s=strchr(curread,'\n'))) {
850 /* buffer wasn't large enough */
851 curoff = strlen(*buf);
852 *buf = xrealloc(*buf,*len*2);
853 curread = *buf + curoff;
854 mylen = *len; /* we filled up the buffer and
855 * got new '*len' bytes to fill
863 /* throw away comments */
864 if (**buf=='#' || **buf==';') {
869 if (s) /* got end of line */
876 /******************************************************************************
877 * _wine_read_USTRING [Internal]
879 * converts a char* into a UNICODE string (up to a special char)
880 * and returns the position exactly after that string
882 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
887 /* read up to "=" or "\0" or "\n" */
890 /* empty string is the win3.1 default value(NULL)*/
894 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
896 while (*s && (*s!='\n') && (*s!='=')) {
898 *ws++=*((unsigned char*)s++);
902 /* Dangling \ ... may only happen if a registry
903 * write was short. FIXME: What do to?
913 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
921 memcpy(xbuf,s,4);xbuf[4]='\0';
922 if (!sscanf(xbuf,"%x",&wc))
923 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
925 *ws++ =(unsigned short)wc;
932 *str = strdupW(*str);
940 /******************************************************************************
941 * _wine_loadsubkey [Internal]
944 * It seems like this is returning a boolean. Should it?
950 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
951 int *buflen, DWORD optflag )
958 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
961 lpkey->flags |= optflag;
963 /* Good. We already got a line here ... so parse it */
973 WARN(reg,"Got a subhierarchy without resp. key?\n");
976 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
980 /* let the caller handle this line */
981 if (i<level || **buf=='\0')
984 /* it can be: a value or a keyname. Parse the name first */
985 s=_wine_read_USTRING(s,&name);
987 /* switch() default: hack to avoid gotos */
991 lpxkey=_find_or_add_key(lpkey,name);
994 int len,lastmodified,type;
997 WARN(reg,"Unexpected character: %c\n",*s);
1001 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1002 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1006 s=strchr(s,',');s++;
1007 s=strchr(s,',');s++;
1008 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1009 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1011 len = lstrlen32W((LPWSTR)data)*2+2;
1016 data = (LPBYTE)xmalloc(len+1);
1017 for (i=0;i<len;i++) {
1019 if (*s>='0' && *s<='9')
1020 data[i]=(*s-'0')<<4;
1021 if (*s>='a' && *s<='f')
1022 data[i]=(*s-'a'+'\xa')<<4;
1023 if (*s>='A' && *s<='F')
1024 data[i]=(*s-'A'+'\xa')<<4;
1026 if (*s>='0' && *s<='9')
1028 if (*s>='a' && *s<='f')
1029 data[i]|=*s-'a'+'\xa';
1030 if (*s>='A' && *s<='F')
1031 data[i]|=*s-'A'+'\xa';
1035 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1038 /* read the next line */
1039 if (!_wine_read_line(F,buf,buflen))
1046 /******************************************************************************
1047 * _wine_loadsubreg [Internal]
1049 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1055 buf=xmalloc(10);buflen=10;
1056 if (!_wine_read_line(F,&buf,&buflen)) {
1060 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1064 if (ver!=REGISTRY_SAVE_VERSION) {
1065 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1069 if (!_wine_read_line(F,&buf,&buflen)) {
1073 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1082 /******************************************************************************
1083 * _wine_loadreg [Internal]
1085 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1089 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1093 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1096 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1105 /******************************************************************************
1106 * _copy_registry [Internal]
1108 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1116 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1118 for (j=0;j<from->nrofvalues;j++) {
1122 valfrom = from->values+j;
1124 if (name) name=strdupW(name);
1125 data=(LPBYTE)xmalloc(valfrom->len);
1126 memcpy(data,valfrom->data,valfrom->len);
1134 valfrom->lastmodified
1137 _copy_registry(from,lpxkey);
1143 /* WINDOWS 95 REGISTRY LOADER */
1145 * Structure of a win95 registry database.
1147 * 0 : "CREG" - magic
1149 * 8 : DWORD offset_of_RGDB_part
1150 * 0C..0F: ? (someone fill in please)
1151 * 10: WORD number of RGDB blocks
1153 * 14: WORD always 0000?
1154 * 16: WORD always 0001?
1155 * 18..1F: ? (someone fill in please)
1159 * 0 : "RGKN" - magic
1160 * 4 : DWORD offset to first RGDB section
1161 * 8 : DWORD offset to the root record
1162 * C..0x1B: ? (fill in)
1163 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1165 * Disk Key Entry Structure:
1166 * 00: DWORD - Free entry indicator(?)
1167 * 04: DWORD - Hash = sum of bytes of keyname
1168 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1169 * 0C: DWORD - disk address of PreviousLevel Key.
1170 * 10: DWORD - disk address of Next Sublevel Key.
1171 * 14: DWORD - disk address of Next Key (on same level).
1172 * DKEP>18: WORD - Nr, Low Significant part.
1173 * 1A: WORD - Nr, High Significant part.
1175 * The disk address always points to the nr part of the previous key entry
1176 * of the referenced key. Don't ask me why, or even if I got this correct
1177 * from staring at 1kg of hexdumps. (DKEP)
1179 * The High significant part of the structure seems to equal the number
1180 * of the RGDB section. The low significant part is a unique ID within
1183 * There are two minor corrections to the position of that structure.
1184 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1185 * the DKE reread from there.
1186 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1187 * CPS - I have not experienced the above phenomenon in my registry files
1190 * 00: "RGDB" - magic
1191 * 04: DWORD offset to next RGDB section
1193 * 0C: WORD always 000d?
1194 * 0E: WORD RGDB block number
1195 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1197 * 20.....: disk keys
1200 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1201 * 08: WORD nrLS - low significant part of NR
1202 * 0A: WORD nrHS - high significant part of NR
1203 * 0C: DWORD bytesused - bytes used in this structure.
1204 * 10: WORD name_len - length of name in bytes. without \0
1205 * 12: WORD nr_of_values - number of values.
1206 * 14: char name[name_len] - name string. No \0.
1207 * 14+name_len: disk values
1208 * nextkeyoffset: ... next disk key
1211 * 00: DWORD type - value type (hmm, could be WORD too)
1212 * 04: DWORD - unknown, usually 0
1213 * 08: WORD namelen - length of Name. 0 means name=NULL
1214 * 0C: WORD datalen - length of Data.
1215 * 10: char name[namelen] - name, no \0
1216 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1217 * 10+namelen+datalen: next values or disk key
1219 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1220 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1221 * structure) and reading another RGDB_section.
1222 * repeat until end of file.
1224 * An interesting relationship exists in RGDB_section. The value at offset
1225 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1226 * idea at the moment what this means. (Kevin Cozens)
1228 * FIXME: this description needs some serious help, yes.
1231 struct _w95keyvalue {
1233 unsigned short datalen;
1235 unsigned char *data;
1243 struct _w95keyvalue *values;
1244 struct _w95key *prevlvl;
1245 struct _w95key *nextsub;
1246 struct _w95key *next;
1260 /******************************************************************************
1261 * _w95_processKey [Internal]
1263 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1264 int nrLS, int nrMS, struct _w95_info *info )
1267 /* Disk Key Header structure (RGDB part) */
1269 unsigned long nextkeyoff;
1270 unsigned short nrLS;
1271 unsigned short nrMS;
1272 unsigned long bytesused;
1273 unsigned short keynamelen;
1274 unsigned short values;
1277 /* disk key values or nothing */
1279 /* Disk Key Value structure */
1283 unsigned short valnamelen;
1284 unsigned short valdatalen;
1285 /* valname, valdata */
1291 char *rgdbdata = info->rgdbbuffer;
1292 int nbytes = info->rgdbsize;
1293 char *curdata = rgdbdata;
1294 char *end = rgdbdata + nbytes;
1296 char *next = rgdbdata;
1302 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1304 memcpy(&off_next_rgdb,curdata+4,4);
1305 next = curdata + off_next_rgdb;
1306 nrgdb = (int) *((short *)curdata + 7);
1308 } while (nrgdb != nrMS && (next < end));
1310 /* curdata now points to the start of the right RGDB section */
1313 #define XREAD(whereto,len) \
1314 if ((curdata + len) <end) {\
1315 memcpy(whereto,curdata,len);\
1320 while (curdata < next) {
1321 struct dkh *xdkh = (struct dkh*)curdata;
1323 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1324 if (xdkh->nrLS == nrLS) {
1325 memcpy(&dkh,xdkh,sizeof(dkh));
1326 curdata += sizeof(dkh);
1329 curdata += xdkh->nextkeyoff;
1332 if (dkh.nrLS != nrLS) return (NULL);
1334 if (nrgdb != dkh.nrMS)
1337 assert((dkh.keynamelen<2) || curdata[0]);
1338 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1339 curdata += dkh.keynamelen;
1341 for (i=0;i< dkh.values; i++) {
1347 XREAD(&dkv,sizeof(dkv));
1349 name = strcvtA2W(curdata, dkv.valnamelen);
1350 curdata += dkv.valnamelen;
1352 if ((1 << dkv.type) & UNICONVMASK) {
1353 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1354 len = 2*(dkv.valdatalen + 1);
1356 /* I don't think we want to NULL terminate all data */
1357 data = xmalloc(dkv.valdatalen);
1358 memcpy (data, curdata, dkv.valdatalen);
1359 len = dkv.valdatalen;
1362 curdata += dkv.valdatalen;
1376 /******************************************************************************
1377 * _w95_walkrgkn [Internal]
1379 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1380 struct _w95_info *info )
1383 /* Disk Key Entry structure (RGKN part) */
1387 unsigned long x3;/*usually 0xFFFFFFFF */
1388 unsigned long prevlvl;
1389 unsigned long nextsub;
1391 unsigned short nrLS;
1392 unsigned short nrMS;
1393 } *dke = (struct dke *)off;
1397 dke = (struct dke *) ((char *)info->rgknbuffer);
1400 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1401 /* XXX <-- This is a hack*/
1406 if (dke->nextsub != -1 &&
1407 ((dke->nextsub - 0x20) < info->rgknsize)
1408 && (dke->nextsub > 0x20)) {
1410 _w95_walkrgkn(lpxkey,
1411 info->rgknbuffer + dke->nextsub - 0x20,
1415 if (dke->next != -1 &&
1416 ((dke->next - 0x20) < info->rgknsize) &&
1417 (dke->next > 0x20)) {
1418 _w95_walkrgkn(prevkey,
1419 info->rgknbuffer + dke->next - 0x20,
1427 /******************************************************************************
1428 * _w95_loadreg [Internal]
1430 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1434 unsigned long where,version,rgdbsection,end;
1435 struct _w95_info info;
1437 BY_HANDLE_FILE_INFORMATION hfdinfo;
1439 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1440 hfd=OpenFile32(fn,&ofs,OF_READ);
1441 if (hfd==HFILE_ERROR32)
1444 if (4!=_lread32(hfd,magic,4))
1446 if (strcmp(magic,"CREG")) {
1447 WARN(reg,"%s is not a w95 registry.\n",fn);
1450 if (4!=_lread32(hfd,&version,4))
1452 if (4!=_lread32(hfd,&rgdbsection,4))
1454 if (-1==_llseek32(hfd,0x20,SEEK_SET))
1456 if (4!=_lread32(hfd,magic,4))
1458 if (strcmp(magic,"RGKN")) {
1459 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1463 /* STEP 1: Keylink structures */
1464 if (-1==_llseek32(hfd,0x40,SEEK_SET))
1469 info.rgknsize = end - where;
1470 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1471 if (info.rgknsize != _lread32(hfd,info.rgknbuffer,info.rgknsize))
1474 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1477 end = hfdinfo.nFileSizeLow;
1478 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1480 if (-1==_llseek32(hfd,rgdbsection,SEEK_SET))
1483 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1484 info.rgdbsize = end - rgdbsection;
1486 if (info.rgdbsize !=_lread32(hfd,info.rgdbbuffer,info.rgdbsize))
1490 _w95_walkrgkn(lpkey, NULL, &info);
1492 free (info.rgdbbuffer);
1493 free (info.rgknbuffer);
1497 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1500 reghack - windows 3.11 registry data format demo program.
1502 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1503 a combined hash table and tree description, and finally a text table.
1505 The header is obvious from the struct header. The taboff1 and taboff2
1506 fields are always 0x20, and their usage is unknown.
1508 The 8-byte entry table has various entry types.
1510 tabent[0] is a root index. The second word has the index of the root of
1512 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1513 the index of the key/value that has that hash. Data with the same
1514 hash value are on a circular list. The other three words in the
1515 hash entry are always zero.
1516 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1517 entry: dirent and keyent/valent. They are identified by context.
1518 tabent[freeidx] is the first free entry. The first word in a free entry
1519 is the index of the next free entry. The last has 0 as a link.
1520 The other three words in the free list are probably irrelevant.
1522 Entries in text table are preceeded by a word at offset-2. This word
1523 has the value (2*index)+1, where index is the referring keyent/valent
1524 entry in the table. I have no suggestion for the 2* and the +1.
1525 Following the word, there are N bytes of data, as per the keyent/valent
1526 entry length. The offset of the keyent/valent entry is from the start
1527 of the text table to the first data byte.
1529 This information is not available from Microsoft. The data format is
1530 deduced from the reg.dat file by me. Mistakes may
1531 have been made. I claim no rights and give no guarantees for this program.
1533 Tor Sjøwall, tor@sn.no
1536 /* reg.dat header format */
1537 struct _w31_header {
1538 char cookie[8]; /* 'SHCC3.10' */
1539 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1540 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1541 unsigned long tabcnt; /* number of entries in index table */
1542 unsigned long textoff; /* offset of text part */
1543 unsigned long textsize; /* byte size of text part */
1544 unsigned short hashsize; /* hash size */
1545 unsigned short freeidx; /* free index */
1548 /* generic format of table entries */
1549 struct _w31_tabent {
1550 unsigned short w0, w1, w2, w3;
1553 /* directory tabent: */
1554 struct _w31_dirent {
1555 unsigned short sibling_idx; /* table index of sibling dirent */
1556 unsigned short child_idx; /* table index of child dirent */
1557 unsigned short key_idx; /* table index of key keyent */
1558 unsigned short value_idx; /* table index of value valent */
1562 struct _w31_keyent {
1563 unsigned short hash_idx; /* hash chain index for string */
1564 unsigned short refcnt; /* reference count */
1565 unsigned short length; /* length of string */
1566 unsigned short string_off; /* offset of string in text table */
1570 struct _w31_valent {
1571 unsigned short hash_idx; /* hash chain index for string */
1572 unsigned short refcnt; /* reference count */
1573 unsigned short length; /* length of string */
1574 unsigned short string_off; /* offset of string in text table */
1577 /* recursive helper function to display a directory tree */
1579 __w31_dumptree( unsigned short idx,
1581 struct _w31_tabent *tab,
1582 struct _w31_header *head,
1584 time_t lastmodified,
1587 struct _w31_dirent *dir;
1588 struct _w31_keyent *key;
1589 struct _w31_valent *val;
1590 LPKEYSTRUCT xlpkey = NULL;
1592 static char tail[400];
1595 dir=(struct _w31_dirent*)&tab[idx];
1598 key = (struct _w31_keyent*)&tab[dir->key_idx];
1600 memcpy(tail,&txt[key->string_off],key->length);
1601 tail[key->length]='\0';
1602 /* all toplevel entries AND the entries in the
1603 * toplevel subdirectory belong to \SOFTWARE\Classes
1605 if (!level && !lstrcmp32A(tail,".classes")) {
1606 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1607 idx=dir->sibling_idx;
1610 name=strdupA2W(tail);
1612 xlpkey=_find_or_add_key(lpkey,name);
1614 /* only add if leaf node or valued node */
1615 if (dir->value_idx!=0||dir->child_idx==0) {
1616 if (dir->value_idx) {
1617 val=(struct _w31_valent*)&tab[dir->value_idx];
1618 memcpy(tail,&txt[val->string_off],val->length);
1619 tail[val->length]='\0';
1620 value=strdupA2W(tail);
1621 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlen32W(value)*2+2,lastmodified);
1625 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1627 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1628 idx=dir->sibling_idx;
1633 /******************************************************************************
1634 * _w31_loadreg [Internal]
1636 void _w31_loadreg(void) {
1638 struct _w31_header head;
1639 struct _w31_tabent *tab;
1643 BY_HANDLE_FILE_INFORMATION hfinfo;
1644 time_t lastmodified;
1647 TRACE(reg,"(void)\n");
1649 hf = OpenFile32("reg.dat",&ofs,OF_READ);
1650 if (hf==HFILE_ERROR32)
1653 /* read & dump header */
1654 if (sizeof(head)!=_lread32(hf,&head,sizeof(head))) {
1655 ERR(reg, "reg.dat is too short.\n");
1659 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1660 ERR(reg, "reg.dat has bad signature.\n");
1665 len = head.tabcnt * sizeof(struct _w31_tabent);
1666 /* read and dump index table */
1668 if (len!=_lread32(hf,tab,len)) {
1669 ERR(reg,"couldn't read %d bytes.\n",len);
1676 txt = xmalloc(head.textsize);
1677 if (-1==_llseek32(hf,head.textoff,SEEK_SET)) {
1678 ERR(reg,"couldn't seek to textblock.\n");
1684 if (head.textsize!=_lread32(hf,txt,head.textsize)) {
1685 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1692 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1693 ERR(reg,"GetFileInformationByHandle failed?.\n");
1699 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1700 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1701 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1709 /**********************************************************************************
1710 * SHELL_LoadRegistry [Internal]
1712 void SHELL_LoadRegistry( void )
1719 TRACE(reg,"(void)\n");
1721 /* Load windows 3.1 entries */
1723 /* Load windows 95 entries */
1724 _w95_loadreg("C:\\system.1st", lookup_hkey(HKEY_LOCAL_MACHINE));
1725 _w95_loadreg("system.dat", lookup_hkey(HKEY_LOCAL_MACHINE));
1726 _w95_loadreg("user.dat", lookup_hkey(HKEY_USERS));
1728 /* the global user default is loaded under HKEY_USERS\\.Default */
1729 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1730 lpkey = lookup_hkey(hkey);
1732 WARN(reg,"Could not create global user default key\n");
1733 _wine_loadreg(lpkey,SAVE_USERS_DEFAULT,0);
1735 /* HKEY_USERS\\.Default is copied to HKEY_CURRENT_USER */
1736 _copy_registry(lpkey,lookup_hkey(HKEY_CURRENT_USER));
1739 /* the global machine defaults */
1740 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),SAVE_LOCAL_MACHINE_DEFAULT,0);
1742 /* load the user saved registries */
1744 /* FIXME: use getenv("HOME") or getpwuid(getuid())->pw_dir ?? */
1746 pwd=getpwuid(getuid());
1747 if (pwd!=NULL && pwd->pw_dir!=NULL) {
1748 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
1749 strcpy(fn,pwd->pw_dir);
1750 strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
1751 _wine_loadreg(lookup_hkey(HKEY_CURRENT_USER),fn,REG_OPTION_TAINTED);
1753 fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
1754 strcpy(fn,pwd->pw_dir);
1755 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1756 _wine_loadreg(lookup_hkey(HKEY_LOCAL_MACHINE),fn,REG_OPTION_TAINTED);
1759 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
1760 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)) {
1761 DWORD junk,type,len;
1765 if (( RegQueryValueEx32A(
1772 )!=ERROR_SUCCESS) ||
1775 RegSetValueEx32A(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
1781 /********************* API FUNCTIONS ***************************************/
1785 * All functions are stubs to RegOpenKeyEx32W where all the
1789 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
1790 * RegOpenKey32W -> RegOpenKeyEx32W
1794 /******************************************************************************
1795 * RegOpenKeyEx32W [ADVAPI32.150]
1796 * Opens the specified key
1798 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
1801 * hkey [I] Handle of open key
1802 * lpszSubKey [I] Name of subkey to open
1803 * dwReserved [I] Reserved - must be zero
1804 * samDesired [I] Security access mask
1805 * retkey [O] Address of handle of open key
1808 * Success: ERROR_SUCCESS
1809 * Failure: Error code
1811 DWORD WINAPI RegOpenKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
1812 REGSAM samDesired, LPHKEY retkey )
1814 LPKEYSTRUCT lpNextKey,lpxkey;
1818 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
1821 lpNextKey = lookup_hkey( hkey );
1823 return ERROR_INVALID_HANDLE;
1825 if (!lpszSubKey || !*lpszSubKey) {
1826 /* Either NULL or pointer to empty string, so return a new handle
1827 to the original hkey */
1829 add_handle(currenthandle,lpNextKey,samDesired);
1830 *retkey=currenthandle;
1831 return ERROR_SUCCESS;
1834 if (lpszSubKey[0] == '\\') {
1835 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
1836 return ERROR_BAD_PATHNAME;
1839 split_keypath(lpszSubKey,&wps,&wpc);
1841 while ((i<wpc) && (wps[i][0]=='\0')) i++;
1845 lpxkey=lpNextKey->nextsub;
1847 if (!lstrcmpi32W(wps[i],lpxkey->keyname)) {
1850 lpxkey=lpxkey->next;
1854 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
1856 return ERROR_FILE_NOT_FOUND;
1863 add_handle(currenthandle,lpxkey,samDesired);
1864 *retkey = currenthandle;
1865 TRACE(reg," Returning %x\n", currenthandle);
1867 return ERROR_SUCCESS;
1871 /******************************************************************************
1872 * RegOpenKeyEx32A [ADVAPI32.149]
1874 DWORD WINAPI RegOpenKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
1875 REGSAM samDesired, LPHKEY retkey )
1877 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1880 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
1882 ret = RegOpenKeyEx32W( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
1888 /******************************************************************************
1889 * RegOpenKey32W [ADVAPI32.151]
1892 * hkey [I] Handle of open key
1893 * lpszSubKey [I] Address of name of subkey to open
1894 * retkey [O] Address of handle of open key
1897 * Success: ERROR_SUCCESS
1898 * Failure: Error code
1900 DWORD WINAPI RegOpenKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
1902 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
1903 return RegOpenKeyEx32W( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
1907 /******************************************************************************
1908 * RegOpenKey32A [ADVAPI32.148]
1910 DWORD WINAPI RegOpenKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1913 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
1914 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1915 ret = RegOpenKey32W( hkey, lpszSubKeyW, retkey );
1921 /******************************************************************************
1922 * RegOpenKey16 [SHELL.1] [KERNEL.217]
1924 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
1926 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
1927 return RegOpenKey32A( hkey, lpszSubKey, retkey );
1934 * All those functions convert their respective
1935 * arguments and call RegCreateKeyExW at the end.
1937 * We stay away from the Ex functions as long as possible because there are
1938 * differences in the return values
1941 * RegCreateKeyEx32A \
1942 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
1946 /******************************************************************************
1947 * RegCreateKeyEx32W [ADVAPI32.131]
1950 * hkey [I] Handle of an open key
1951 * lpszSubKey [I] Address of subkey name
1952 * dwReserved [I] Reserved - must be 0
1953 * lpszClass [I] Address of class string
1954 * fdwOptions [I] Special options flag
1955 * samDesired [I] Desired security access
1956 * lpSecAttribs [I] Address of key security structure
1957 * retkey [O] Address of buffer for opened handle
1958 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
1960 DWORD WINAPI RegCreateKeyEx32W( HKEY hkey, LPCWSTR lpszSubKey,
1961 DWORD dwReserved, LPWSTR lpszClass,
1962 DWORD fdwOptions, REGSAM samDesired,
1963 LPSECURITY_ATTRIBUTES lpSecAttribs,
1964 LPHKEY retkey, LPDWORD lpDispos )
1966 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
1970 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
1971 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
1972 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
1974 lpNextKey = lookup_hkey(hkey);
1976 return ERROR_INVALID_HANDLE;
1978 /* Check for valid options */
1979 switch(fdwOptions) {
1980 case REG_OPTION_NON_VOLATILE:
1981 case REG_OPTION_VOLATILE:
1982 case REG_OPTION_BACKUP_RESTORE:
1985 return ERROR_INVALID_PARAMETER;
1988 /* Sam has to be a combination of the following */
1990 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
1991 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
1992 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
1993 return ERROR_INVALID_PARAMETER;
1995 if (!lpszSubKey || !*lpszSubKey) {
1997 add_handle(currenthandle,lpNextKey,samDesired);
1998 *retkey=currenthandle;
1999 TRACE(reg, "Returning %x\n", currenthandle);
2000 lpNextKey->flags|=REG_OPTION_TAINTED;
2001 return ERROR_SUCCESS;
2004 if (lpszSubKey[0] == '\\') {
2005 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2006 return ERROR_BAD_PATHNAME;
2009 split_keypath(lpszSubKey,&wps,&wpc);
2011 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2014 lpxkey=lpNextKey->nextsub;
2016 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
2018 lpxkey=lpxkey->next;
2027 add_handle(currenthandle,lpxkey,samDesired);
2028 lpxkey->flags |= REG_OPTION_TAINTED;
2029 *retkey = currenthandle;
2030 TRACE(reg, "Returning %x\n", currenthandle);
2032 *lpDispos = REG_OPENED_EXISTING_KEY;
2034 return ERROR_SUCCESS;
2037 /* Good. Now the hard part */
2039 lplpPrevKey = &(lpNextKey->nextsub);
2040 lpxkey = *lplpPrevKey;
2042 lplpPrevKey = &(lpxkey->next);
2043 lpxkey = *lplpPrevKey;
2045 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2046 if (!*lplpPrevKey) {
2048 TRACE(reg, "Returning OUTOFMEMORY\n");
2049 return ERROR_OUTOFMEMORY;
2051 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2052 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2053 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2054 (*lplpPrevKey)->next = NULL;
2055 (*lplpPrevKey)->nextsub = NULL;
2056 (*lplpPrevKey)->values = NULL;
2057 (*lplpPrevKey)->nrofvalues = 0;
2058 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2060 (*lplpPrevKey)->class = strdupW(lpszClass);
2062 (*lplpPrevKey)->class = NULL;
2063 lpNextKey = *lplpPrevKey;
2067 add_handle(currenthandle,lpNextKey,samDesired);
2069 /*FIXME: flag handling correct? */
2070 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2072 lpNextKey->class = strdupW(lpszClass);
2074 lpNextKey->class = NULL;
2075 *retkey = currenthandle;
2076 TRACE(reg, "Returning %x\n", currenthandle);
2078 *lpDispos = REG_CREATED_NEW_KEY;
2080 return ERROR_SUCCESS;
2084 /******************************************************************************
2085 * RegCreateKeyEx32A [ADVAPI32.130]
2087 DWORD WINAPI RegCreateKeyEx32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2088 LPSTR lpszClass, DWORD fdwOptions,
2090 LPSECURITY_ATTRIBUTES lpSecAttribs,
2091 LPHKEY retkey, LPDWORD lpDispos )
2093 LPWSTR lpszSubKeyW, lpszClassW;
2096 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2097 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2100 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2101 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2103 ret = RegCreateKeyEx32W( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2104 fdwOptions, samDesired, lpSecAttribs, retkey,
2107 if(lpszSubKeyW) free(lpszSubKeyW);
2108 if(lpszClassW) free(lpszClassW);
2114 /******************************************************************************
2115 * RegCreateKey32W [ADVAPI32.132]
2117 DWORD WINAPI RegCreateKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2120 LPKEYSTRUCT lpNextKey;
2122 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2124 /* This check is here because the return value is different than the
2125 one from the Ex functions */
2126 lpNextKey = lookup_hkey(hkey);
2128 return ERROR_BADKEY;
2130 return RegCreateKeyEx32W( hkey, lpszSubKey, 0, NULL,
2131 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2136 /******************************************************************************
2137 * RegCreateKey32A [ADVAPI32.129]
2139 DWORD WINAPI RegCreateKey32A( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2144 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2145 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2146 ret = RegCreateKey32W( hkey, lpszSubKeyW, retkey );
2147 if(lpszSubKeyW) free(lpszSubKeyW);
2152 /******************************************************************************
2153 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2155 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2157 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2158 return RegCreateKey32A( hkey, lpszSubKey, retkey );
2163 * Query Value Functions
2164 * Win32 differs between keynames and valuenames.
2165 * multiple values may belong to one key, the special value
2166 * with name NULL is the default value used by the win31
2170 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2171 * RegQueryValue32W -> RegQueryValueEx32W
2175 /******************************************************************************
2176 * RegQueryValueEx32W [ADVAPI32.158]
2177 * Retrieves type and data for a specified name associated with an open key
2180 * hkey [I] Handle of key to query
2181 * lpValueName [I] Name of value to query
2182 * lpdwReserved [I] Reserved - must be NULL
2183 * lpdwType [O] Address of buffer for value type. If NULL, the type
2185 * lpbData [O] Address of data buffer. If NULL, the actual data is
2187 * lpcbData [I/O] Address of data buffer size
2190 * ERROR_SUCCESS: Success
2191 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2192 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2194 DWORD WINAPI RegQueryValueEx32W( HKEY hkey, LPWSTR lpValueName,
2195 LPDWORD lpdwReserved, LPDWORD lpdwType,
2196 LPBYTE lpbData, LPDWORD lpcbData )
2202 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2203 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2205 lpkey = lookup_hkey(hkey);
2208 return ERROR_INVALID_HANDLE;
2210 if ((lpbData && ! lpcbData) || lpdwReserved)
2211 return ERROR_INVALID_PARAMETER;
2213 /* An empty name string is equivalent to NULL */
2214 if (lpValueName && !*lpValueName)
2217 if (lpValueName==NULL)
2218 { /* Use key's unnamed or default value, if any */
2219 for (i=0;i<lpkey->nrofvalues;i++)
2220 if (lpkey->values[i].name==NULL)
2224 { /* Search for the key name */
2225 for (i=0;i<lpkey->nrofvalues;i++)
2226 if ( lpkey->values[i].name && !lstrcmpi32W(lpValueName,lpkey->values[i].name))
2230 if (i==lpkey->nrofvalues)
2231 { TRACE(reg," Key not found\n");
2232 if (lpValueName==NULL)
2233 { /* Empty keyname not found */
2235 { *(WCHAR*)lpbData = 0;
2240 TRACE(reg, " Returning an empty string\n");
2241 return ERROR_SUCCESS;
2243 return ERROR_FILE_NOT_FOUND;
2246 ret = ERROR_SUCCESS;
2248 if (lpdwType) /* type required ?*/
2249 *lpdwType = lpkey->values[i].type;
2251 if (lpbData) /* data required ?*/
2252 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2253 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2255 ret = ERROR_MORE_DATA;
2258 if (lpcbData) /* size required ?*/
2259 { *lpcbData = lpkey->values[i].len;
2262 debug_print_value ( lpbData, lpkey->values[i].type, lpkey->values[i].len);
2264 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2270 /******************************************************************************
2271 * RegQueryValue32W [ADVAPI32.159]
2273 DWORD WINAPI RegQueryValue32W( HKEY hkey, LPWSTR lpszSubKey, LPWSTR lpszData,
2279 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2280 lpcbData?*lpcbData:0);
2282 /* Only open subkey, if we really do descend */
2283 if (lpszSubKey && *lpszSubKey) {
2284 ret = RegOpenKey32W( hkey, lpszSubKey, &xhkey );
2285 if (ret != ERROR_SUCCESS) {
2286 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2293 ret = RegQueryValueEx32W( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2301 /******************************************************************************
2302 * RegQueryValueEx32A [ADVAPI32.157]
2305 * the documantation is wrong: if the buffer is to small it remains untouched
2307 * FIXME: check returnvalue (len) for an empty key
2309 DWORD WINAPI RegQueryValueEx32A( HKEY hkey, LPSTR lpszValueName,
2310 LPDWORD lpdwReserved, LPDWORD lpdwType,
2311 LPBYTE lpbData, LPDWORD lpcbData )
2313 LPWSTR lpszValueNameW;
2314 LPBYTE mybuf = NULL;
2315 DWORD ret, mytype, mylen = 0;
2317 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2318 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2320 if (!lpcbData && lpbData) /* buffer without size is illegal */
2321 { return ERROR_INVALID_PARAMETER;
2324 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2326 /* get just the type first */
2327 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2329 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2330 { if(lpszValueNameW) free(lpszValueNameW);
2334 if (lpcbData) /* at least length requested? */
2335 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2336 { if (lpbData ) /* value requested? */
2337 { mylen = 2*( *lpcbData );
2338 mybuf = (LPBYTE)xmalloc( mylen );
2341 ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2343 if (ret == ERROR_SUCCESS )
2345 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2349 *lpcbData = mylen/2; /* size is in byte! */
2351 else /* no strings, call it straight */
2352 { ret = RegQueryValueEx32W( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2356 if (lpdwType) /* type when requested */
2357 { *lpdwType = mytype;
2360 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2362 if(mybuf) free(mybuf);
2363 if(lpszValueNameW) free(lpszValueNameW);
2368 /******************************************************************************
2369 * RegQueryValueEx16 [KERNEL.225]
2371 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2372 LPDWORD lpdwReserved, LPDWORD lpdwType,
2373 LPBYTE lpbData, LPDWORD lpcbData )
2375 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2376 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2377 return RegQueryValueEx32A( hkey, lpszValueName, lpdwReserved, lpdwType,
2378 lpbData, lpcbData );
2382 /******************************************************************************
2383 * RegQueryValue32A [ADVAPI32.156]
2385 DWORD WINAPI RegQueryValue32A( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2391 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2392 lpcbData?*lpcbData:0);
2394 if (lpszSubKey && *lpszSubKey) {
2395 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2396 if( ret != ERROR_SUCCESS )
2402 ret = RegQueryValueEx32A( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2405 RegCloseKey( xhkey );
2410 /******************************************************************************
2411 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2414 * Is this HACK still applicable?
2417 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2418 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2421 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2424 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2425 lpcbData?*lpcbData:0);
2428 *lpcbData &= 0xFFFF;
2429 return RegQueryValue32A(hkey,lpszSubKey,lpszData,lpcbData);
2434 * Setting values of Registry keys
2437 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2438 * RegSetValue32W -> RegSetValueEx32W
2442 /******************************************************************************
2443 * RegSetValueEx32W [ADVAPI32.170]
2444 * Sets the data and type of a value under a register key
2447 * hkey [I] Handle of key to set value for
2448 * lpszValueName [I] Name of value to set
2449 * dwReserved [I] Reserved - must be zero
2450 * dwType [I] Flag for value type
2451 * lpbData [I] Address of value data
2452 * cbData [I] Size of value data
2455 * Success: ERROR_SUCCESS
2456 * Failure: Error code
2459 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2461 DWORD WINAPI RegSetValueEx32W( HKEY hkey, LPWSTR lpszValueName,
2462 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2468 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2469 dwReserved, dwType, lpbData, cbData);
2471 debug_print_value ( lpbData, dwType, cbData );
2473 lpkey = lookup_hkey( hkey );
2476 return ERROR_INVALID_HANDLE;
2478 lpkey->flags |= REG_OPTION_TAINTED;
2480 if (lpszValueName==NULL) {
2481 /* Sets type and name for key's unnamed or default value */
2482 for (i=0;i<lpkey->nrofvalues;i++)
2483 if (lpkey->values[i].name==NULL)
2486 for (i=0;i<lpkey->nrofvalues;i++)
2487 if ( lpkey->values[i].name &&
2488 !lstrcmpi32W(lpszValueName,lpkey->values[i].name)
2492 if (i==lpkey->nrofvalues) {
2493 lpkey->values = (LPKEYVALUE)xrealloc(
2495 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2497 lpkey->nrofvalues++;
2498 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2500 if (lpkey->values[i].name==NULL) {
2502 lpkey->values[i].name = strdupW(lpszValueName);
2504 lpkey->values[i].name = NULL;
2507 if (dwType == REG_SZ)
2508 cbData = 2 * (lstrlen32W ((LPCWSTR)lpbData) + 1);
2510 lpkey->values[i].len = cbData;
2511 lpkey->values[i].type = dwType;
2512 if (lpkey->values[i].data !=NULL)
2513 free(lpkey->values[i].data);
2514 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2515 lpkey->values[i].lastmodified = time(NULL);
2516 memcpy(lpkey->values[i].data,lpbData,cbData);
2517 return ERROR_SUCCESS;
2521 /******************************************************************************
2522 * RegSetValueEx32A [ADVAPI32.169]
2525 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2527 DWORD WINAPI RegSetValueEx32A( HKEY hkey, LPSTR lpszValueName,
2528 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2532 LPWSTR lpszValueNameW;
2536 return (ERROR_INVALID_PARAMETER);
2538 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2539 dwReserved,dwType,lpbData,cbData);
2541 if ((1<<dwType) & UNICONVMASK)
2542 { if (dwType == REG_SZ)
2543 cbData = strlen ((LPCSTR)lpbData)+1;
2545 buf = (LPBYTE)xmalloc( cbData *2 );
2546 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2553 lpszValueNameW = strdupA2W(lpszValueName);
2555 lpszValueNameW = NULL;
2557 ret=RegSetValueEx32W(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2560 free(lpszValueNameW);
2569 /******************************************************************************
2570 * RegSetValueEx16 [KERNEL.226]
2572 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2573 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2575 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2576 dwReserved,dwType,lpbData,cbData);
2577 return RegSetValueEx32A( hkey, lpszValueName, dwReserved, dwType, lpbData,
2582 /******************************************************************************
2583 * RegSetValue32W [ADVAPI32.171]
2585 DWORD WINAPI RegSetValue32W( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2586 LPCWSTR lpszData, DWORD cbData )
2591 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2592 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2594 if (lpszSubKey && *lpszSubKey) {
2595 ret=RegCreateKey32W(hkey,lpszSubKey,&xhkey);
2596 if (ret!=ERROR_SUCCESS)
2600 if (dwType!=REG_SZ) {
2601 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2604 if (cbData!=2*lstrlen32W(lpszData)+2) {
2605 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2606 cbData,debugstr_w(lpszData),2*lstrlen32W(lpszData)+2
2608 cbData=2*lstrlen32W(lpszData)+2;
2610 ret=RegSetValueEx32W(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2617 /******************************************************************************
2618 * RegSetValue32A [ADVAPI32.168]
2621 DWORD WINAPI RegSetValue32A( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2622 LPCSTR lpszData, DWORD cbData )
2627 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2628 if (lpszSubKey && *lpszSubKey) {
2629 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2630 if (ret!=ERROR_SUCCESS)
2635 if (dwType!=REG_SZ) {
2636 TRACE(reg,"dwType=%ld!\n",dwType);
2639 if (cbData!=strlen(lpszData)+1)
2640 cbData=strlen(lpszData)+1;
2641 ret=RegSetValueEx32A(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2648 /******************************************************************************
2649 * RegSetValue16 [KERNEL.221] [SHELL.5]
2651 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2652 LPCSTR lpszData, DWORD cbData )
2654 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2655 debugstr_a(lpszData),cbData);
2656 return RegSetValue32A(hkey,lpszSubKey,dwType,lpszData,cbData);
2664 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2665 * RegEnumKey32W -> RegEnumKeyEx32W
2669 /******************************************************************************
2670 * RegEnumKeyEx32W [ADVAPI32.139]
2673 * hkey [I] Handle to key to enumerate
2674 * iSubKey [I] Index of subkey to enumerate
2675 * lpszName [O] Buffer for subkey name
2676 * lpcchName [O] Size of subkey buffer
2677 * lpdwReserved [I] Reserved
2678 * lpszClass [O] Buffer for class string
2679 * lpcchClass [O] Size of class buffer
2680 * ft [O] Time key last written to
2682 DWORD WINAPI RegEnumKeyEx32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2683 LPDWORD lpcchName, LPDWORD lpdwReserved,
2684 LPWSTR lpszClass, LPDWORD lpcchClass,
2687 LPKEYSTRUCT lpkey,lpxkey;
2689 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2690 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2692 lpkey = lookup_hkey( hkey );
2694 return ERROR_INVALID_HANDLE;
2696 if (!lpkey->nextsub)
2697 return ERROR_NO_MORE_ITEMS;
2698 lpxkey=lpkey->nextsub;
2700 /* Traverse the subkeys */
2701 while (iSubkey && lpxkey) {
2703 lpxkey=lpxkey->next;
2706 if (iSubkey || !lpxkey)
2707 return ERROR_NO_MORE_ITEMS;
2708 if (lstrlen32W(lpxkey->keyname)+1>*lpcchName)
2709 return ERROR_MORE_DATA;
2710 memcpy(lpszName,lpxkey->keyname,lstrlen32W(lpxkey->keyname)*2+2);
2713 *lpcchName = lstrlen32W(lpszName);
2716 /* FIXME: what should we write into it? */
2720 return ERROR_SUCCESS;
2724 /******************************************************************************
2725 * RegEnumKey32W [ADVAPI32.140]
2727 DWORD WINAPI RegEnumKey32W( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2732 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2733 return RegEnumKeyEx32W(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2737 /******************************************************************************
2738 * RegEnumKeyEx32A [ADVAPI32.138]
2740 DWORD WINAPI RegEnumKeyEx32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2741 LPDWORD lpcchName, LPDWORD lpdwReserved,
2742 LPSTR lpszClass, LPDWORD lpcchClass,
2745 DWORD ret,lpcchNameW,lpcchClassW;
2746 LPWSTR lpszNameW,lpszClassW;
2749 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
2750 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
2753 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
2754 lpcchNameW = *lpcchName;
2760 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
2761 lpcchClassW = *lpcchClass;
2766 ret=RegEnumKeyEx32W(
2776 if (ret==ERROR_SUCCESS) {
2777 lstrcpyWtoA(lpszName,lpszNameW);
2778 *lpcchName=strlen(lpszName);
2780 lstrcpyWtoA(lpszClass,lpszClassW);
2781 *lpcchClass=strlen(lpszClass);
2792 /******************************************************************************
2793 * RegEnumKey32A [ADVAPI32.137]
2795 DWORD WINAPI RegEnumKey32A( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2800 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2801 return RegEnumKeyEx32A( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
2806 /******************************************************************************
2807 * RegEnumKey16 [SHELL.7] [KERNEL.216]
2809 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2812 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2813 return RegEnumKey32A( hkey, iSubkey, lpszName, lpcchName);
2818 * Enumerate Registry Values
2821 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
2825 /******************************************************************************
2826 * RegEnumValue32W [ADVAPI32.142]
2829 * hkey [I] Handle to key to query
2830 * iValue [I] Index of value to query
2831 * lpszValue [O] Value string
2832 * lpcchValue [I/O] Size of value buffer (in wchars)
2833 * lpdReserved [I] Reserved
2834 * lpdwType [O] Type code
2835 * lpbData [O] Value data
2836 * lpcbData [I/O] Size of data buffer (in bytes)
2838 * Note: wide character functions that take and/or return "character counts"
2839 * use TCHAR (that is unsigned short or char) not byte counts.
2841 DWORD WINAPI RegEnumValue32W( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
2842 LPDWORD lpcchValue, LPDWORD lpdReserved,
2843 LPDWORD lpdwType, LPBYTE lpbData,
2849 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
2850 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
2852 lpkey = lookup_hkey( hkey );
2854 if (!lpcbData && lpbData)
2855 return ERROR_INVALID_PARAMETER;
2858 return ERROR_INVALID_HANDLE;
2860 if (lpkey->nrofvalues <= iValue)
2861 return ERROR_NO_MORE_ITEMS;
2863 val = &(lpkey->values[iValue]);
2866 if (lstrlen32W(val->name)+1>*lpcchValue) {
2867 *lpcchValue = lstrlen32W(val->name)+1;
2868 return ERROR_MORE_DATA;
2870 memcpy(lpszValue,val->name,2 * (lstrlen32W(val->name)+1) );
2871 *lpcchValue=lstrlen32W(val->name);
2877 /* Can be NULL if the type code is not required */
2879 *lpdwType = val->type;
2882 if (val->len>*lpcbData)
2883 return ERROR_MORE_DATA;
2884 memcpy(lpbData,val->data,val->len);
2885 *lpcbData = val->len;
2888 debug_print_value ( val->data, val->type, val->len );
2889 return ERROR_SUCCESS;
2893 /******************************************************************************
2894 * RegEnumValue32A [ADVAPI32.141]
2896 DWORD WINAPI RegEnumValue32A( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2897 LPDWORD lpcchValue, LPDWORD lpdReserved,
2898 LPDWORD lpdwType, LPBYTE lpbData,
2903 DWORD ret,lpcbDataW;
2906 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2907 lpdReserved,lpdwType,lpbData,lpcbData);
2909 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
2911 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
2912 lpcbDataW = *lpcbData;
2916 ret = RegEnumValue32W( hkey, iValue, lpszValueW, lpcchValue,
2917 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
2922 if (ret==ERROR_SUCCESS) {
2923 lstrcpyWtoA(lpszValue,lpszValueW);
2925 if ((1<<dwType) & UNICONVMASK) {
2926 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
2928 if (lpcbDataW > *lpcbData)
2929 ret = ERROR_MORE_DATA;
2931 memcpy(lpbData,lpbDataW,lpcbDataW);
2933 *lpcbData = lpcbDataW;
2936 if (lpbDataW) free(lpbDataW);
2937 if (lpszValueW) free(lpszValueW);
2942 /******************************************************************************
2943 * RegEnumValue16 [KERNEL.223]
2945 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
2946 LPDWORD lpcchValue, LPDWORD lpdReserved,
2947 LPDWORD lpdwType, LPBYTE lpbData,
2950 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
2951 lpdReserved,lpdwType,lpbData,lpcbData);
2952 return RegEnumValue32A( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
2953 lpdwType, lpbData, lpcbData );
2957 /******************************************************************************
2958 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
2959 * Releases the handle of the specified key
2962 * hkey [I] Handle of key to close
2965 * Success: ERROR_SUCCESS
2966 * Failure: Error code
2968 DWORD WINAPI RegCloseKey( HKEY hkey )
2970 TRACE(reg,"(%x)\n",hkey);
2972 /* The standard handles are allowed to succeed, even though they are not
2974 if (is_standard_hkey(hkey))
2975 return ERROR_SUCCESS;
2977 return remove_handle(hkey);
2982 * Delete registry key
2985 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
2989 /******************************************************************************
2990 * RegDeleteKey32W [ADVAPI32.134]
2993 * hkey [I] Handle to open key
2994 * lpszSubKey [I] Name of subkey to delete
2997 * Success: ERROR_SUCCESS
2998 * Failure: Error code
3000 DWORD WINAPI RegDeleteKey32W( HKEY hkey, LPWSTR lpszSubKey )
3002 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3006 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3008 lpNextKey = lookup_hkey(hkey);
3010 return ERROR_INVALID_HANDLE;
3012 /* Subkey param cannot be NULL */
3013 if (!lpszSubKey || !*lpszSubKey)
3014 return ERROR_BADKEY;
3016 /* We need to know the previous key in the hier. */
3017 split_keypath(lpszSubKey,&wps,&wpc);
3021 lpxkey=lpNextKey->nextsub;
3023 TRACE(reg, " Scanning [%s]\n",
3024 debugstr_w(lpxkey->keyname));
3025 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3027 lpxkey=lpxkey->next;
3031 TRACE(reg, " Not found.\n");
3032 /* not found is success */
3033 return ERROR_SUCCESS;
3038 lpxkey = lpNextKey->nextsub;
3039 lplpPrevKey = &(lpNextKey->nextsub);
3041 TRACE(reg, " Scanning [%s]\n",
3042 debugstr_w(lpxkey->keyname));
3043 if (!lstrcmpi32W(wps[i],lpxkey->keyname))
3045 lplpPrevKey = &(lpxkey->next);
3046 lpxkey = lpxkey->next;
3051 WARN(reg , " Not found.\n");
3052 return ERROR_FILE_NOT_FOUND;
3055 if (lpxkey->nextsub) {
3057 WARN(reg , " Not empty.\n");
3058 return ERROR_CANTWRITE;
3060 *lplpPrevKey = lpxkey->next;
3061 free(lpxkey->keyname);
3063 free(lpxkey->class);
3065 free(lpxkey->values);
3068 TRACE(reg, " Done.\n");
3069 return ERROR_SUCCESS;
3073 /******************************************************************************
3074 * RegDeleteKey32A [ADVAPI32.133]
3076 DWORD WINAPI RegDeleteKey32A( HKEY hkey, LPCSTR lpszSubKey )
3081 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3082 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3083 ret = RegDeleteKey32W( hkey, lpszSubKeyW );
3084 if(lpszSubKeyW) free(lpszSubKeyW);
3089 /******************************************************************************
3090 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3092 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3094 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3095 return RegDeleteKey32A( hkey, lpszSubKey );
3100 * Delete registry value
3103 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3107 /******************************************************************************
3108 * RegDeleteValue32W [ADVAPI32.136]
3116 DWORD WINAPI RegDeleteValue32W( HKEY hkey, LPWSTR lpszValue )
3122 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3124 lpkey = lookup_hkey( hkey );
3126 return ERROR_INVALID_HANDLE;
3129 for (i=0;i<lpkey->nrofvalues;i++)
3130 if ( lpkey->values[i].name &&
3131 !lstrcmpi32W(lpkey->values[i].name,lpszValue)
3135 for (i=0;i<lpkey->nrofvalues;i++)
3136 if (lpkey->values[i].name==NULL)
3140 if (i == lpkey->nrofvalues)
3141 return ERROR_FILE_NOT_FOUND;
3143 val = lpkey->values+i;
3144 if (val->name) free(val->name);
3145 if (val->data) free(val->data);
3149 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3151 lpkey->values = (LPKEYVALUE)xrealloc(
3153 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3155 lpkey->nrofvalues--;
3156 return ERROR_SUCCESS;
3160 /******************************************************************************
3161 * RegDeleteValue32A [ADVAPI32.135]
3163 DWORD WINAPI RegDeleteValue32A( HKEY hkey, LPSTR lpszValue )
3168 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3169 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3170 ret = RegDeleteValue32W( hkey, lpszValueW );
3171 if(lpszValueW) free(lpszValueW);
3176 /******************************************************************************
3177 * RegDeleteValue16 [KERNEL.222]
3179 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3181 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3182 return RegDeleteValue32A( hkey, lpszValue );
3186 /******************************************************************************
3187 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3188 * Writes key to registry
3191 * hkey [I] Handle of key to write
3194 * Success: ERROR_SUCCESS
3195 * Failure: Error code
3197 DWORD WINAPI RegFlushKey( HKEY hkey )
3202 TRACE(reg, "(%x)\n", hkey);
3204 lpkey = lookup_hkey( hkey );
3206 return ERROR_INVALID_HANDLE;
3208 ERR(reg, "What is the correct filename?\n");
3210 ret = _savereg( lpkey, "foo.bar", TRUE);
3213 return ERROR_SUCCESS;
3215 return ERROR_UNKNOWN; /* FIXME */
3219 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3222 /******************************************************************************
3223 * RegQueryInfoKey32W [ADVAPI32.153]
3226 * hkey [I] Handle to key to query
3227 * lpszClass [O] Buffer for class string
3228 * lpcchClass [O] Size of class string buffer
3229 * lpdwReserved [I] Reserved
3230 * lpcSubKeys [I] Buffer for number of subkeys
3231 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3232 * lpcchMaxClass [O] Buffer for longest class string length
3233 * lpcValues [O] Buffer for number of value entries
3234 * lpcchMaxValueName [O] Buffer for longest value name length
3235 * lpccbMaxValueData [O] Buffer for longest value data length
3236 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3238 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3239 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3240 * lpcchClass is NULL
3241 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3242 * (it's hard to test validity, so test !NULL instead)
3244 DWORD WINAPI RegQueryInfoKey32W( HKEY hkey, LPWSTR lpszClass,
3245 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3246 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3247 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3248 LPDWORD lpcchMaxValueName,
3249 LPDWORD lpccbMaxValueData,
3250 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3252 LPKEYSTRUCT lpkey,lpxkey;
3253 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3256 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3257 lpkey = lookup_hkey(hkey);
3259 return ERROR_INVALID_HANDLE;
3261 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3262 return ERROR_INVALID_PARAMETER;
3264 /* either lpcchClass is valid or this is win95 and lpcchClass
3267 DWORD classLen = lstrlen32W(lpkey->class);
3269 if (lpcchClass && classLen+1>*lpcchClass) {
3270 *lpcchClass=classLen+1;
3271 return ERROR_MORE_DATA;
3274 *lpcchClass=classLen;
3275 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3283 *lpcchClass = lstrlen32W(lpkey->class);
3285 lpxkey=lpkey->nextsub;
3286 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3289 if (lstrlen32W(lpxkey->keyname)>maxsubkey)
3290 maxsubkey=lstrlen32W(lpxkey->keyname);
3291 if (lpxkey->class && lstrlen32W(lpxkey->class)>maxclass)
3292 maxclass=lstrlen32W(lpxkey->class);
3293 lpxkey=lpxkey->next;
3295 for (i=0;i<lpkey->nrofvalues;i++) {
3296 LPKEYVALUE val=lpkey->values+i;
3298 if (val->name && lstrlen32W(val->name)>maxvname)
3299 maxvname=lstrlen32W(val->name);
3300 if (val->len>maxvdata)
3303 if (!maxclass) maxclass = 1;
3304 if (!maxvname) maxvname = 1;
3306 *lpcValues = lpkey->nrofvalues;
3308 *lpcSubKeys = nrofkeys;
3310 *lpcchMaxSubkey = maxsubkey;
3312 *lpcchMaxClass = maxclass;
3313 if (lpcchMaxValueName)
3314 *lpcchMaxValueName= maxvname;
3315 if (lpccbMaxValueData)
3316 *lpccbMaxValueData= maxvdata;
3317 return ERROR_SUCCESS;
3321 /******************************************************************************
3322 * RegQueryInfoKey32A [ADVAPI32.152]
3324 DWORD WINAPI RegQueryInfoKey32A( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3325 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3326 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3327 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3328 LPDWORD lpccbMaxValueData,
3329 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3331 LPWSTR lpszClassW = NULL;
3334 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3337 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3338 } else if (VERSION_GetVersion() == WIN95) {
3339 /* win95 allows lpcchClass to be null */
3340 /* we don't know how big lpszClass is, would
3341 MAX_PATHNAME_LEN be the correct default? */
3342 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3347 ret=RegQueryInfoKey32W(
3358 lpcbSecurityDescriptor,
3361 if (ret==ERROR_SUCCESS && lpszClass)
3362 lstrcpyWtoA(lpszClass,lpszClassW);
3369 /******************************************************************************
3370 * RegConnectRegistry32W [ADVAPI32.128]
3373 * lpMachineName [I] Address of name of remote computer
3374 * hHey [I] Predefined registry handle
3375 * phkResult [I] Address of buffer for remote registry handle
3377 LONG WINAPI RegConnectRegistry32W( LPCWSTR lpMachineName, HKEY hKey,
3380 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3382 if (!lpMachineName || !*lpMachineName) {
3383 /* Use the local machine name */
3384 return RegOpenKey16( hKey, "", phkResult );
3387 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3388 return ERROR_BAD_NETPATH;
3392 /******************************************************************************
3393 * RegConnectRegistry32A [ADVAPI32.127]
3395 LONG WINAPI RegConnectRegistry32A( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3398 LPWSTR machineW = strdupA2W(machine);
3399 ret = RegConnectRegistry32W( machineW, hkey, reskey );
3405 /******************************************************************************
3406 * RegGetKeySecurity [ADVAPI32.144]
3407 * Retrieves a copy of security descriptor protecting the registry key
3410 * hkey [I] Open handle of key to set
3411 * SecurityInformation [I] Descriptor contents
3412 * pSecurityDescriptor [O] Address of descriptor for key
3413 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3416 * Success: ERROR_SUCCESS
3417 * Failure: Error code
3419 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3420 SECURITY_INFORMATION SecurityInformation,
3421 LPSECURITY_DESCRIPTOR pSecurityDescriptor,
3422 LPDWORD lpcbSecurityDescriptor )
3426 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3427 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3429 lpkey = lookup_hkey( hkey );
3431 return ERROR_INVALID_HANDLE;
3433 /* FIXME: Check for valid SecurityInformation values */
3435 if (*lpcbSecurityDescriptor < sizeof(*pSecurityDescriptor))
3436 return ERROR_INSUFFICIENT_BUFFER;
3438 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3439 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3441 return ERROR_SUCCESS;
3445 /******************************************************************************
3446 * RegLoadKey32W [ADVAPI32.???]
3449 * hkey [I] Handle of open key
3450 * lpszSubKey [I] Address of name of subkey
3451 * lpszFile [I] Address of filename for registry information
3453 LONG WINAPI RegLoadKey32W( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3456 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3458 /* Do this check before the hkey check */
3459 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3460 return ERROR_INVALID_PARAMETER;
3462 lpkey = lookup_hkey( hkey );
3464 return ERROR_INVALID_HANDLE;
3466 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3467 debugstr_w(lpszFile));
3469 return ERROR_SUCCESS;
3473 /******************************************************************************
3474 * RegLoadKey32A [ADVAPI32.???]
3476 LONG WINAPI RegLoadKey32A( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3479 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3480 LPWSTR lpszFileW = strdupA2W(lpszFile);
3481 ret = RegLoadKey32W( hkey, lpszSubKeyW, lpszFileW );
3482 if(lpszFileW) free(lpszFileW);
3483 if(lpszSubKeyW) free(lpszSubKeyW);
3488 /******************************************************************************
3489 * RegNotifyChangeKeyValue [ADVAPI32.???]
3492 * hkey [I] Handle of key to watch
3493 * fWatchSubTree [I] Flag for subkey notification
3494 * fdwNotifyFilter [I] Changes to be reported
3495 * hEvent [I] Handle of signaled event
3496 * fAsync [I] Flag for asynchronous reporting
3498 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL32 fWatchSubTree,
3499 DWORD fdwNotifyFilter, HANDLE32 hEvent,
3503 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3506 lpkey = lookup_hkey( hkey );
3508 return ERROR_INVALID_HANDLE;
3510 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3513 return ERROR_SUCCESS;
3517 /******************************************************************************
3518 * RegUnLoadKey32W [ADVAPI32.173]
3521 * hkey [I] Handle of open key
3522 * lpSubKey [I] Address of name of subkey to unload
3524 LONG WINAPI RegUnLoadKey32W( HKEY hkey, LPCWSTR lpSubKey )
3526 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3527 return ERROR_SUCCESS;
3531 /******************************************************************************
3532 * RegUnLoadKey32A [ADVAPI32.172]
3534 LONG WINAPI RegUnLoadKey32A( HKEY hkey, LPCSTR lpSubKey )
3537 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3538 ret = RegUnLoadKey32W( hkey, lpSubKeyW );
3539 if(lpSubKeyW) free(lpSubKeyW);
3544 /******************************************************************************
3545 * RegSetKeySecurity [ADVAPI32.167]
3548 * hkey [I] Open handle of key to set
3549 * SecurityInfo [I] Descriptor contents
3550 * pSecurityDesc [I] Address of descriptor for key
3552 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3553 LPSECURITY_DESCRIPTOR pSecurityDesc )
3557 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3559 /* It seems to perform this check before the hkey check */
3560 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3561 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3562 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3563 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3566 return ERROR_INVALID_PARAMETER;
3569 return ERROR_INVALID_PARAMETER;
3571 lpkey = lookup_hkey( hkey );
3573 return ERROR_INVALID_HANDLE;
3575 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3577 return ERROR_SUCCESS;
3581 /******************************************************************************
3582 * RegSaveKey32W [ADVAPI32.166]
3585 * hkey [I] Handle of key where save begins
3586 * lpFile [I] Address of filename to save to
3587 * sa [I] Address of security structure
3589 LONG WINAPI RegSaveKey32W( HKEY hkey, LPCWSTR lpFile,
3590 LPSECURITY_ATTRIBUTES sa )
3594 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3596 /* It appears to do this check before the hkey check */
3597 if (!lpFile || !*lpFile)
3598 return ERROR_INVALID_PARAMETER;
3600 lpkey = lookup_hkey( hkey );
3602 return ERROR_INVALID_HANDLE;
3604 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3606 return ERROR_SUCCESS;
3610 /******************************************************************************
3611 * RegSaveKey32A [ADVAPI32.165]
3613 LONG WINAPI RegSaveKey32A( HKEY hkey, LPCSTR lpFile,
3614 LPSECURITY_ATTRIBUTES sa )
3617 LPWSTR lpFileW = strdupA2W(lpFile);
3618 ret = RegSaveKey32W( hkey, lpFileW, sa );
3624 /******************************************************************************
3625 * RegRestoreKey32W [ADVAPI32.164]
3628 * hkey [I] Handle of key where restore begins
3629 * lpFile [I] Address of filename containing saved tree
3630 * dwFlags [I] Optional flags
3632 LONG WINAPI RegRestoreKey32W( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3636 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3638 /* It seems to do this check before the hkey check */
3639 if (!lpFile || !*lpFile)
3640 return ERROR_INVALID_PARAMETER;
3642 lpkey = lookup_hkey( hkey );
3644 return ERROR_INVALID_HANDLE;
3646 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3648 /* Check for file existence */
3650 return ERROR_SUCCESS;
3654 /******************************************************************************
3655 * RegRestoreKey32A [ADVAPI32.163]
3657 LONG WINAPI RegRestoreKey32A( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3660 LPWSTR lpFileW = strdupA2W(lpFile);
3661 ret = RegRestoreKey32W( hkey, lpFileW, dwFlags );
3662 if(lpFileW) free(lpFileW);
3667 /******************************************************************************
3668 * RegReplaceKey32W [ADVAPI32.162]
3671 * hkey [I] Handle of open key
3672 * lpSubKey [I] Address of name of subkey
3673 * lpNewFile [I] Address of filename for file with new data
3674 * lpOldFile [I] Address of filename for backup file
3676 LONG WINAPI RegReplaceKey32W( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3681 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3682 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3684 lpkey = lookup_hkey( hkey );
3686 return ERROR_INVALID_HANDLE;
3688 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3689 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3691 return ERROR_SUCCESS;
3695 /******************************************************************************
3696 * RegReplaceKey32A [ADVAPI32.161]
3698 LONG WINAPI RegReplaceKey32A( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3702 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3703 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3704 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3705 ret = RegReplaceKey32W( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );