Updated (prepare|unprepare)header functions (wave, midi) to allow
[wine/multimedia.git] / misc / registry.c
blob4c37e1ebb6f81deaa4ab52eb4f4ef127e6f57ae1
1 /*
2 * Registry Functions
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.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
30 #include <sys/stat.h>
31 #include <pwd.h>
32 #include <assert.h>
33 #include <time.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
38 #include "winerror.h"
39 #include "file.h"
40 #include "heap.h"
41 #include "debug.h"
42 #include "xmalloc.h"
43 #include "options.h"
44 #include "winreg.h"
45 #include "winversion.h"
47 static void REGISTRY_Init(void);
48 /* FIXME: following defines should be configured global ... */
50 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
51 #define WINE_PREFIX "/.wine"
52 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
53 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
55 /* relative in ~user/.wine/ : */
56 #define SAVE_CURRENT_USER "user.reg"
57 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
58 #define SAVE_LOCAL_MACHINE "system.reg"
60 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
61 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
63 /* one value of a key */
64 typedef struct tagKEYVALUE
66 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
67 DWORD type; /* type of value */
68 DWORD len; /* length of data in BYTEs */
69 DWORD lastmodified; /* time of seconds since 1.1.1970 */
70 LPBYTE data; /* content, may be strings, binaries, etc. */
71 } KEYVALUE,*LPKEYVALUE;
73 /* a registry key */
74 typedef struct tagKEYSTRUCT
76 LPWSTR keyname; /* name of THIS key (UNICODE) */
77 DWORD flags; /* flags. */
78 LPWSTR class;
79 /* values */
80 DWORD nrofvalues; /* nr of values in THIS key */
81 LPKEYVALUE values; /* values in THIS key */
82 /* key management pointers */
83 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
84 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
85 } KEYSTRUCT, *LPKEYSTRUCT;
88 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
89 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
90 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
91 static KEYSTRUCT *key_users=NULL; /* all users? */
93 /* dynamic, not saved */
94 static KEYSTRUCT *key_performance_data=NULL;
95 static KEYSTRUCT *key_current_config=NULL;
96 static KEYSTRUCT *key_dyn_data=NULL;
98 /* what valuetypes do we need to convert? */
99 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
102 static struct openhandle {
103 LPKEYSTRUCT lpkey;
104 HKEY hkey;
105 REGSAM accessmask;
106 } *openhandles=NULL;
107 static int nrofopenhandles=0;
108 /* Starts after 1 because 0,1 are reserved for Win16 */
109 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
110 HKEYs for remote registry access */
111 static int currenthandle=2;
115 * QUESTION
116 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
117 * If so, can we remove them?
118 * ANSWER
119 * No, the memory handling functions are called very often in here,
120 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
121 * loading 100 times slower. -MM
123 static LPWSTR strdupA2W(LPCSTR src)
125 if(src) {
126 LPWSTR dest=xmalloc(2*strlen(src)+2);
127 lstrcpyAtoW(dest,src);
128 return dest;
130 return NULL;
133 static LPWSTR strdupW(LPCWSTR a) {
134 LPWSTR b;
135 int len;
137 if(a) {
138 len=sizeof(WCHAR)*(lstrlenW(a)+1);
139 b=(LPWSTR)xmalloc(len);
140 memcpy(b,a,len);
141 return b;
143 return NULL;
146 LPWSTR strcvtA2W(LPCSTR src, int nchars)
149 LPWSTR dest = xmalloc (2 * nchars + 2);
151 lstrcpynAtoW(dest,src,nchars+1);
152 dest[nchars] = 0;
153 return dest;
156 * we need to convert A to W with '\0' in strings (MULTI_SZ)
159 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
160 { LPWSTR p = dst;
162 TRACE(reg,"\"%s\" %i\n",src, n);
164 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
166 return dst;
168 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
169 { LPSTR p = dst;
171 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
173 while (n-- > 0) *p++ = (CHAR)*src++;
175 return dst;
178 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
180 if (TRACE_ON(reg) && lpbData)
182 switch(key->type)
184 case HEX_REG_EXPAND_SZ:
185 case HEX_REG_SZ:
186 case REG_SZ:
187 TRACE(reg," Value %s, Data(sz)=%s\n",
188 debugstr_w(key->name),
189 debugstr_w((LPCWSTR)lpbData));
190 break;
192 case HEX_REG_DWORD:
193 case REG_DWORD:
194 TRACE(reg," Value %s, Data(dword)=0x%08lx\n",
195 debugstr_w(key->name),
196 (DWORD)*lpbData);
197 break;
199 case HEX_REG_MULTI_SZ:
200 case REG_MULTI_SZ:
202 int i;
203 LPCWSTR ptr = (LPCWSTR)lpbData;
204 for (i=0;ptr[0];i++)
206 TRACE(reg, " Value %s, MULTI_SZ(%i=%s)\n",
207 debugstr_w(key->name),
209 debugstr_w(ptr));
211 ptr += lstrlenW(ptr)+1;
214 break;
216 case HEX_REG_NONE:
217 case HEX_REG_BINARY:
218 case HEX_REG_LINK:
219 case HEX_REG_RESOURCE_LIST:
220 case HEX_REG_FULL_RESOURCE_DESCRIPTOR:
221 case REG_NONE:
222 case REG_LINK:
223 case REG_RESOURCE_LIST:
224 case REG_FULL_RESOURCE_DESCRIPTOR:
225 case REG_BINARY:
227 char szTemp[100]; /* 3*32 + 3 + 1 */
228 int i;
229 for ( i = 0; i < key->len ; i++)
231 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
232 if (i>=31)
234 sprintf (&(szTemp[i*3+3]),"...");
235 break;
238 TRACE(reg," Value %s, Data(raw)=(%s)\n",
239 debugstr_w(key->name),
240 szTemp);
242 break;
244 default:
245 FIXME(reg, " Value %s, Unknown data type %ld\n",
246 debugstr_w(key->name),
247 key->type);
248 } /* switch */
249 } /* if */
253 /******************************************************************************
254 * is_standard_hkey [Internal]
255 * Determines if a hkey is a standard key
257 static BOOL is_standard_hkey( HKEY hkey )
259 switch(hkey) {
260 case 0x00000000:
261 case 0x00000001:
262 case HKEY_CLASSES_ROOT:
263 case HKEY_CURRENT_CONFIG:
264 case HKEY_CURRENT_USER:
265 case HKEY_LOCAL_MACHINE:
266 case HKEY_USERS:
267 case HKEY_PERFORMANCE_DATA:
268 case HKEY_DYN_DATA:
269 return TRUE;
270 default:
271 return FALSE;
275 /******************************************************************************
276 * add_handle [Internal]
278 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
280 int i;
282 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
283 /* Check for duplicates */
284 for (i=0;i<nrofopenhandles;i++) {
285 if (openhandles[i].lpkey==lpkey) {
286 /* This is not really an error - the user is allowed to create
287 two (or more) handles to the same key */
288 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
290 if (openhandles[i].hkey==hkey) {
291 WARN(reg, "Adding handle %x twice\n",hkey);
294 openhandles=xrealloc( openhandles,
295 sizeof(struct openhandle)*(nrofopenhandles+1));
297 openhandles[i].lpkey = lpkey;
298 openhandles[i].hkey = hkey;
299 openhandles[i].accessmask = accessmask;
300 nrofopenhandles++;
304 /******************************************************************************
305 * get_handle [Internal]
307 * RETURNS
308 * Success: Pointer to key
309 * Failure: NULL
311 static LPKEYSTRUCT get_handle( HKEY hkey )
313 int i;
315 for (i=0; i<nrofopenhandles; i++)
316 if (openhandles[i].hkey == hkey)
317 return openhandles[i].lpkey;
318 WARN(reg, "Could not find handle 0x%x\n",hkey);
319 return NULL;
323 /******************************************************************************
324 * remove_handle [Internal]
326 * PARAMS
327 * hkey [I] Handle of key to remove
329 * RETURNS
330 * Success: ERROR_SUCCESS
331 * Failure: ERROR_INVALID_HANDLE
333 static DWORD remove_handle( HKEY hkey )
335 int i;
337 for (i=0;i<nrofopenhandles;i++)
338 if (openhandles[i].hkey==hkey)
339 break;
341 if (i == nrofopenhandles) {
342 WARN(reg, "Could not find handle 0x%x\n",hkey);
343 return ERROR_INVALID_HANDLE;
346 memcpy( openhandles+i,
347 openhandles+i+1,
348 sizeof(struct openhandle)*(nrofopenhandles-i-1)
350 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
351 nrofopenhandles--;
352 return ERROR_SUCCESS;
355 /******************************************************************************
356 * lookup_hkey [Internal]
358 * Just as the name says. Creates the root keys on demand, so we can call the
359 * Reg* functions at any time.
361 * RETURNS
362 * Success: Pointer to key structure
363 * Failure: NULL
365 #define ADD_ROOT_KEY(xx) \
366 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
367 memset(xx,'\0',sizeof(KEYSTRUCT));\
368 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
370 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
372 switch (hkey) {
373 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
374 * some programs. Do not remove those cases. -MM
376 case 0x00000000:
377 case 0x00000001:
378 case HKEY_CLASSES_ROOT:
380 if (!key_classes_root)
382 HKEY cl_r_hkey;
384 /* calls lookup_hkey recursively, TWICE */
385 if ( RegCreateKey16(
386 HKEY_LOCAL_MACHINE,
387 "SOFTWARE\\Classes",
388 &cl_r_hkey) != ERROR_SUCCESS)
390 ERR(
391 reg,
392 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
393 exit(1);
396 key_classes_root = lookup_hkey(cl_r_hkey);
398 return key_classes_root;
401 case HKEY_CURRENT_USER:
402 if (!key_current_user) {
403 ADD_ROOT_KEY(key_current_user);
405 return key_current_user;
407 case HKEY_LOCAL_MACHINE:
408 if (!key_local_machine) {
409 ADD_ROOT_KEY(key_local_machine);
410 REGISTRY_Init();
412 return key_local_machine;
414 case HKEY_USERS:
415 if (!key_users) {
416 ADD_ROOT_KEY(key_users);
418 return key_users;
420 case HKEY_PERFORMANCE_DATA:
421 if (!key_performance_data) {
422 ADD_ROOT_KEY(key_performance_data);
424 return key_performance_data;
426 case HKEY_DYN_DATA:
427 if (!key_dyn_data) {
428 ADD_ROOT_KEY(key_dyn_data);
430 return key_dyn_data;
432 case HKEY_CURRENT_CONFIG:
433 if (!key_current_config) {
434 ADD_ROOT_KEY(key_current_config);
436 return key_current_config;
438 default:
439 return get_handle(hkey);
442 /*NOTREACHED*/
444 #undef ADD_ROOT_KEY
445 /* so we don't accidently access them ... */
446 #define key_current_config NULL NULL
447 #define key_current_user NULL NULL
448 #define key_users NULL NULL
449 #define key_local_machine NULL NULL
450 #define key_classes_root NULL NULL
451 #define key_dyn_data NULL NULL
452 #define key_performance_data NULL NULL
454 /******************************************************************************
455 * split_keypath [Internal]
456 * splits the unicode string 'wp' into an array of strings.
457 * the array is allocated by this function.
458 * Free the array using FREE_KEY_PATH
460 * PARAMS
461 * wp [I] String to split up
462 * wpv [O] Array of pointers to strings
463 * wpc [O] Number of components
465 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
467 int i,j,len;
468 LPWSTR ws;
470 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
472 ws = HEAP_strdupW( SystemHeap, 0, wp );
474 /* We know we have at least one substring */
475 *wpc = 1;
477 /* Replace each backslash with NULL, and increment the count */
478 for (i=0;ws[i];i++) {
479 if (ws[i]=='\\') {
480 ws[i]=0;
481 (*wpc)++;
485 len = i;
487 /* Allocate the space for the array of pointers, leaving room for the
488 NULL at the end */
489 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
490 (*wpv)[0]= ws;
492 /* Assign each pointer to the appropriate character in the string */
493 j = 1;
494 for (i=1;i<len;i++)
495 if (ws[i-1]==0) {
496 (*wpv)[j++]=ws+i;
497 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
500 (*wpv)[j]=NULL;
502 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
507 /******************************************************************************
508 * REGISTRY_Init [Internal]
509 * Registry initialisation, allocates some default keys.
511 static void REGISTRY_Init(void) {
512 HKEY hkey;
513 char buf[200];
515 TRACE(reg,"(void)\n");
517 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
518 RegCloseKey(hkey);
520 /* This was an Open, but since it is called before the real registries
521 are loaded, it was changed to a Create - MTB 980507*/
522 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
523 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
524 RegCloseKey(hkey);
526 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
527 * CurrentVersion
528 * CurrentBuildNumber
529 * CurrentType
530 * string RegisteredOwner
531 * string RegisteredOrganization
534 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
535 * string SysContact
536 * string SysLocation
537 * SysServices
539 if (-1!=gethostname(buf,200)) {
540 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
541 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
542 RegCloseKey(hkey);
547 /************************ SAVE Registry Function ****************************/
549 #define REGISTRY_SAVE_VERSION 0x00000001
551 /* Registry saveformat:
552 * If you change it, increase above number by 1, which will flush
553 * old registry database files.
555 * Global:
556 * "WINE REGISTRY Version %d"
557 * subkeys....
558 * Subkeys:
559 * keyname
560 * valuename=lastmodified,type,data
561 * ...
562 * subkeys
563 * ...
564 * keyname,valuename,stringdata:
565 * the usual ascii characters from 0x00-0xff (well, not 0x00)
566 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
567 * ( "=\\\t" escaped in \uXXXX form.)
568 * type,lastmodified:
569 * int
571 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
573 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
574 * SaveOnlyUpdatedKeys=yes
577 /******************************************************************************
578 * _save_check_tainted [Internal]
580 static int _save_check_tainted( LPKEYSTRUCT lpkey )
582 int tainted;
584 if (!lpkey)
585 return 0;
586 if (lpkey->flags & REG_OPTION_TAINTED)
587 tainted = 1;
588 else
589 tainted = 0;
590 while (lpkey) {
591 if (_save_check_tainted(lpkey->nextsub)) {
592 lpkey->flags |= REG_OPTION_TAINTED;
593 tainted = 1;
595 lpkey = lpkey->next;
597 return tainted;
600 /******************************************************************************
601 * _save_USTRING [Internal]
603 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
605 LPWSTR s;
606 int doescape;
608 if (wstr==NULL)
609 return;
610 s=wstr;
611 while (*s) {
612 doescape=0;
613 if (*s>0xff)
614 doescape = 1;
615 if (*s=='\n')
616 doescape = 1;
617 if (escapeeq && *s=='=')
618 doescape = 1;
619 if (*s=='\\')
620 fputc(*s,F); /* if \\ then put it twice. */
621 if (doescape)
622 fprintf(F,"\\u%04x",*((unsigned short*)s));
623 else
624 fputc(*s,F);
625 s++;
629 /******************************************************************************
630 * _savesubkey [Internal]
632 * NOTES
633 * REG_MULTI_SZ is handled as binary (like in win95) (js)
635 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
637 LPKEYSTRUCT lpxkey;
638 int i,tabs,j;
640 lpxkey = lpkey;
641 while (lpxkey) {
642 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
643 (all || (lpxkey->flags & REG_OPTION_TAINTED))
645 for (tabs=level;tabs--;)
646 fputc('\t',F);
647 _save_USTRING(F,lpxkey->keyname,1);
648 fputs("\n",F);
649 for (i=0;i<lpxkey->nrofvalues;i++) {
650 LPKEYVALUE val=lpxkey->values+i;
652 for (tabs=level+1;tabs--;)
653 fputc('\t',F);
654 _save_USTRING(F,val->name,0);
655 fputc('=',F);
656 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
657 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
658 _save_USTRING(F,(LPWSTR)val->data,0);
659 else
660 for (j=0;j<val->len;j++)
661 fprintf(F,"%02x",*((unsigned char*)val->data+j));
662 fputs("\n",F);
664 /* descend recursively */
665 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
666 return 0;
668 lpxkey=lpxkey->next;
670 return 1;
674 /******************************************************************************
675 * _savesubreg [Internal]
677 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
679 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
680 _save_check_tainted(lpkey->nextsub);
681 return _savesubkey(F,lpkey->nextsub,0,all);
685 /******************************************************************************
686 * _savereg [Internal]
688 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
690 FILE *F;
692 F=fopen(fn,"w");
693 if (F==NULL) {
694 WARN(reg,"Couldn't open %s for writing: %s\n",
695 fn,strerror(errno)
697 return FALSE;
699 if (!_savesubreg(F,lpkey,all)) {
700 fclose(F);
701 unlink(fn);
702 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
703 return FALSE;
705 fclose(F);
706 return TRUE;
710 /******************************************************************************
711 * SHELL_SaveRegistry [Internal]
713 void SHELL_SaveRegistry( void )
715 char *fn;
716 struct passwd *pwd;
717 char buf[4];
718 HKEY hkey;
719 int all;
720 int usedCfgUser = 0;
721 int usedCfgLM = 0;
723 TRACE(reg,"(void)\n");
725 all=0;
726 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
728 strcpy(buf,"yes");
730 else
732 DWORD len,junk,type;
734 len=4;
735 if ( (ERROR_SUCCESS!=RegQueryValueExA(
736 hkey,
737 VAL_SAVEUPDATED,
738 &junk,
739 &type,
740 buf,
741 &len)) || (type!=REG_SZ))
743 strcpy(buf,"yes");
745 RegCloseKey(hkey);
748 if (lstrcmpiA(buf,"yes"))
749 all=1;
751 pwd=getpwuid(getuid());
752 if ( (pwd!=NULL) && (pwd->pw_dir!=NULL))
754 char *tmp;
756 * Save HKEY_CURRENT_USER
757 * Try first saving according to the defined location in .winerc
759 fn = xmalloc( MAX_PATHNAME_LEN );
760 if (PROFILE_GetWineIniString (
761 "Registry",
762 "UserFileName",
763 "",
764 fn,
765 MAX_PATHNAME_LEN - 1))
767 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
768 usedCfgUser = 1;
770 free (fn);
772 if (usedCfgUser != 1)
774 fn=(char*)xmalloc(
775 strlen(pwd->pw_dir) +
776 strlen(WINE_PREFIX) +
777 strlen(SAVE_CURRENT_USER) + 2 );
779 strcpy(fn,pwd->pw_dir);
780 strcat(fn,WINE_PREFIX);
782 /* create the directory. don't care about errorcodes. */
783 mkdir(fn,0755); /* drwxr-xr-x */
784 strcat(fn,"/"SAVE_CURRENT_USER);
786 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
787 strcpy(tmp,fn);
788 strcat(tmp,".tmp");
790 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
791 if (-1==rename(tmp,fn)) {
792 perror("rename tmp registry");
793 unlink(tmp);
796 free(tmp);
797 free(fn);
801 * Save HKEY_LOCAL_MACHINE
802 * Try first saving according to the defined location in .winerc
804 fn = xmalloc ( MAX_PATHNAME_LEN);
805 if (PROFILE_GetWineIniString (
806 "Registry",
807 "LocalMachineFileName",
808 "",
809 fn,
810 MAX_PATHNAME_LEN - 1))
812 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
813 usedCfgLM = 1;
815 free (fn);
817 if ( usedCfgLM != 1)
819 fn=(char*)xmalloc(
820 strlen(pwd->pw_dir)+
821 strlen(WINE_PREFIX)+
822 strlen(SAVE_LOCAL_MACHINE)+2);
824 strcpy(fn,pwd->pw_dir);
825 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
827 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
828 strcpy(tmp,fn);
829 strcat(tmp,".tmp");
831 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
832 if (-1==rename(tmp,fn)) {
833 perror("rename tmp registry");
834 unlink(tmp);
837 free(tmp);
838 free(fn);
842 * Save HKEY_USERS
844 fn=(char*)xmalloc(
845 strlen(pwd->pw_dir)+
846 strlen(WINE_PREFIX)+
847 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
849 strcpy(fn,pwd->pw_dir);
850 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
852 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
853 strcpy(tmp,fn);strcat(tmp,".tmp");
854 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
855 if (-1==rename(tmp,fn)) {
856 perror("rename tmp registry");
857 unlink(tmp);
860 free(tmp);
861 free(fn);
863 else
865 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
870 /************************ LOAD Registry Function ****************************/
874 /******************************************************************************
875 * _find_or_add_key [Internal]
877 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
879 LPKEYSTRUCT lpxkey,*lplpkey;
881 if ((!keyname) || (keyname[0]==0)) {
882 free(keyname);
883 return lpkey;
885 lplpkey= &(lpkey->nextsub);
886 lpxkey = *lplpkey;
887 while (lpxkey) {
888 if ( (lpxkey->keyname[0]==keyname[0]) &&
889 !lstrcmpiW(lpxkey->keyname,keyname)
891 break;
892 lplpkey = &(lpxkey->next);
893 lpxkey = *lplpkey;
895 if (lpxkey==NULL) {
896 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
897 lpxkey = *lplpkey;
898 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
899 lpxkey->keyname = keyname;
900 } else
901 free(keyname);
902 return lpxkey;
905 /******************************************************************************
906 * _find_or_add_value [Internal]
908 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
909 LPBYTE data, DWORD len, DWORD lastmodified )
911 LPKEYVALUE val=NULL;
912 int i;
914 if (name && !*name) {/* empty string equals default (NULL) value */
915 free(name);
916 name = NULL;
919 for (i=0;i<lpkey->nrofvalues;i++) {
920 val=lpkey->values+i;
921 if (name==NULL) {
922 if (val->name==NULL)
923 break;
924 } else {
925 if ( val->name!=NULL &&
926 val->name[0]==name[0] &&
927 !lstrcmpiW(val->name,name)
929 break;
932 if (i==lpkey->nrofvalues) {
933 lpkey->values = xrealloc(
934 lpkey->values,
935 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
937 val=lpkey->values+i;
938 memset(val,'\0',sizeof(KEYVALUE));
939 val->name = name;
940 } else {
941 if (name)
942 free(name);
944 if (val->lastmodified<lastmodified) {
945 val->lastmodified=lastmodified;
946 val->type = type;
947 val->len = len;
948 if (val->data)
949 free(val->data);
950 val->data = data;
951 } else
952 free(data);
956 /******************************************************************************
957 * _wine_read_line [Internal]
959 * reads a line including dynamically enlarging the readbuffer and throwing
960 * away comments
962 static int _wine_read_line( FILE *F, char **buf, int *len )
964 char *s,*curread;
965 int mylen,curoff;
967 curread = *buf;
968 mylen = *len;
969 **buf = '\0';
970 while (1) {
971 while (1) {
972 s=fgets(curread,mylen,F);
973 if (s==NULL)
974 return 0; /* EOF */
975 if (NULL==(s=strchr(curread,'\n'))) {
976 /* buffer wasn't large enough */
977 curoff = strlen(*buf);
978 *buf = xrealloc(*buf,*len*2);
979 curread = *buf + curoff;
980 mylen = *len; /* we filled up the buffer and
981 * got new '*len' bytes to fill
983 *len = *len * 2;
984 } else {
985 *s='\0';
986 break;
989 /* throw away comments */
990 if (**buf=='#' || **buf==';') {
991 curread = *buf;
992 mylen = *len;
993 continue;
995 if (s) /* got end of line */
996 break;
998 return 1;
1002 /******************************************************************************
1003 * _wine_read_USTRING [Internal]
1005 * converts a char* into a UNICODE string (up to a special char)
1006 * and returns the position exactly after that string
1008 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1010 char *s;
1011 LPWSTR ws;
1013 /* read up to "=" or "\0" or "\n" */
1014 s = buf;
1015 if (*s == '=') {
1016 /* empty string is the win3.1 default value(NULL)*/
1017 *str = NULL;
1018 return s;
1020 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1021 ws = *str;
1022 while (*s && (*s!='\n') && (*s!='=')) {
1023 if (*s!='\\')
1024 *ws++=*((unsigned char*)s++);
1025 else {
1026 s++;
1027 if (!*s) {
1028 /* Dangling \ ... may only happen if a registry
1029 * write was short. FIXME: What do to?
1031 break;
1033 if (*s=='\\') {
1034 *ws++='\\';
1035 s++;
1036 continue;
1038 if (*s!='u') {
1039 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1040 *ws++='\\';
1041 *ws++=*s++;
1042 } else {
1043 char xbuf[5];
1044 int wc;
1046 s++;
1047 memcpy(xbuf,s,4);xbuf[4]='\0';
1048 if (!sscanf(xbuf,"%x",&wc))
1049 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
1050 s+=4;
1051 *ws++ =(unsigned short)wc;
1055 *ws = 0;
1056 ws = *str;
1057 if (*ws)
1058 *str = strdupW(*str);
1059 else
1060 *str = NULL;
1061 free(ws);
1062 return s;
1066 /******************************************************************************
1067 * _wine_loadsubkey [Internal]
1069 * NOTES
1070 * It seems like this is returning a boolean. Should it?
1072 * RETURNS
1073 * Success: 1
1074 * Failure: 0
1076 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1077 int *buflen, DWORD optflag )
1079 LPKEYSTRUCT lpxkey;
1080 int i;
1081 char *s;
1082 LPWSTR name;
1084 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1085 *buflen, optflag);
1087 lpkey->flags |= optflag;
1089 /* Good. We already got a line here ... so parse it */
1090 lpxkey = NULL;
1091 while (1) {
1092 i=0;s=*buf;
1093 while (*s=='\t') {
1094 s++;
1095 i++;
1097 if (i>level) {
1098 if (lpxkey==NULL) {
1099 WARN(reg,"Got a subhierarchy without resp. key?\n");
1100 return 0;
1102 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1103 continue;
1106 /* let the caller handle this line */
1107 if (i<level || **buf=='\0')
1108 return 1;
1110 /* it can be: a value or a keyname. Parse the name first */
1111 s=_wine_read_USTRING(s,&name);
1113 /* switch() default: hack to avoid gotos */
1114 switch (0) {
1115 default:
1116 if (*s=='\0') {
1117 lpxkey=_find_or_add_key(lpkey,name);
1118 } else {
1119 LPBYTE data;
1120 int len,lastmodified,type;
1122 if (*s!='=') {
1123 WARN(reg,"Unexpected character: %c\n",*s);
1124 break;
1126 s++;
1127 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1128 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1129 break;
1131 /* skip the 2 , */
1132 s=strchr(s,',');s++;
1133 s=strchr(s,',');s++;
1134 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1135 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1136 if (data)
1137 len = lstrlenW((LPWSTR)data)*2+2;
1138 else
1139 len = 0;
1140 } else {
1141 len=strlen(s)/2;
1142 data = (LPBYTE)xmalloc(len+1);
1143 for (i=0;i<len;i++) {
1144 data[i]=0;
1145 if (*s>='0' && *s<='9')
1146 data[i]=(*s-'0')<<4;
1147 if (*s>='a' && *s<='f')
1148 data[i]=(*s-'a'+'\xa')<<4;
1149 if (*s>='A' && *s<='F')
1150 data[i]=(*s-'A'+'\xa')<<4;
1151 s++;
1152 if (*s>='0' && *s<='9')
1153 data[i]|=*s-'0';
1154 if (*s>='a' && *s<='f')
1155 data[i]|=*s-'a'+'\xa';
1156 if (*s>='A' && *s<='F')
1157 data[i]|=*s-'A'+'\xa';
1158 s++;
1161 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1164 /* read the next line */
1165 if (!_wine_read_line(F,buf,buflen))
1166 return 1;
1168 return 1;
1172 /******************************************************************************
1173 * _wine_loadsubreg [Internal]
1175 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1177 int ver;
1178 char *buf;
1179 int buflen;
1181 buf=xmalloc(10);buflen=10;
1182 if (!_wine_read_line(F,&buf,&buflen)) {
1183 free(buf);
1184 return 0;
1186 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1187 free(buf);
1188 return 0;
1190 if (ver!=REGISTRY_SAVE_VERSION) {
1191 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1192 free(buf);
1193 return 0;
1195 if (!_wine_read_line(F,&buf,&buflen)) {
1196 free(buf);
1197 return 0;
1199 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1200 free(buf);
1201 return 0;
1203 free(buf);
1204 return 1;
1208 /******************************************************************************
1209 * _wine_loadreg [Internal]
1211 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1213 FILE *F;
1215 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1217 F = fopen(fn,"rb");
1218 if (F==NULL) {
1219 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1220 return;
1222 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1223 fclose(F);
1224 unlink(fn);
1225 return;
1227 fclose(F);
1230 /******************************************************************************
1231 * _flush_registry [Internal]
1233 * This function allow to flush section of the internal registry. It is mainly
1234 * implements to fix a problem with the global HKU and the local HKU.
1235 * Those two files are read to build the HKU\.Default branch to finaly copy
1236 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1237 * all the global HKU are saved onto the user's personal version of HKU hive.
1238 * which is bad...
1241 /* Forward declaration of recusive agent */
1242 static void _flush_reg(LPKEYSTRUCT from);
1244 static void _flush_registry( LPKEYSTRUCT from )
1246 /* make sure we have something... */
1247 if (from == NULL)
1248 return;
1250 /* Launch the recusive agent on sub branches */
1251 _flush_reg( from->nextsub );
1252 _flush_reg( from->next );
1254 /* Initialize pointers */
1255 from->nextsub = NULL;
1256 from->next = NULL;
1258 static void _flush_reg( LPKEYSTRUCT from )
1260 int j;
1262 /* make sure we have something... */
1263 if (from == NULL)
1264 return;
1267 * do the same for the child keys
1269 if (from->nextsub != NULL)
1270 _flush_reg(from->nextsub);
1273 * do the same for the sibling keys
1275 if (from->next != NULL)
1276 _flush_reg(from->next);
1279 * iterate through this key's values and delete them
1281 for (j=0;j<from->nrofvalues;j++)
1283 free( (from->values+j)->name);
1284 free( (from->values+j)->data);
1288 * free the structure
1290 if ( from != NULL )
1291 free(from);
1295 /******************************************************************************
1296 * _copy_registry [Internal]
1298 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1300 LPKEYSTRUCT lpxkey;
1301 int j;
1302 LPKEYVALUE valfrom;
1304 from=from->nextsub;
1305 while (from) {
1306 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1308 for (j=0;j<from->nrofvalues;j++) {
1309 LPWSTR name;
1310 LPBYTE data;
1312 valfrom = from->values+j;
1313 name=valfrom->name;
1314 if (name) name=strdupW(name);
1315 data=(LPBYTE)xmalloc(valfrom->len);
1316 memcpy(data,valfrom->data,valfrom->len);
1318 _find_or_add_value(
1319 lpxkey,
1320 name,
1321 valfrom->type,
1322 data,
1323 valfrom->len,
1324 valfrom->lastmodified
1327 _copy_registry(from,lpxkey);
1328 from = from->next;
1333 /* WINDOWS 95 REGISTRY LOADER */
1335 * Structure of a win95 registry database.
1336 * main header:
1337 * 0 : "CREG" - magic
1338 * 4 : DWORD version
1339 * 8 : DWORD offset_of_RGDB_part
1340 * 0C..0F: ? (someone fill in please)
1341 * 10: WORD number of RGDB blocks
1342 * 12: WORD ?
1343 * 14: WORD always 0000?
1344 * 16: WORD always 0001?
1345 * 18..1F: ? (someone fill in please)
1347 * 20: RGKN_section:
1348 * header:
1349 * 0 : "RGKN" - magic
1350 * 4 : DWORD offset to first RGDB section
1351 * 8 : DWORD offset to the root record
1352 * C..0x1B: ? (fill in)
1353 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1355 * Disk Key Entry Structure:
1356 * 00: DWORD - Free entry indicator(?)
1357 * 04: DWORD - Hash = sum of bytes of keyname
1358 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1359 * 0C: DWORD - disk address of PreviousLevel Key.
1360 * 10: DWORD - disk address of Next Sublevel Key.
1361 * 14: DWORD - disk address of Next Key (on same level).
1362 * DKEP>18: WORD - Nr, Low Significant part.
1363 * 1A: WORD - Nr, High Significant part.
1365 * The disk address always points to the nr part of the previous key entry
1366 * of the referenced key. Don't ask me why, or even if I got this correct
1367 * from staring at 1kg of hexdumps. (DKEP)
1369 * The High significant part of the structure seems to equal the number
1370 * of the RGDB section. The low significant part is a unique ID within
1371 * that RGDB section
1373 * There are two minor corrections to the position of that structure.
1374 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1375 * the DKE reread from there.
1376 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1377 * CPS - I have not experienced the above phenomenon in my registry files
1379 * RGDB_section:
1380 * 00: "RGDB" - magic
1381 * 04: DWORD offset to next RGDB section
1382 * 08: DWORD ?
1383 * 0C: WORD always 000d?
1384 * 0E: WORD RGDB block number
1385 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1386 * 14..1F: ?
1387 * 20.....: disk keys
1389 * disk key:
1390 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1391 * 08: WORD nrLS - low significant part of NR
1392 * 0A: WORD nrHS - high significant part of NR
1393 * 0C: DWORD bytesused - bytes used in this structure.
1394 * 10: WORD name_len - length of name in bytes. without \0
1395 * 12: WORD nr_of_values - number of values.
1396 * 14: char name[name_len] - name string. No \0.
1397 * 14+name_len: disk values
1398 * nextkeyoffset: ... next disk key
1400 * disk value:
1401 * 00: DWORD type - value type (hmm, could be WORD too)
1402 * 04: DWORD - unknown, usually 0
1403 * 08: WORD namelen - length of Name. 0 means name=NULL
1404 * 0C: WORD datalen - length of Data.
1405 * 10: char name[namelen] - name, no \0
1406 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1407 * 10+namelen+datalen: next values or disk key
1409 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1410 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1411 * structure) and reading another RGDB_section.
1412 * repeat until end of file.
1414 * An interesting relationship exists in RGDB_section. The value at offset
1415 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1416 * idea at the moment what this means. (Kevin Cozens)
1418 * FIXME: this description needs some serious help, yes.
1421 struct _w95keyvalue {
1422 unsigned long type;
1423 unsigned short datalen;
1424 char *name;
1425 unsigned char *data;
1426 unsigned long x1;
1427 int lastmodified;
1430 struct _w95key {
1431 char *name;
1432 int nrofvals;
1433 struct _w95keyvalue *values;
1434 struct _w95key *prevlvl;
1435 struct _w95key *nextsub;
1436 struct _w95key *next;
1440 struct _w95_info {
1441 char *rgknbuffer;
1442 int rgknsize;
1443 char *rgdbbuffer;
1444 int rgdbsize;
1445 int depth;
1446 int lastmodified;
1450 /******************************************************************************
1451 * _w95_processKey [Internal]
1453 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1454 int nrLS, int nrMS, struct _w95_info *info )
1457 /* Disk Key Header structure (RGDB part) */
1458 struct dkh {
1459 unsigned long nextkeyoff;
1460 unsigned short nrLS;
1461 unsigned short nrMS;
1462 unsigned long bytesused;
1463 unsigned short keynamelen;
1464 unsigned short values;
1465 unsigned long xx1;
1466 /* keyname */
1467 /* disk key values or nothing */
1469 /* Disk Key Value structure */
1470 struct dkv {
1471 unsigned long type;
1472 unsigned long x1;
1473 unsigned short valnamelen;
1474 unsigned short valdatalen;
1475 /* valname, valdata */
1479 struct dkh dkh;
1480 int bytesread = 0;
1481 char *rgdbdata = info->rgdbbuffer;
1482 int nbytes = info->rgdbsize;
1483 char *curdata = rgdbdata;
1484 char *end = rgdbdata + nbytes;
1485 int off_next_rgdb;
1486 char *next = rgdbdata;
1487 int nrgdb, i;
1488 LPKEYSTRUCT lpxkey;
1490 do {
1491 curdata = next;
1492 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1494 memcpy(&off_next_rgdb,curdata+4,4);
1495 next = curdata + off_next_rgdb;
1496 nrgdb = (int) *((short *)curdata + 7);
1498 } while (nrgdb != nrMS && (next < end));
1500 /* curdata now points to the start of the right RGDB section */
1501 curdata += 0x20;
1503 #define XREAD(whereto,len) \
1504 if ((curdata + len) <= end) {\
1505 memcpy(whereto,curdata,len);\
1506 curdata+=len;\
1507 bytesread+=len;\
1510 while (curdata < next) {
1511 struct dkh *xdkh = (struct dkh*)curdata;
1513 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1514 if (xdkh->nrLS == nrLS) {
1515 memcpy(&dkh,xdkh,sizeof(dkh));
1516 curdata += sizeof(dkh);
1517 break;
1519 curdata += xdkh->nextkeyoff;
1522 if (dkh.nrLS != nrLS) return (NULL);
1524 if (nrgdb != dkh.nrMS)
1525 return (NULL);
1527 assert((dkh.keynamelen<2) || curdata[0]);
1528 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1529 curdata += dkh.keynamelen;
1531 for (i=0;i< dkh.values; i++) {
1532 struct dkv dkv;
1533 LPBYTE data;
1534 int len;
1535 LPWSTR name;
1537 XREAD(&dkv,sizeof(dkv));
1539 name = strcvtA2W(curdata, dkv.valnamelen);
1540 curdata += dkv.valnamelen;
1542 if ((1 << dkv.type) & UNICONVMASK) {
1543 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1544 len = 2*(dkv.valdatalen + 1);
1545 } else {
1546 /* I don't think we want to NULL terminate all data */
1547 data = xmalloc(dkv.valdatalen);
1548 memcpy (data, curdata, dkv.valdatalen);
1549 len = dkv.valdatalen;
1552 curdata += dkv.valdatalen;
1554 _find_or_add_value(
1555 lpxkey,
1556 name,
1557 dkv.type,
1558 data,
1559 len,
1560 info->lastmodified
1563 return (lpxkey);
1566 /******************************************************************************
1567 * _w95_walkrgkn [Internal]
1569 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1570 struct _w95_info *info )
1573 /* Disk Key Entry structure (RGKN part) */
1574 struct dke {
1575 unsigned long x1;
1576 unsigned long x2;
1577 unsigned long x3;/*usually 0xFFFFFFFF */
1578 unsigned long prevlvl;
1579 unsigned long nextsub;
1580 unsigned long next;
1581 unsigned short nrLS;
1582 unsigned short nrMS;
1583 } *dke = (struct dke *)off;
1584 LPKEYSTRUCT lpxkey;
1586 if (dke == NULL) {
1587 dke = (struct dke *) ((char *)info->rgknbuffer);
1590 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1591 /* XXX <-- This is a hack*/
1592 if (!lpxkey) {
1593 lpxkey = prevkey;
1596 if (dke->nextsub != -1 &&
1597 ((dke->nextsub - 0x20) < info->rgknsize)
1598 && (dke->nextsub > 0x20)) {
1600 _w95_walkrgkn(lpxkey,
1601 info->rgknbuffer + dke->nextsub - 0x20,
1602 info);
1605 if (dke->next != -1 &&
1606 ((dke->next - 0x20) < info->rgknsize) &&
1607 (dke->next > 0x20)) {
1608 _w95_walkrgkn(prevkey,
1609 info->rgknbuffer + dke->next - 0x20,
1610 info);
1613 return;
1617 /******************************************************************************
1618 * _w95_loadreg [Internal]
1620 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1622 HFILE hfd;
1623 char magic[5];
1624 unsigned long where,version,rgdbsection,end;
1625 struct _w95_info info;
1626 OFSTRUCT ofs;
1627 BY_HANDLE_FILE_INFORMATION hfdinfo;
1629 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1630 hfd=OpenFile(fn,&ofs,OF_READ);
1631 if (hfd==HFILE_ERROR)
1632 return;
1633 magic[4]=0;
1634 if (4!=_lread(hfd,magic,4))
1635 return;
1636 if (strcmp(magic,"CREG")) {
1637 WARN(reg,"%s is not a w95 registry.\n",fn);
1638 return;
1640 if (4!=_lread(hfd,&version,4))
1641 return;
1642 if (4!=_lread(hfd,&rgdbsection,4))
1643 return;
1644 if (-1==_llseek(hfd,0x20,SEEK_SET))
1645 return;
1646 if (4!=_lread(hfd,magic,4))
1647 return;
1648 if (strcmp(magic,"RGKN")) {
1649 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1650 return;
1653 /* STEP 1: Keylink structures */
1654 if (-1==_llseek(hfd,0x40,SEEK_SET))
1655 return;
1656 where = 0x40;
1657 end = rgdbsection;
1659 info.rgknsize = end - where;
1660 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1661 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1662 return;
1664 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1665 return;
1667 end = hfdinfo.nFileSizeLow;
1668 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1670 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1671 return;
1673 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1674 info.rgdbsize = end - rgdbsection;
1676 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1677 return;
1678 _lclose(hfd);
1680 _w95_walkrgkn(lpkey, NULL, &info);
1682 free (info.rgdbbuffer);
1683 free (info.rgknbuffer);
1687 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1690 reghack - windows 3.11 registry data format demo program.
1692 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1693 a combined hash table and tree description, and finally a text table.
1695 The header is obvious from the struct header. The taboff1 and taboff2
1696 fields are always 0x20, and their usage is unknown.
1698 The 8-byte entry table has various entry types.
1700 tabent[0] is a root index. The second word has the index of the root of
1701 the directory.
1702 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1703 the index of the key/value that has that hash. Data with the same
1704 hash value are on a circular list. The other three words in the
1705 hash entry are always zero.
1706 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1707 entry: dirent and keyent/valent. They are identified by context.
1708 tabent[freeidx] is the first free entry. The first word in a free entry
1709 is the index of the next free entry. The last has 0 as a link.
1710 The other three words in the free list are probably irrelevant.
1712 Entries in text table are preceeded by a word at offset-2. This word
1713 has the value (2*index)+1, where index is the referring keyent/valent
1714 entry in the table. I have no suggestion for the 2* and the +1.
1715 Following the word, there are N bytes of data, as per the keyent/valent
1716 entry length. The offset of the keyent/valent entry is from the start
1717 of the text table to the first data byte.
1719 This information is not available from Microsoft. The data format is
1720 deduced from the reg.dat file by me. Mistakes may
1721 have been made. I claim no rights and give no guarantees for this program.
1723 Tor Sjøwall, tor@sn.no
1726 /* reg.dat header format */
1727 struct _w31_header {
1728 char cookie[8]; /* 'SHCC3.10' */
1729 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1730 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1731 unsigned long tabcnt; /* number of entries in index table */
1732 unsigned long textoff; /* offset of text part */
1733 unsigned long textsize; /* byte size of text part */
1734 unsigned short hashsize; /* hash size */
1735 unsigned short freeidx; /* free index */
1738 /* generic format of table entries */
1739 struct _w31_tabent {
1740 unsigned short w0, w1, w2, w3;
1743 /* directory tabent: */
1744 struct _w31_dirent {
1745 unsigned short sibling_idx; /* table index of sibling dirent */
1746 unsigned short child_idx; /* table index of child dirent */
1747 unsigned short key_idx; /* table index of key keyent */
1748 unsigned short value_idx; /* table index of value valent */
1751 /* key tabent: */
1752 struct _w31_keyent {
1753 unsigned short hash_idx; /* hash chain index for string */
1754 unsigned short refcnt; /* reference count */
1755 unsigned short length; /* length of string */
1756 unsigned short string_off; /* offset of string in text table */
1759 /* value tabent: */
1760 struct _w31_valent {
1761 unsigned short hash_idx; /* hash chain index for string */
1762 unsigned short refcnt; /* reference count */
1763 unsigned short length; /* length of string */
1764 unsigned short string_off; /* offset of string in text table */
1767 /* recursive helper function to display a directory tree */
1768 void
1769 __w31_dumptree( unsigned short idx,
1770 unsigned char *txt,
1771 struct _w31_tabent *tab,
1772 struct _w31_header *head,
1773 LPKEYSTRUCT lpkey,
1774 time_t lastmodified,
1775 int level
1777 struct _w31_dirent *dir;
1778 struct _w31_keyent *key;
1779 struct _w31_valent *val;
1780 LPKEYSTRUCT xlpkey = NULL;
1781 LPWSTR name,value;
1782 static char tail[400];
1784 while (idx!=0) {
1785 dir=(struct _w31_dirent*)&tab[idx];
1787 if (dir->key_idx) {
1788 key = (struct _w31_keyent*)&tab[dir->key_idx];
1790 memcpy(tail,&txt[key->string_off],key->length);
1791 tail[key->length]='\0';
1792 /* all toplevel entries AND the entries in the
1793 * toplevel subdirectory belong to \SOFTWARE\Classes
1795 if (!level && !lstrcmpA(tail,".classes")) {
1796 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1797 idx=dir->sibling_idx;
1798 continue;
1800 name=strdupA2W(tail);
1802 xlpkey=_find_or_add_key(lpkey,name);
1804 /* only add if leaf node or valued node */
1805 if (dir->value_idx!=0||dir->child_idx==0) {
1806 if (dir->value_idx) {
1807 val=(struct _w31_valent*)&tab[dir->value_idx];
1808 memcpy(tail,&txt[val->string_off],val->length);
1809 tail[val->length]='\0';
1810 value=strdupA2W(tail);
1811 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1814 } else {
1815 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1817 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1818 idx=dir->sibling_idx;
1823 /******************************************************************************
1824 * _w31_loadreg [Internal]
1826 void _w31_loadreg(void) {
1827 HFILE hf;
1828 struct _w31_header head;
1829 struct _w31_tabent *tab;
1830 unsigned char *txt;
1831 int len;
1832 OFSTRUCT ofs;
1833 BY_HANDLE_FILE_INFORMATION hfinfo;
1834 time_t lastmodified;
1835 LPKEYSTRUCT lpkey;
1837 TRACE(reg,"(void)\n");
1839 hf = OpenFile("reg.dat",&ofs,OF_READ);
1840 if (hf==HFILE_ERROR)
1841 return;
1843 /* read & dump header */
1844 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1845 ERR(reg, "reg.dat is too short.\n");
1846 _lclose(hf);
1847 return;
1849 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1850 ERR(reg, "reg.dat has bad signature.\n");
1851 _lclose(hf);
1852 return;
1855 len = head.tabcnt * sizeof(struct _w31_tabent);
1856 /* read and dump index table */
1857 tab = xmalloc(len);
1858 if (len!=_lread(hf,tab,len)) {
1859 ERR(reg,"couldn't read %d bytes.\n",len);
1860 free(tab);
1861 _lclose(hf);
1862 return;
1865 /* read text */
1866 txt = xmalloc(head.textsize);
1867 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1868 ERR(reg,"couldn't seek to textblock.\n");
1869 free(tab);
1870 free(txt);
1871 _lclose(hf);
1872 return;
1874 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1875 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1876 free(tab);
1877 free(txt);
1878 _lclose(hf);
1879 return;
1882 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1883 ERR(reg,"GetFileInformationByHandle failed?.\n");
1884 free(tab);
1885 free(txt);
1886 _lclose(hf);
1887 return;
1889 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1890 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1891 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1892 free(tab);
1893 free(txt);
1894 _lclose(hf);
1895 return;
1899 /**********************************************************************************
1900 * SHELL_LoadRegistry [Internal]
1902 void SHELL_LoadRegistry( void )
1904 char *fn;
1905 struct passwd *pwd;
1906 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1907 HKEY hkey;
1909 TRACE(reg,"(void)\n");
1911 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1912 HKU = lookup_hkey(HKEY_USERS);
1913 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1915 /* Load windows 3.1 entries */
1916 _w31_loadreg();
1917 /* Load windows 95 entries */
1918 _w95_loadreg("C:\\system.1st", HKLM);
1919 _w95_loadreg("system.dat", HKLM);
1920 _w95_loadreg("user.dat", HKU);
1923 * Load the global HKU hive directly from /usr/local/etc
1925 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1928 * Load the global machine defaults directly form /usr/local/etc
1930 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1932 /* Get current user info */
1933 pwd=getpwuid(getuid());
1936 * Load the user saved registries
1938 if ( (pwd != NULL) &&
1939 (pwd->pw_dir != NULL) )
1942 * Load user's personal versions of global HKU/.Default keys
1944 fn=(char*)xmalloc(
1945 strlen(pwd->pw_dir)+
1946 strlen(WINE_PREFIX)+
1947 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1949 strcpy(fn, pwd->pw_dir);
1950 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1951 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1952 free(fn);
1955 * Load HKCU, attempt to get the registry location from the config
1956 * file first, if exist, load and keep going.
1958 fn = xmalloc( MAX_PATHNAME_LEN );
1959 if ( PROFILE_GetWineIniString(
1960 "Registry",
1961 "UserFileName",
1962 "",
1963 fn,
1964 MAX_PATHNAME_LEN - 1))
1966 _wine_loadreg(HKCU,fn,0);
1968 free (fn);
1970 fn=(char*)xmalloc(
1971 strlen(pwd->pw_dir)+
1972 strlen(WINE_PREFIX)+
1973 strlen(SAVE_CURRENT_USER)+2);
1975 strcpy(fn, pwd->pw_dir);
1976 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1977 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1978 free(fn);
1981 * Load HKLM, attempt to get the registry location from the config
1982 * file first, if exist, load and keep going.
1984 fn = xmalloc ( MAX_PATHNAME_LEN);
1985 if ( PROFILE_GetWineIniString(
1986 "Registry",
1987 "LocalMachineFileName",
1988 "",
1989 fn,
1990 MAX_PATHNAME_LEN - 1))
1992 _wine_loadreg(HKLM, fn, 0);
1994 free(fn);
1996 fn=(char*)xmalloc(
1997 strlen(pwd->pw_dir)+
1998 strlen(WINE_PREFIX)+
1999 strlen(SAVE_LOCAL_MACHINE)+2);
2001 strcpy(fn,pwd->pw_dir);
2002 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2003 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2004 free(fn);
2006 else
2008 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
2012 * Obtain the handle of the HKU\.Default key.
2013 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2015 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2016 lpkey = lookup_hkey(hkey);
2017 if(!lpkey)
2018 WARN(reg,"Could not create global user default key\n");
2019 else
2020 _copy_registry(lpkey, HKCU );
2022 RegCloseKey(hkey);
2025 * Since HKU is built from the global HKU and the local user HKU file we must
2026 * flush the HKU tree we have built at this point otherwise the part brought
2027 * in from the global HKU is saved into the local HKU. To avoid this
2028 * useless dupplication of HKU keys we reread the local HKU key.
2031 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2032 _flush_registry(HKU);
2034 /* Reload user's local HKU hive */
2035 fn=(char*)xmalloc(
2036 strlen(pwd->pw_dir)+
2037 strlen(WINE_PREFIX)+
2038 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2040 strcpy(fn,pwd->pw_dir);
2041 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2043 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2045 free(fn);
2048 * Make sure the update mode is there
2050 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2052 DWORD junk,type,len;
2053 char data[5];
2055 len=4;
2056 if (( RegQueryValueExA(
2057 hkey,
2058 VAL_SAVEUPDATED,
2059 &junk,
2060 &type,
2061 data,
2062 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2064 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2067 RegCloseKey(hkey);
2072 /********************* API FUNCTIONS ***************************************/
2074 * Open Keys.
2076 * All functions are stubs to RegOpenKeyEx32W where all the
2077 * magic happens.
2079 * Callpath:
2080 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2081 * RegOpenKey32W -> RegOpenKeyEx32W
2085 /******************************************************************************
2086 * RegOpenKeyEx32W [ADVAPI32.150]
2087 * Opens the specified key
2089 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2091 * PARAMS
2092 * hkey [I] Handle of open key
2093 * lpszSubKey [I] Name of subkey to open
2094 * dwReserved [I] Reserved - must be zero
2095 * samDesired [I] Security access mask
2096 * retkey [O] Address of handle of open key
2098 * RETURNS
2099 * Success: ERROR_SUCCESS
2100 * Failure: Error code
2102 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2103 REGSAM samDesired, LPHKEY retkey )
2105 LPKEYSTRUCT lpNextKey,lpxkey;
2106 LPWSTR *wps;
2107 int wpc,i;
2109 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2110 samDesired,retkey);
2112 lpNextKey = lookup_hkey( hkey );
2113 if (!lpNextKey)
2114 return ERROR_INVALID_HANDLE;
2116 if (!lpszSubKey || !*lpszSubKey) {
2117 /* Either NULL or pointer to empty string, so return a new handle
2118 to the original hkey */
2119 currenthandle += 2;
2120 add_handle(currenthandle,lpNextKey,samDesired);
2121 *retkey=currenthandle;
2122 return ERROR_SUCCESS;
2125 if (lpszSubKey[0] == '\\') {
2126 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2127 return ERROR_BAD_PATHNAME;
2130 split_keypath(lpszSubKey,&wps,&wpc);
2131 i = 0;
2132 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2133 lpxkey = lpNextKey;
2135 while (wps[i]) {
2136 lpxkey=lpNextKey->nextsub;
2137 while (lpxkey) {
2138 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2139 break;
2141 lpxkey=lpxkey->next;
2144 if (!lpxkey) {
2145 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
2146 FREE_KEY_PATH;
2147 return ERROR_FILE_NOT_FOUND;
2149 i++;
2150 lpNextKey = lpxkey;
2153 currenthandle += 2;
2154 add_handle(currenthandle,lpxkey,samDesired);
2155 *retkey = currenthandle;
2156 TRACE(reg," Returning %x\n", currenthandle);
2157 FREE_KEY_PATH;
2158 return ERROR_SUCCESS;
2162 /******************************************************************************
2163 * RegOpenKeyEx32A [ADVAPI32.149]
2165 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2166 REGSAM samDesired, LPHKEY retkey )
2168 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2169 DWORD ret;
2171 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2172 samDesired,retkey);
2173 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2174 free(lpszSubKeyW);
2175 return ret;
2179 /******************************************************************************
2180 * RegOpenKey32W [ADVAPI32.151]
2182 * PARAMS
2183 * hkey [I] Handle of open key
2184 * lpszSubKey [I] Address of name of subkey to open
2185 * retkey [O] Address of handle of open key
2187 * RETURNS
2188 * Success: ERROR_SUCCESS
2189 * Failure: Error code
2191 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2193 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2194 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2198 /******************************************************************************
2199 * RegOpenKey32A [ADVAPI32.148]
2201 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2203 DWORD ret;
2204 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2205 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2206 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2207 free(lpszSubKeyW);
2208 return ret;
2212 /******************************************************************************
2213 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2215 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2217 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2218 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2223 * Create keys
2225 * All those functions convert their respective
2226 * arguments and call RegCreateKeyExW at the end.
2228 * We stay away from the Ex functions as long as possible because there are
2229 * differences in the return values
2231 * Callpath:
2232 * RegCreateKeyEx32A \
2233 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2237 /******************************************************************************
2238 * RegCreateKeyEx32W [ADVAPI32.131]
2240 * PARAMS
2241 * hkey [I] Handle of an open key
2242 * lpszSubKey [I] Address of subkey name
2243 * dwReserved [I] Reserved - must be 0
2244 * lpszClass [I] Address of class string
2245 * fdwOptions [I] Special options flag
2246 * samDesired [I] Desired security access
2247 * lpSecAttribs [I] Address of key security structure
2248 * retkey [O] Address of buffer for opened handle
2249 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2251 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2252 DWORD dwReserved, LPWSTR lpszClass,
2253 DWORD fdwOptions, REGSAM samDesired,
2254 LPSECURITY_ATTRIBUTES lpSecAttribs,
2255 LPHKEY retkey, LPDWORD lpDispos )
2257 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2258 LPWSTR *wps;
2259 int wpc,i;
2261 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2262 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2263 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2265 lpNextKey = lookup_hkey(hkey);
2266 if (!lpNextKey)
2267 return ERROR_INVALID_HANDLE;
2269 /* Check for valid options */
2270 switch(fdwOptions) {
2271 case REG_OPTION_NON_VOLATILE:
2272 case REG_OPTION_VOLATILE:
2273 case REG_OPTION_BACKUP_RESTORE:
2274 break;
2275 default:
2276 return ERROR_INVALID_PARAMETER;
2279 /* Sam has to be a combination of the following */
2280 if (!(samDesired &
2281 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2282 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2283 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2284 return ERROR_INVALID_PARAMETER;
2286 if (!lpszSubKey || !*lpszSubKey) {
2287 currenthandle += 2;
2288 add_handle(currenthandle,lpNextKey,samDesired);
2289 *retkey=currenthandle;
2290 TRACE(reg, "Returning %x\n", currenthandle);
2291 lpNextKey->flags|=REG_OPTION_TAINTED;
2292 return ERROR_SUCCESS;
2295 if (lpszSubKey[0] == '\\') {
2296 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2297 return ERROR_BAD_PATHNAME;
2300 split_keypath(lpszSubKey,&wps,&wpc);
2301 i = 0;
2302 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2303 lpxkey = lpNextKey;
2304 while (wps[i]) {
2305 lpxkey=lpNextKey->nextsub;
2306 while (lpxkey) {
2307 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2308 break;
2309 lpxkey=lpxkey->next;
2311 if (!lpxkey)
2312 break;
2313 i++;
2314 lpNextKey = lpxkey;
2316 if (lpxkey) {
2317 currenthandle += 2;
2318 add_handle(currenthandle,lpxkey,samDesired);
2319 lpxkey->flags |= REG_OPTION_TAINTED;
2320 *retkey = currenthandle;
2321 TRACE(reg, "Returning %x\n", currenthandle);
2322 if (lpDispos)
2323 *lpDispos = REG_OPENED_EXISTING_KEY;
2324 FREE_KEY_PATH;
2325 return ERROR_SUCCESS;
2328 /* Good. Now the hard part */
2329 while (wps[i]) {
2330 lplpPrevKey = &(lpNextKey->nextsub);
2331 lpxkey = *lplpPrevKey;
2332 while (lpxkey) {
2333 lplpPrevKey = &(lpxkey->next);
2334 lpxkey = *lplpPrevKey;
2336 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2337 if (!*lplpPrevKey) {
2338 FREE_KEY_PATH;
2339 TRACE(reg, "Returning OUTOFMEMORY\n");
2340 return ERROR_OUTOFMEMORY;
2342 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2343 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2344 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2345 (*lplpPrevKey)->next = NULL;
2346 (*lplpPrevKey)->nextsub = NULL;
2347 (*lplpPrevKey)->values = NULL;
2348 (*lplpPrevKey)->nrofvalues = 0;
2349 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2350 if (lpszClass)
2351 (*lplpPrevKey)->class = strdupW(lpszClass);
2352 else
2353 (*lplpPrevKey)->class = NULL;
2354 lpNextKey = *lplpPrevKey;
2355 i++;
2357 currenthandle += 2;
2358 add_handle(currenthandle,lpNextKey,samDesired);
2360 /*FIXME: flag handling correct? */
2361 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2362 if (lpszClass)
2363 lpNextKey->class = strdupW(lpszClass);
2364 else
2365 lpNextKey->class = NULL;
2366 *retkey = currenthandle;
2367 TRACE(reg, "Returning %x\n", currenthandle);
2368 if (lpDispos)
2369 *lpDispos = REG_CREATED_NEW_KEY;
2370 FREE_KEY_PATH;
2371 return ERROR_SUCCESS;
2375 /******************************************************************************
2376 * RegCreateKeyEx32A [ADVAPI32.130]
2378 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2379 LPSTR lpszClass, DWORD fdwOptions,
2380 REGSAM samDesired,
2381 LPSECURITY_ATTRIBUTES lpSecAttribs,
2382 LPHKEY retkey, LPDWORD lpDispos )
2384 LPWSTR lpszSubKeyW, lpszClassW;
2385 DWORD ret;
2387 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2388 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2389 retkey,lpDispos);
2391 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2392 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2394 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2395 fdwOptions, samDesired, lpSecAttribs, retkey,
2396 lpDispos );
2398 if(lpszSubKeyW) free(lpszSubKeyW);
2399 if(lpszClassW) free(lpszClassW);
2401 return ret;
2405 /******************************************************************************
2406 * RegCreateKey32W [ADVAPI32.132]
2408 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2410 DWORD junk;
2411 LPKEYSTRUCT lpNextKey;
2413 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2415 /* This check is here because the return value is different than the
2416 one from the Ex functions */
2417 lpNextKey = lookup_hkey(hkey);
2418 if (!lpNextKey)
2419 return ERROR_BADKEY;
2421 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2422 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2423 retkey, &junk);
2427 /******************************************************************************
2428 * RegCreateKey32A [ADVAPI32.129]
2430 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2432 DWORD ret;
2433 LPWSTR lpszSubKeyW;
2435 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2436 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2437 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2438 if(lpszSubKeyW) free(lpszSubKeyW);
2439 return ret;
2443 /******************************************************************************
2444 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2446 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2448 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2449 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2454 * Query Value Functions
2455 * Win32 differs between keynames and valuenames.
2456 * multiple values may belong to one key, the special value
2457 * with name NULL is the default value used by the win31
2458 * compat functions.
2460 * Callpath:
2461 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2462 * RegQueryValue32W -> RegQueryValueEx32W
2466 /******************************************************************************
2467 * RegQueryValueEx32W [ADVAPI32.158]
2468 * Retrieves type and data for a specified name associated with an open key
2470 * PARAMS
2471 * hkey [I] Handle of key to query
2472 * lpValueName [I] Name of value to query
2473 * lpdwReserved [I] Reserved - must be NULL
2474 * lpdwType [O] Address of buffer for value type. If NULL, the type
2475 * is not required.
2476 * lpbData [O] Address of data buffer. If NULL, the actual data is
2477 * not required.
2478 * lpcbData [I/O] Address of data buffer size
2480 * RETURNS
2481 * ERROR_SUCCESS: Success
2482 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2483 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2485 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2486 LPDWORD lpdwReserved, LPDWORD lpdwType,
2487 LPBYTE lpbData, LPDWORD lpcbData )
2489 LPKEYSTRUCT lpkey;
2490 int i;
2491 DWORD ret;
2493 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2494 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2496 lpkey = lookup_hkey(hkey);
2498 if (!lpkey)
2499 return ERROR_INVALID_HANDLE;
2501 if ((lpbData && ! lpcbData) || lpdwReserved)
2502 return ERROR_INVALID_PARAMETER;
2504 /* An empty name string is equivalent to NULL */
2505 if (lpValueName && !*lpValueName)
2506 lpValueName = NULL;
2508 if (lpValueName==NULL)
2509 { /* Use key's unnamed or default value, if any */
2510 for (i=0;i<lpkey->nrofvalues;i++)
2511 if (lpkey->values[i].name==NULL)
2512 break;
2514 else
2515 { /* Search for the key name */
2516 for (i=0;i<lpkey->nrofvalues;i++)
2517 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2518 break;
2521 if (i==lpkey->nrofvalues)
2522 { TRACE(reg," Key not found\n");
2523 if (lpValueName==NULL)
2524 { /* Empty keyname not found */
2525 if (lpbData)
2526 { *(WCHAR*)lpbData = 0;
2527 *lpcbData = 2;
2529 if (lpdwType)
2530 *lpdwType = REG_SZ;
2531 TRACE(reg, " Returning an empty string\n");
2532 return ERROR_SUCCESS;
2534 return ERROR_FILE_NOT_FOUND;
2537 ret = ERROR_SUCCESS;
2539 if (lpdwType) /* type required ?*/
2540 *lpdwType = lpkey->values[i].type;
2542 if (lpbData) /* data required ?*/
2543 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2544 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2545 else
2546 ret = ERROR_MORE_DATA;
2549 if (lpcbData) /* size required ?*/
2550 { *lpcbData = lpkey->values[i].len;
2553 debug_print_value ( lpbData, &lpkey->values[i]);
2555 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2557 return ret;
2561 /******************************************************************************
2562 * RegQueryValue32W [ADVAPI32.159]
2564 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2565 LPLONG lpcbData )
2567 HKEY xhkey;
2568 DWORD ret,lpdwType;
2570 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2571 lpcbData?*lpcbData:0);
2573 /* Only open subkey, if we really do descend */
2574 if (lpszSubKey && *lpszSubKey) {
2575 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2576 if (ret != ERROR_SUCCESS) {
2577 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2578 return ret;
2580 } else
2581 xhkey = hkey;
2583 lpdwType = REG_SZ;
2584 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2585 lpcbData );
2586 if (xhkey != hkey)
2587 RegCloseKey(xhkey);
2588 return ret;
2592 /******************************************************************************
2593 * RegQueryValueEx32A [ADVAPI32.157]
2595 * NOTES:
2596 * the documantation is wrong: if the buffer is to small it remains untouched
2598 * FIXME: check returnvalue (len) for an empty key
2600 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2601 LPDWORD lpdwReserved, LPDWORD lpdwType,
2602 LPBYTE lpbData, LPDWORD lpcbData )
2604 LPWSTR lpszValueNameW;
2605 LPBYTE mybuf = NULL;
2606 DWORD ret, mytype, mylen = 0;
2608 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2609 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2611 if (!lpcbData && lpbData) /* buffer without size is illegal */
2612 { return ERROR_INVALID_PARAMETER;
2615 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2617 /* get just the type first */
2618 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2620 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2621 { if(lpszValueNameW) free(lpszValueNameW);
2622 return ret;
2625 if (lpcbData) /* at least length requested? */
2626 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2627 { if (lpbData ) /* value requested? */
2628 { mylen = 2*( *lpcbData );
2629 mybuf = (LPBYTE)xmalloc( mylen );
2632 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2634 if (ret == ERROR_SUCCESS )
2635 { if ( lpbData )
2636 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2640 *lpcbData = mylen/2; /* size is in byte! */
2642 else /* no strings, call it straight */
2643 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2647 if (lpdwType) /* type when requested */
2648 { *lpdwType = mytype;
2651 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2653 if(mybuf) free(mybuf);
2654 if(lpszValueNameW) free(lpszValueNameW);
2655 return ret;
2659 /******************************************************************************
2660 * RegQueryValueEx16 [KERNEL.225]
2662 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2663 LPDWORD lpdwReserved, LPDWORD lpdwType,
2664 LPBYTE lpbData, LPDWORD lpcbData )
2666 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2667 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2668 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2669 lpbData, lpcbData );
2673 /******************************************************************************
2674 * RegQueryValue32A [ADVAPI32.156]
2676 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2677 LPLONG lpcbData )
2679 HKEY xhkey;
2680 DWORD ret, dwType;
2682 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2683 lpcbData?*lpcbData:0);
2685 if (lpszSubKey && *lpszSubKey) {
2686 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2687 if( ret != ERROR_SUCCESS )
2688 return ret;
2689 } else
2690 xhkey = hkey;
2692 dwType = REG_SZ;
2693 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2694 lpcbData );
2695 if( xhkey != hkey )
2696 RegCloseKey( xhkey );
2697 return ret;
2701 /******************************************************************************
2702 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2704 * NOTES
2705 * Is this HACK still applicable?
2707 * HACK
2708 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2709 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2710 * Aldus FH4)
2712 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2713 LPDWORD lpcbData )
2715 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2716 lpcbData?*lpcbData:0);
2718 if (lpcbData)
2719 *lpcbData &= 0xFFFF;
2720 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2725 * Setting values of Registry keys
2727 * Callpath:
2728 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2729 * RegSetValue32W -> RegSetValueEx32W
2733 /******************************************************************************
2734 * RegSetValueEx32W [ADVAPI32.170]
2735 * Sets the data and type of a value under a register key
2737 * PARAMS
2738 * hkey [I] Handle of key to set value for
2739 * lpszValueName [I] Name of value to set
2740 * dwReserved [I] Reserved - must be zero
2741 * dwType [I] Flag for value type
2742 * lpbData [I] Address of value data
2743 * cbData [I] Size of value data
2745 * RETURNS
2746 * Success: ERROR_SUCCESS
2747 * Failure: Error code
2749 * NOTES
2750 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2752 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2753 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2754 DWORD cbData)
2756 LPKEYSTRUCT lpkey;
2757 int i;
2759 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2760 dwReserved, dwType, lpbData, cbData);
2762 lpkey = lookup_hkey( hkey );
2764 if (!lpkey)
2765 return ERROR_INVALID_HANDLE;
2767 lpkey->flags |= REG_OPTION_TAINTED;
2769 if (lpszValueName==NULL) {
2770 /* Sets type and name for key's unnamed or default value */
2771 for (i=0;i<lpkey->nrofvalues;i++)
2772 if (lpkey->values[i].name==NULL)
2773 break;
2774 } else {
2775 for (i=0;i<lpkey->nrofvalues;i++)
2776 if ( lpkey->values[i].name &&
2777 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2779 break;
2781 if (i==lpkey->nrofvalues) {
2782 lpkey->values = (LPKEYVALUE)xrealloc(
2783 lpkey->values,
2784 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2786 lpkey->nrofvalues++;
2787 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2789 if (lpkey->values[i].name==NULL) {
2790 if (lpszValueName)
2791 lpkey->values[i].name = strdupW(lpszValueName);
2792 else
2793 lpkey->values[i].name = NULL;
2796 if (dwType == REG_SZ)
2797 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2799 lpkey->values[i].len = cbData;
2800 lpkey->values[i].type = dwType;
2801 if (lpkey->values[i].data !=NULL)
2802 free(lpkey->values[i].data);
2803 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2804 lpkey->values[i].lastmodified = time(NULL);
2805 memcpy(lpkey->values[i].data,lpbData,cbData);
2806 return ERROR_SUCCESS;
2810 /******************************************************************************
2811 * RegSetValueEx32A [ADVAPI32.169]
2813 * NOTES
2814 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2816 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2817 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2818 DWORD cbData )
2820 LPBYTE buf;
2821 LPWSTR lpszValueNameW;
2822 DWORD ret;
2824 if (!lpbData)
2825 return (ERROR_INVALID_PARAMETER);
2827 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2828 dwReserved,dwType,lpbData,cbData);
2830 if ((1<<dwType) & UNICONVMASK)
2831 { if (dwType == REG_SZ)
2832 cbData = strlen ((LPCSTR)lpbData)+1;
2834 buf = (LPBYTE)xmalloc( cbData *2 );
2835 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2836 cbData=2*cbData;
2838 else
2839 buf=lpbData;
2841 if (lpszValueName)
2842 lpszValueNameW = strdupA2W(lpszValueName);
2843 else
2844 lpszValueNameW = NULL;
2846 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2848 if (lpszValueNameW)
2849 free(lpszValueNameW);
2851 if (buf!=lpbData)
2852 free(buf);
2854 return ret;
2858 /******************************************************************************
2859 * RegSetValueEx16 [KERNEL.226]
2861 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2862 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2864 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2865 dwReserved,dwType,lpbData,cbData);
2866 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2867 cbData );
2871 /******************************************************************************
2872 * RegSetValue32W [ADVAPI32.171]
2874 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2875 LPCWSTR lpszData, DWORD cbData )
2877 HKEY xhkey;
2878 DWORD ret;
2880 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2881 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2883 if (lpszSubKey && *lpszSubKey) {
2884 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2885 if (ret!=ERROR_SUCCESS)
2886 return ret;
2887 } else
2888 xhkey=hkey;
2889 if (dwType!=REG_SZ) {
2890 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2891 dwType=REG_SZ;
2893 if (cbData!=2*lstrlenW(lpszData)+2) {
2894 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2895 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2897 cbData=2*lstrlenW(lpszData)+2;
2899 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2900 if (hkey!=xhkey)
2901 RegCloseKey(xhkey);
2902 return ret;
2906 /******************************************************************************
2907 * RegSetValue32A [ADVAPI32.168]
2910 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2911 LPCSTR lpszData, DWORD cbData )
2913 DWORD ret;
2914 HKEY xhkey;
2916 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2917 if (lpszSubKey && *lpszSubKey) {
2918 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2919 if (ret!=ERROR_SUCCESS)
2920 return ret;
2921 } else
2922 xhkey=hkey;
2924 if (dwType!=REG_SZ) {
2925 TRACE(reg,"dwType=%ld!\n",dwType);
2926 dwType=REG_SZ;
2928 if (cbData!=strlen(lpszData)+1)
2929 cbData=strlen(lpszData)+1;
2930 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2931 if (xhkey!=hkey)
2932 RegCloseKey(xhkey);
2933 return ret;
2937 /******************************************************************************
2938 * RegSetValue16 [KERNEL.221] [SHELL.5]
2940 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2941 LPCSTR lpszData, DWORD cbData )
2943 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2944 debugstr_a(lpszData),cbData);
2945 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2950 * Key Enumeration
2952 * Callpath:
2953 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2954 * RegEnumKey32W -> RegEnumKeyEx32W
2958 /******************************************************************************
2959 * RegEnumKeyEx32W [ADVAPI32.139]
2961 * PARAMS
2962 * hkey [I] Handle to key to enumerate
2963 * iSubKey [I] Index of subkey to enumerate
2964 * lpszName [O] Buffer for subkey name
2965 * lpcchName [O] Size of subkey buffer
2966 * lpdwReserved [I] Reserved
2967 * lpszClass [O] Buffer for class string
2968 * lpcchClass [O] Size of class buffer
2969 * ft [O] Time key last written to
2971 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2972 LPDWORD lpcchName, LPDWORD lpdwReserved,
2973 LPWSTR lpszClass, LPDWORD lpcchClass,
2974 FILETIME *ft )
2976 LPKEYSTRUCT lpkey,lpxkey;
2978 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2979 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2981 lpkey = lookup_hkey( hkey );
2982 if (!lpkey)
2983 return ERROR_INVALID_HANDLE;
2985 if (!lpkey->nextsub)
2986 return ERROR_NO_MORE_ITEMS;
2987 lpxkey=lpkey->nextsub;
2989 /* Traverse the subkeys */
2990 while (iSubkey && lpxkey) {
2991 iSubkey--;
2992 lpxkey=lpxkey->next;
2995 if (iSubkey || !lpxkey)
2996 return ERROR_NO_MORE_ITEMS;
2997 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
2998 return ERROR_MORE_DATA;
2999 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3001 if (*lpcchName)
3002 *lpcchName = lstrlenW(lpszName);
3004 if (lpszClass) {
3005 /* FIXME: what should we write into it? */
3006 *lpszClass = 0;
3007 *lpcchClass = 2;
3009 return ERROR_SUCCESS;
3013 /******************************************************************************
3014 * RegEnumKey32W [ADVAPI32.140]
3016 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3017 DWORD lpcchName )
3019 FILETIME ft;
3021 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3022 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3026 /******************************************************************************
3027 * RegEnumKeyEx32A [ADVAPI32.138]
3029 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3030 LPDWORD lpcchName, LPDWORD lpdwReserved,
3031 LPSTR lpszClass, LPDWORD lpcchClass,
3032 FILETIME *ft )
3034 DWORD ret,lpcchNameW,lpcchClassW;
3035 LPWSTR lpszNameW,lpszClassW;
3038 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3039 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3041 if (lpszName) {
3042 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3043 lpcchNameW = *lpcchName;
3044 } else {
3045 lpszNameW = NULL;
3046 lpcchNameW = 0;
3048 if (lpszClass) {
3049 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3050 lpcchClassW = *lpcchClass;
3051 } else {
3052 lpszClassW =0;
3053 lpcchClassW=0;
3055 ret=RegEnumKeyExW(
3056 hkey,
3057 iSubkey,
3058 lpszNameW,
3059 &lpcchNameW,
3060 lpdwReserved,
3061 lpszClassW,
3062 &lpcchClassW,
3065 if (ret==ERROR_SUCCESS) {
3066 lstrcpyWtoA(lpszName,lpszNameW);
3067 *lpcchName=strlen(lpszName);
3068 if (lpszClassW) {
3069 lstrcpyWtoA(lpszClass,lpszClassW);
3070 *lpcchClass=strlen(lpszClass);
3073 if (lpszNameW)
3074 free(lpszNameW);
3075 if (lpszClassW)
3076 free(lpszClassW);
3077 return ret;
3081 /******************************************************************************
3082 * RegEnumKey32A [ADVAPI32.137]
3084 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3085 DWORD lpcchName )
3087 FILETIME ft;
3089 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3090 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3091 NULL, &ft );
3095 /******************************************************************************
3096 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3098 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3099 DWORD lpcchName )
3101 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3102 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3107 * Enumerate Registry Values
3109 * Callpath:
3110 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3114 /******************************************************************************
3115 * RegEnumValue32W [ADVAPI32.142]
3117 * PARAMS
3118 * hkey [I] Handle to key to query
3119 * iValue [I] Index of value to query
3120 * lpszValue [O] Value string
3121 * lpcchValue [I/O] Size of value buffer (in wchars)
3122 * lpdReserved [I] Reserved
3123 * lpdwType [O] Type code
3124 * lpbData [O] Value data
3125 * lpcbData [I/O] Size of data buffer (in bytes)
3127 * Note: wide character functions that take and/or return "character counts"
3128 * use TCHAR (that is unsigned short or char) not byte counts.
3130 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3131 LPDWORD lpcchValue, LPDWORD lpdReserved,
3132 LPDWORD lpdwType, LPBYTE lpbData,
3133 LPDWORD lpcbData )
3135 LPKEYSTRUCT lpkey;
3136 LPKEYVALUE val;
3138 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3139 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3141 lpkey = lookup_hkey( hkey );
3143 if (!lpcbData && lpbData)
3144 return ERROR_INVALID_PARAMETER;
3146 if (!lpkey)
3147 return ERROR_INVALID_HANDLE;
3149 if (lpkey->nrofvalues <= iValue)
3150 return ERROR_NO_MORE_ITEMS;
3152 val = &(lpkey->values[iValue]);
3154 if (val->name) {
3155 if (lstrlenW(val->name)+1>*lpcchValue) {
3156 *lpcchValue = lstrlenW(val->name)+1;
3157 return ERROR_MORE_DATA;
3159 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3160 *lpcchValue=lstrlenW(val->name);
3161 } else {
3162 *lpszValue = 0;
3163 *lpcchValue = 0;
3166 /* Can be NULL if the type code is not required */
3167 if (lpdwType)
3168 *lpdwType = val->type;
3170 if (lpbData) {
3171 if (val->len>*lpcbData)
3172 return ERROR_MORE_DATA;
3173 memcpy(lpbData,val->data,val->len);
3174 *lpcbData = val->len;
3177 debug_print_value ( val->data, val );
3178 return ERROR_SUCCESS;
3182 /******************************************************************************
3183 * RegEnumValue32A [ADVAPI32.141]
3185 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3186 LPDWORD lpcchValue, LPDWORD lpdReserved,
3187 LPDWORD lpdwType, LPBYTE lpbData,
3188 LPDWORD lpcbData )
3190 LPWSTR lpszValueW;
3191 LPBYTE lpbDataW;
3192 DWORD ret,lpcbDataW;
3193 DWORD dwType;
3195 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3196 lpdReserved,lpdwType,lpbData,lpcbData);
3198 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3199 if (lpbData) {
3200 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3201 lpcbDataW = *lpcbData;
3202 } else
3203 lpbDataW = NULL;
3205 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3206 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3208 if (lpdwType)
3209 *lpdwType = dwType;
3211 if (ret==ERROR_SUCCESS) {
3212 lstrcpyWtoA(lpszValue,lpszValueW);
3213 if (lpbData) {
3214 if ((1<<dwType) & UNICONVMASK) {
3215 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3216 } else {
3217 if (lpcbDataW > *lpcbData)
3218 ret = ERROR_MORE_DATA;
3219 else
3220 memcpy(lpbData,lpbDataW,lpcbDataW);
3222 *lpcbData = lpcbDataW;
3225 if (lpbDataW) free(lpbDataW);
3226 if (lpszValueW) free(lpszValueW);
3227 return ret;
3231 /******************************************************************************
3232 * RegEnumValue16 [KERNEL.223]
3234 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3235 LPDWORD lpcchValue, LPDWORD lpdReserved,
3236 LPDWORD lpdwType, LPBYTE lpbData,
3237 LPDWORD lpcbData )
3239 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3240 lpdReserved,lpdwType,lpbData,lpcbData);
3241 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3242 lpdwType, lpbData, lpcbData );
3246 /******************************************************************************
3247 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3248 * Releases the handle of the specified key
3250 * PARAMS
3251 * hkey [I] Handle of key to close
3253 * RETURNS
3254 * Success: ERROR_SUCCESS
3255 * Failure: Error code
3257 DWORD WINAPI RegCloseKey( HKEY hkey )
3259 TRACE(reg,"(%x)\n",hkey);
3261 /* The standard handles are allowed to succeed, even though they are not
3262 closed */
3263 if (is_standard_hkey(hkey))
3264 return ERROR_SUCCESS;
3266 return remove_handle(hkey);
3271 * Delete registry key
3273 * Callpath:
3274 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3278 /******************************************************************************
3279 * RegDeleteKey32W [ADVAPI32.134]
3281 * PARAMS
3282 * hkey [I] Handle to open key
3283 * lpszSubKey [I] Name of subkey to delete
3285 * RETURNS
3286 * Success: ERROR_SUCCESS
3287 * Failure: Error code
3289 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3291 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3292 LPWSTR *wps;
3293 int wpc,i;
3295 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3297 lpNextKey = lookup_hkey(hkey);
3298 if (!lpNextKey)
3299 return ERROR_INVALID_HANDLE;
3301 /* Subkey param cannot be NULL */
3302 if (!lpszSubKey || !*lpszSubKey)
3303 return ERROR_BADKEY;
3305 /* We need to know the previous key in the hier. */
3306 split_keypath(lpszSubKey,&wps,&wpc);
3307 i = 0;
3308 lpxkey = lpNextKey;
3309 while (i<wpc-1) {
3310 lpxkey=lpNextKey->nextsub;
3311 while (lpxkey) {
3312 TRACE(reg, " Scanning [%s]\n",
3313 debugstr_w(lpxkey->keyname));
3314 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3315 break;
3316 lpxkey=lpxkey->next;
3318 if (!lpxkey) {
3319 FREE_KEY_PATH;
3320 TRACE(reg, " Not found.\n");
3321 /* not found is success */
3322 return ERROR_SUCCESS;
3324 i++;
3325 lpNextKey = lpxkey;
3327 lpxkey = lpNextKey->nextsub;
3328 lplpPrevKey = &(lpNextKey->nextsub);
3329 while (lpxkey) {
3330 TRACE(reg, " Scanning [%s]\n",
3331 debugstr_w(lpxkey->keyname));
3332 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3333 break;
3334 lplpPrevKey = &(lpxkey->next);
3335 lpxkey = lpxkey->next;
3338 if (!lpxkey) {
3339 FREE_KEY_PATH;
3340 WARN(reg , " Not found.\n");
3341 return ERROR_FILE_NOT_FOUND;
3344 if (lpxkey->nextsub) {
3345 FREE_KEY_PATH;
3346 WARN(reg , " Not empty.\n");
3347 return ERROR_CANTWRITE;
3349 *lplpPrevKey = lpxkey->next;
3350 free(lpxkey->keyname);
3351 if (lpxkey->class)
3352 free(lpxkey->class);
3353 if (lpxkey->values)
3354 free(lpxkey->values);
3355 free(lpxkey);
3356 FREE_KEY_PATH;
3357 TRACE(reg, " Done.\n");
3358 return ERROR_SUCCESS;
3362 /******************************************************************************
3363 * RegDeleteKey32A [ADVAPI32.133]
3365 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3367 LPWSTR lpszSubKeyW;
3368 DWORD ret;
3370 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3371 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3372 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3373 if(lpszSubKeyW) free(lpszSubKeyW);
3374 return ret;
3378 /******************************************************************************
3379 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3381 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3383 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3384 return RegDeleteKeyA( hkey, lpszSubKey );
3389 * Delete registry value
3391 * Callpath:
3392 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3396 /******************************************************************************
3397 * RegDeleteValue32W [ADVAPI32.136]
3399 * PARAMS
3400 * hkey [I]
3401 * lpszValue [I]
3403 * RETURNS
3405 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3407 DWORD i;
3408 LPKEYSTRUCT lpkey;
3409 LPKEYVALUE val;
3411 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3413 lpkey = lookup_hkey( hkey );
3414 if (!lpkey)
3415 return ERROR_INVALID_HANDLE;
3417 if (lpszValue) {
3418 for (i=0;i<lpkey->nrofvalues;i++)
3419 if ( lpkey->values[i].name &&
3420 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3422 break;
3423 } else {
3424 for (i=0;i<lpkey->nrofvalues;i++)
3425 if (lpkey->values[i].name==NULL)
3426 break;
3429 if (i == lpkey->nrofvalues)
3430 return ERROR_FILE_NOT_FOUND;
3432 val = lpkey->values+i;
3433 if (val->name) free(val->name);
3434 if (val->data) free(val->data);
3435 memcpy(
3436 lpkey->values+i,
3437 lpkey->values+i+1,
3438 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3440 lpkey->values = (LPKEYVALUE)xrealloc(
3441 lpkey->values,
3442 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3444 lpkey->nrofvalues--;
3445 return ERROR_SUCCESS;
3449 /******************************************************************************
3450 * RegDeleteValue32A [ADVAPI32.135]
3452 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3454 LPWSTR lpszValueW;
3455 DWORD ret;
3457 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3458 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3459 ret = RegDeleteValueW( hkey, lpszValueW );
3460 if(lpszValueW) free(lpszValueW);
3461 return ret;
3465 /******************************************************************************
3466 * RegDeleteValue16 [KERNEL.222]
3468 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3470 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3471 return RegDeleteValueA( hkey, lpszValue );
3475 /******************************************************************************
3476 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3477 * Writes key to registry
3479 * PARAMS
3480 * hkey [I] Handle of key to write
3482 * RETURNS
3483 * Success: ERROR_SUCCESS
3484 * Failure: Error code
3486 DWORD WINAPI RegFlushKey( HKEY hkey )
3488 LPKEYSTRUCT lpkey;
3489 BOOL ret;
3491 TRACE(reg, "(%x)\n", hkey);
3493 lpkey = lookup_hkey( hkey );
3494 if (!lpkey)
3495 return ERROR_BADKEY;
3497 ERR(reg, "What is the correct filename?\n");
3499 ret = _savereg( lpkey, "foo.bar", TRUE);
3501 if( ret ) {
3502 return ERROR_SUCCESS;
3503 } else
3504 return ERROR_UNKNOWN; /* FIXME */
3508 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3511 /******************************************************************************
3512 * RegQueryInfoKey32W [ADVAPI32.153]
3514 * PARAMS
3515 * hkey [I] Handle to key to query
3516 * lpszClass [O] Buffer for class string
3517 * lpcchClass [O] Size of class string buffer
3518 * lpdwReserved [I] Reserved
3519 * lpcSubKeys [I] Buffer for number of subkeys
3520 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3521 * lpcchMaxClass [O] Buffer for longest class string length
3522 * lpcValues [O] Buffer for number of value entries
3523 * lpcchMaxValueName [O] Buffer for longest value name length
3524 * lpccbMaxValueData [O] Buffer for longest value data length
3525 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3526 * ft
3527 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3528 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3529 * lpcchClass is NULL
3530 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3531 * (it's hard to test validity, so test !NULL instead)
3533 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3534 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3535 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3536 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3537 LPDWORD lpcchMaxValueName,
3538 LPDWORD lpccbMaxValueData,
3539 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3541 LPKEYSTRUCT lpkey,lpxkey;
3542 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3543 int i;
3545 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3546 lpkey = lookup_hkey(hkey);
3547 if (!lpkey)
3548 return ERROR_INVALID_HANDLE;
3549 if (lpszClass) {
3550 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3551 return ERROR_INVALID_PARAMETER;
3553 /* either lpcchClass is valid or this is win95 and lpcchClass
3554 could be invalid */
3555 if (lpkey->class) {
3556 DWORD classLen = lstrlenW(lpkey->class);
3558 if (lpcchClass && classLen+1>*lpcchClass) {
3559 *lpcchClass=classLen+1;
3560 return ERROR_MORE_DATA;
3562 if (lpcchClass)
3563 *lpcchClass=classLen;
3564 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3565 } else {
3566 *lpszClass = 0;
3567 if (lpcchClass)
3568 *lpcchClass = 0;
3570 } else {
3571 if (lpcchClass)
3572 *lpcchClass = lstrlenW(lpkey->class);
3574 lpxkey=lpkey->nextsub;
3575 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3576 while (lpxkey) {
3577 nrofkeys++;
3578 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3579 maxsubkey=lstrlenW(lpxkey->keyname);
3580 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3581 maxclass=lstrlenW(lpxkey->class);
3582 lpxkey=lpxkey->next;
3584 for (i=0;i<lpkey->nrofvalues;i++) {
3585 LPKEYVALUE val=lpkey->values+i;
3587 if (val->name && lstrlenW(val->name)>maxvname)
3588 maxvname=lstrlenW(val->name);
3589 if (val->len>maxvdata)
3590 maxvdata=val->len;
3592 if (!maxclass) maxclass = 1;
3593 if (!maxvname) maxvname = 1;
3594 if (lpcValues)
3595 *lpcValues = lpkey->nrofvalues;
3596 if (lpcSubKeys)
3597 *lpcSubKeys = nrofkeys;
3598 if (lpcchMaxSubkey)
3599 *lpcchMaxSubkey = maxsubkey;
3600 if (lpcchMaxClass)
3601 *lpcchMaxClass = maxclass;
3602 if (lpcchMaxValueName)
3603 *lpcchMaxValueName= maxvname;
3604 if (lpccbMaxValueData)
3605 *lpccbMaxValueData= maxvdata;
3606 return ERROR_SUCCESS;
3610 /******************************************************************************
3611 * RegQueryInfoKey32A [ADVAPI32.152]
3613 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3614 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3615 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3616 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3617 LPDWORD lpccbMaxValueData,
3618 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3620 LPWSTR lpszClassW = NULL;
3621 DWORD ret;
3623 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3624 if (lpszClass) {
3625 if (lpcchClass) {
3626 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3627 } else if (VERSION_GetVersion() == WIN95) {
3628 /* win95 allows lpcchClass to be null */
3629 /* we don't know how big lpszClass is, would
3630 MAX_PATHNAME_LEN be the correct default? */
3631 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3634 } else
3635 lpszClassW = NULL;
3636 ret=RegQueryInfoKeyW(
3637 hkey,
3638 lpszClassW,
3639 lpcchClass,
3640 lpdwReserved,
3641 lpcSubKeys,
3642 lpcchMaxSubkey,
3643 lpcchMaxClass,
3644 lpcValues,
3645 lpcchMaxValueName,
3646 lpccbMaxValueData,
3647 lpcbSecurityDescriptor,
3650 if (ret==ERROR_SUCCESS && lpszClass)
3651 lstrcpyWtoA(lpszClass,lpszClassW);
3652 if (lpszClassW)
3653 free(lpszClassW);
3654 return ret;
3658 /******************************************************************************
3659 * RegConnectRegistry32W [ADVAPI32.128]
3661 * PARAMS
3662 * lpMachineName [I] Address of name of remote computer
3663 * hHey [I] Predefined registry handle
3664 * phkResult [I] Address of buffer for remote registry handle
3666 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3667 LPHKEY phkResult )
3669 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3671 if (!lpMachineName || !*lpMachineName) {
3672 /* Use the local machine name */
3673 return RegOpenKey16( hKey, "", phkResult );
3676 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3677 return ERROR_BAD_NETPATH;
3681 /******************************************************************************
3682 * RegConnectRegistry32A [ADVAPI32.127]
3684 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3686 DWORD ret;
3687 LPWSTR machineW = strdupA2W(machine);
3688 ret = RegConnectRegistryW( machineW, hkey, reskey );
3689 free(machineW);
3690 return ret;
3694 /******************************************************************************
3695 * RegGetKeySecurity [ADVAPI32.144]
3696 * Retrieves a copy of security descriptor protecting the registry key
3698 * PARAMS
3699 * hkey [I] Open handle of key to set
3700 * SecurityInformation [I] Descriptor contents
3701 * pSecurityDescriptor [O] Address of descriptor for key
3702 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3704 * RETURNS
3705 * Success: ERROR_SUCCESS
3706 * Failure: Error code
3708 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3709 SECURITY_INFORMATION SecurityInformation,
3710 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3711 LPDWORD lpcbSecurityDescriptor )
3713 LPKEYSTRUCT lpkey;
3715 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3716 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3718 lpkey = lookup_hkey( hkey );
3719 if (!lpkey)
3720 return ERROR_INVALID_HANDLE;
3722 /* FIXME: Check for valid SecurityInformation values */
3724 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3725 return ERROR_INSUFFICIENT_BUFFER;
3727 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3728 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3730 return ERROR_SUCCESS;
3734 /******************************************************************************
3735 * RegLoadKey32W [ADVAPI32.???]
3737 * PARAMS
3738 * hkey [I] Handle of open key
3739 * lpszSubKey [I] Address of name of subkey
3740 * lpszFile [I] Address of filename for registry information
3742 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3744 LPKEYSTRUCT lpkey;
3745 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3747 /* Do this check before the hkey check */
3748 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3749 return ERROR_INVALID_PARAMETER;
3751 lpkey = lookup_hkey( hkey );
3752 if (!lpkey)
3753 return ERROR_INVALID_HANDLE;
3755 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3756 debugstr_w(lpszFile));
3758 return ERROR_SUCCESS;
3762 /******************************************************************************
3763 * RegLoadKey32A [ADVAPI32.???]
3765 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3767 LONG ret;
3768 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3769 LPWSTR lpszFileW = strdupA2W(lpszFile);
3770 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3771 if(lpszFileW) free(lpszFileW);
3772 if(lpszSubKeyW) free(lpszSubKeyW);
3773 return ret;
3777 /******************************************************************************
3778 * RegNotifyChangeKeyValue [ADVAPI32.???]
3780 * PARAMS
3781 * hkey [I] Handle of key to watch
3782 * fWatchSubTree [I] Flag for subkey notification
3783 * fdwNotifyFilter [I] Changes to be reported
3784 * hEvent [I] Handle of signaled event
3785 * fAsync [I] Flag for asynchronous reporting
3787 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3788 DWORD fdwNotifyFilter, HANDLE hEvent,
3789 BOOL fAsync )
3791 LPKEYSTRUCT lpkey;
3792 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3793 hEvent,fAsync);
3795 lpkey = lookup_hkey( hkey );
3796 if (!lpkey)
3797 return ERROR_INVALID_HANDLE;
3799 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3800 hEvent,fAsync);
3802 return ERROR_SUCCESS;
3806 /******************************************************************************
3807 * RegUnLoadKey32W [ADVAPI32.173]
3809 * PARAMS
3810 * hkey [I] Handle of open key
3811 * lpSubKey [I] Address of name of subkey to unload
3813 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3815 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3816 return ERROR_SUCCESS;
3820 /******************************************************************************
3821 * RegUnLoadKey32A [ADVAPI32.172]
3823 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3825 LONG ret;
3826 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3827 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3828 if(lpSubKeyW) free(lpSubKeyW);
3829 return ret;
3833 /******************************************************************************
3834 * RegSetKeySecurity [ADVAPI32.167]
3836 * PARAMS
3837 * hkey [I] Open handle of key to set
3838 * SecurityInfo [I] Descriptor contents
3839 * pSecurityDesc [I] Address of descriptor for key
3841 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3842 PSECURITY_DESCRIPTOR pSecurityDesc )
3844 LPKEYSTRUCT lpkey;
3846 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3848 /* It seems to perform this check before the hkey check */
3849 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3850 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3851 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3852 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3853 /* Param OK */
3854 } else
3855 return ERROR_INVALID_PARAMETER;
3857 if (!pSecurityDesc)
3858 return ERROR_INVALID_PARAMETER;
3860 lpkey = lookup_hkey( hkey );
3861 if (!lpkey)
3862 return ERROR_INVALID_HANDLE;
3864 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3866 return ERROR_SUCCESS;
3870 /******************************************************************************
3871 * RegSaveKey32W [ADVAPI32.166]
3873 * PARAMS
3874 * hkey [I] Handle of key where save begins
3875 * lpFile [I] Address of filename to save to
3876 * sa [I] Address of security structure
3878 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3879 LPSECURITY_ATTRIBUTES sa )
3881 LPKEYSTRUCT lpkey;
3883 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3885 /* It appears to do this check before the hkey check */
3886 if (!lpFile || !*lpFile)
3887 return ERROR_INVALID_PARAMETER;
3889 lpkey = lookup_hkey( hkey );
3890 if (!lpkey)
3891 return ERROR_INVALID_HANDLE;
3893 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3895 return ERROR_SUCCESS;
3899 /******************************************************************************
3900 * RegSaveKey32A [ADVAPI32.165]
3902 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3903 LPSECURITY_ATTRIBUTES sa )
3905 LONG ret;
3906 LPWSTR lpFileW = strdupA2W(lpFile);
3907 ret = RegSaveKeyW( hkey, lpFileW, sa );
3908 free(lpFileW);
3909 return ret;
3913 /******************************************************************************
3914 * RegRestoreKey32W [ADVAPI32.164]
3916 * PARAMS
3917 * hkey [I] Handle of key where restore begins
3918 * lpFile [I] Address of filename containing saved tree
3919 * dwFlags [I] Optional flags
3921 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3923 LPKEYSTRUCT lpkey;
3925 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3927 /* It seems to do this check before the hkey check */
3928 if (!lpFile || !*lpFile)
3929 return ERROR_INVALID_PARAMETER;
3931 lpkey = lookup_hkey( hkey );
3932 if (!lpkey)
3933 return ERROR_INVALID_HANDLE;
3935 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3937 /* Check for file existence */
3939 return ERROR_SUCCESS;
3943 /******************************************************************************
3944 * RegRestoreKey32A [ADVAPI32.163]
3946 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3948 LONG ret;
3949 LPWSTR lpFileW = strdupA2W(lpFile);
3950 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3951 if(lpFileW) free(lpFileW);
3952 return ret;
3956 /******************************************************************************
3957 * RegReplaceKey32W [ADVAPI32.162]
3959 * PARAMS
3960 * hkey [I] Handle of open key
3961 * lpSubKey [I] Address of name of subkey
3962 * lpNewFile [I] Address of filename for file with new data
3963 * lpOldFile [I] Address of filename for backup file
3965 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3966 LPCWSTR lpOldFile )
3968 LPKEYSTRUCT lpkey;
3970 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3971 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3973 lpkey = lookup_hkey( hkey );
3974 if (!lpkey)
3975 return ERROR_INVALID_HANDLE;
3977 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3978 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3980 return ERROR_SUCCESS;
3984 /******************************************************************************
3985 * RegReplaceKey32A [ADVAPI32.161]
3987 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3988 LPCSTR lpOldFile )
3990 LONG ret;
3991 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3992 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3993 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3994 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3995 free(lpOldFileW);
3996 free(lpNewFileW);
3997 free(lpSubKeyW);
3998 return ret;