New debug scheme with explicit debug channels declaration.
[wine.git] / misc / registry.c
blob529388debe6417f255eec41e733f39a33eb3f3f8
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 DECLARE_DEBUG_CHANNEL(reg)
48 DECLARE_DEBUG_CHANNEL(string)
50 static void REGISTRY_Init(void);
51 /* FIXME: following defines should be configured global ... */
53 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
54 #define WINE_PREFIX "/.wine"
55 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
56 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
58 /* relative in ~user/.wine/ : */
59 #define SAVE_CURRENT_USER "user.reg"
60 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
61 #define SAVE_LOCAL_MACHINE "system.reg"
63 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
64 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
66 /* one value of a key */
67 typedef struct tagKEYVALUE
69 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
70 DWORD type; /* type of value */
71 DWORD len; /* length of data in BYTEs */
72 DWORD lastmodified; /* time of seconds since 1.1.1970 */
73 LPBYTE data; /* content, may be strings, binaries, etc. */
74 } KEYVALUE,*LPKEYVALUE;
76 /* a registry key */
77 typedef struct tagKEYSTRUCT
79 LPWSTR keyname; /* name of THIS key (UNICODE) */
80 DWORD flags; /* flags. */
81 LPWSTR class;
82 /* values */
83 DWORD nrofvalues; /* nr of values in THIS key */
84 LPKEYVALUE values; /* values in THIS key */
85 /* key management pointers */
86 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
87 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
88 } KEYSTRUCT, *LPKEYSTRUCT;
91 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
92 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
93 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
94 static KEYSTRUCT *key_users=NULL; /* all users? */
96 /* dynamic, not saved */
97 static KEYSTRUCT *key_performance_data=NULL;
98 static KEYSTRUCT *key_current_config=NULL;
99 static KEYSTRUCT *key_dyn_data=NULL;
101 /* what valuetypes do we need to convert? */
102 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
105 static struct openhandle {
106 LPKEYSTRUCT lpkey;
107 HKEY hkey;
108 REGSAM accessmask;
109 } *openhandles=NULL;
110 static int nrofopenhandles=0;
111 /* Starts after 1 because 0,1 are reserved for Win16 */
112 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
113 HKEYs for remote registry access */
114 static int currenthandle=2;
118 * QUESTION
119 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
120 * If so, can we remove them?
121 * ANSWER
122 * No, the memory handling functions are called very often in here,
123 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
124 * loading 100 times slower. -MM
126 static LPWSTR strdupA2W(LPCSTR src)
128 if(src) {
129 LPWSTR dest=xmalloc(2*strlen(src)+2);
130 lstrcpyAtoW(dest,src);
131 return dest;
133 return NULL;
136 static LPWSTR strdupW(LPCWSTR a) {
137 LPWSTR b;
138 int len;
140 if(a) {
141 len=sizeof(WCHAR)*(lstrlenW(a)+1);
142 b=(LPWSTR)xmalloc(len);
143 memcpy(b,a,len);
144 return b;
146 return NULL;
149 LPWSTR strcvtA2W(LPCSTR src, int nchars)
152 LPWSTR dest = xmalloc (2 * nchars + 2);
154 lstrcpynAtoW(dest,src,nchars+1);
155 dest[nchars] = 0;
156 return dest;
159 * we need to convert A to W with '\0' in strings (MULTI_SZ)
162 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
163 { LPWSTR p = dst;
165 TRACE(reg,"\"%s\" %i\n",src, n);
167 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
169 return dst;
171 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
172 { LPSTR p = dst;
174 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
176 while (n-- > 0) *p++ = (CHAR)*src++;
178 return dst;
181 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
183 if (TRACE_ON(reg) && lpbData)
185 switch(key->type)
187 case HEX_REG_EXPAND_SZ:
188 case HEX_REG_SZ:
189 case REG_SZ:
190 TRACE(reg," Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
193 break;
195 case HEX_REG_DWORD:
196 case REG_DWORD:
197 TRACE(reg," Value %s, Data(dword)=0x%08lx\n",
198 debugstr_w(key->name),
199 (DWORD)*lpbData);
200 break;
202 case HEX_REG_MULTI_SZ:
203 case REG_MULTI_SZ:
205 int i;
206 LPCWSTR ptr = (LPCWSTR)lpbData;
207 for (i=0;ptr[0];i++)
209 TRACE(reg, " Value %s, MULTI_SZ(%i=%s)\n",
210 debugstr_w(key->name),
212 debugstr_w(ptr));
214 ptr += lstrlenW(ptr)+1;
217 break;
219 case HEX_REG_NONE:
220 case HEX_REG_BINARY:
221 case HEX_REG_LINK:
222 case HEX_REG_RESOURCE_LIST:
223 case HEX_REG_FULL_RESOURCE_DESCRIPTOR:
224 case REG_NONE:
225 case REG_LINK:
226 case REG_RESOURCE_LIST:
227 case REG_FULL_RESOURCE_DESCRIPTOR:
228 case REG_BINARY:
230 char szTemp[100]; /* 3*32 + 3 + 1 */
231 int i;
232 for ( i = 0; i < key->len ; i++)
234 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
235 if (i>=31)
237 sprintf (&(szTemp[i*3+3]),"...");
238 break;
241 TRACE(reg," Value %s, Data(raw)=(%s)\n",
242 debugstr_w(key->name),
243 szTemp);
245 break;
247 default:
248 FIXME(reg, " Value %s, Unknown data type %ld\n",
249 debugstr_w(key->name),
250 key->type);
251 } /* switch */
252 } /* if */
256 /******************************************************************************
257 * is_standard_hkey [Internal]
258 * Determines if a hkey is a standard key
260 static BOOL is_standard_hkey( HKEY hkey )
262 switch(hkey) {
263 case 0x00000000:
264 case 0x00000001:
265 case HKEY_CLASSES_ROOT:
266 case HKEY_CURRENT_CONFIG:
267 case HKEY_CURRENT_USER:
268 case HKEY_LOCAL_MACHINE:
269 case HKEY_USERS:
270 case HKEY_PERFORMANCE_DATA:
271 case HKEY_DYN_DATA:
272 return TRUE;
273 default:
274 return FALSE;
278 /******************************************************************************
279 * add_handle [Internal]
281 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
283 int i;
285 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
286 /* Check for duplicates */
287 for (i=0;i<nrofopenhandles;i++) {
288 if (openhandles[i].lpkey==lpkey) {
289 /* This is not really an error - the user is allowed to create
290 two (or more) handles to the same key */
291 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
293 if (openhandles[i].hkey==hkey) {
294 WARN(reg, "Adding handle %x twice\n",hkey);
297 openhandles=xrealloc( openhandles,
298 sizeof(struct openhandle)*(nrofopenhandles+1));
300 openhandles[i].lpkey = lpkey;
301 openhandles[i].hkey = hkey;
302 openhandles[i].accessmask = accessmask;
303 nrofopenhandles++;
307 /******************************************************************************
308 * get_handle [Internal]
310 * RETURNS
311 * Success: Pointer to key
312 * Failure: NULL
314 static LPKEYSTRUCT get_handle( HKEY hkey )
316 int i;
318 for (i=0; i<nrofopenhandles; i++)
319 if (openhandles[i].hkey == hkey)
320 return openhandles[i].lpkey;
321 WARN(reg, "Could not find handle 0x%x\n",hkey);
322 return NULL;
326 /******************************************************************************
327 * remove_handle [Internal]
329 * PARAMS
330 * hkey [I] Handle of key to remove
332 * RETURNS
333 * Success: ERROR_SUCCESS
334 * Failure: ERROR_INVALID_HANDLE
336 static DWORD remove_handle( HKEY hkey )
338 int i;
340 for (i=0;i<nrofopenhandles;i++)
341 if (openhandles[i].hkey==hkey)
342 break;
344 if (i == nrofopenhandles) {
345 WARN(reg, "Could not find handle 0x%x\n",hkey);
346 return ERROR_INVALID_HANDLE;
349 memcpy( openhandles+i,
350 openhandles+i+1,
351 sizeof(struct openhandle)*(nrofopenhandles-i-1)
353 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
354 nrofopenhandles--;
355 return ERROR_SUCCESS;
358 /******************************************************************************
359 * lookup_hkey [Internal]
361 * Just as the name says. Creates the root keys on demand, so we can call the
362 * Reg* functions at any time.
364 * RETURNS
365 * Success: Pointer to key structure
366 * Failure: NULL
368 #define ADD_ROOT_KEY(xx) \
369 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
370 memset(xx,'\0',sizeof(KEYSTRUCT));\
371 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
373 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
375 switch (hkey) {
376 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
377 * some programs. Do not remove those cases. -MM
379 case 0x00000000:
380 case 0x00000001:
381 case HKEY_CLASSES_ROOT:
383 if (!key_classes_root)
385 HKEY cl_r_hkey;
387 /* calls lookup_hkey recursively, TWICE */
388 if ( RegCreateKey16(
389 HKEY_LOCAL_MACHINE,
390 "SOFTWARE\\Classes",
391 &cl_r_hkey) != ERROR_SUCCESS)
393 ERR(
394 reg,
395 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
396 exit(1);
399 key_classes_root = lookup_hkey(cl_r_hkey);
401 return key_classes_root;
404 case HKEY_CURRENT_USER:
405 if (!key_current_user) {
406 ADD_ROOT_KEY(key_current_user);
408 return key_current_user;
410 case HKEY_LOCAL_MACHINE:
411 if (!key_local_machine) {
412 ADD_ROOT_KEY(key_local_machine);
413 REGISTRY_Init();
415 return key_local_machine;
417 case HKEY_USERS:
418 if (!key_users) {
419 ADD_ROOT_KEY(key_users);
421 return key_users;
423 case HKEY_PERFORMANCE_DATA:
424 if (!key_performance_data) {
425 ADD_ROOT_KEY(key_performance_data);
427 return key_performance_data;
429 case HKEY_DYN_DATA:
430 if (!key_dyn_data) {
431 ADD_ROOT_KEY(key_dyn_data);
433 return key_dyn_data;
435 case HKEY_CURRENT_CONFIG:
436 if (!key_current_config) {
437 ADD_ROOT_KEY(key_current_config);
439 return key_current_config;
441 default:
442 return get_handle(hkey);
445 /*NOTREACHED*/
447 #undef ADD_ROOT_KEY
448 /* so we don't accidently access them ... */
449 #define key_current_config NULL NULL
450 #define key_current_user NULL NULL
451 #define key_users NULL NULL
452 #define key_local_machine NULL NULL
453 #define key_classes_root NULL NULL
454 #define key_dyn_data NULL NULL
455 #define key_performance_data NULL NULL
457 /******************************************************************************
458 * split_keypath [Internal]
459 * splits the unicode string 'wp' into an array of strings.
460 * the array is allocated by this function.
461 * Free the array using FREE_KEY_PATH
463 * PARAMS
464 * wp [I] String to split up
465 * wpv [O] Array of pointers to strings
466 * wpc [O] Number of components
468 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
470 int i,j,len;
471 LPWSTR ws;
473 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
475 ws = HEAP_strdupW( SystemHeap, 0, wp );
477 /* We know we have at least one substring */
478 *wpc = 1;
480 /* Replace each backslash with NULL, and increment the count */
481 for (i=0;ws[i];i++) {
482 if (ws[i]=='\\') {
483 ws[i]=0;
484 (*wpc)++;
488 len = i;
490 /* Allocate the space for the array of pointers, leaving room for the
491 NULL at the end */
492 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
493 (*wpv)[0]= ws;
495 /* Assign each pointer to the appropriate character in the string */
496 j = 1;
497 for (i=1;i<len;i++)
498 if (ws[i-1]==0) {
499 (*wpv)[j++]=ws+i;
500 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
503 (*wpv)[j]=NULL;
505 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
510 /******************************************************************************
511 * REGISTRY_Init [Internal]
512 * Registry initialisation, allocates some default keys.
514 static void REGISTRY_Init(void) {
515 HKEY hkey;
516 char buf[200];
518 TRACE(reg,"(void)\n");
520 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
521 RegCloseKey(hkey);
523 /* This was an Open, but since it is called before the real registries
524 are loaded, it was changed to a Create - MTB 980507*/
525 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
526 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
527 RegCloseKey(hkey);
529 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
530 * CurrentVersion
531 * CurrentBuildNumber
532 * CurrentType
533 * string RegisteredOwner
534 * string RegisteredOrganization
537 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
538 * string SysContact
539 * string SysLocation
540 * SysServices
542 if (-1!=gethostname(buf,200)) {
543 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
544 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
545 RegCloseKey(hkey);
550 /************************ SAVE Registry Function ****************************/
552 #define REGISTRY_SAVE_VERSION 0x00000001
554 /* Registry saveformat:
555 * If you change it, increase above number by 1, which will flush
556 * old registry database files.
558 * Global:
559 * "WINE REGISTRY Version %d"
560 * subkeys....
561 * Subkeys:
562 * keyname
563 * valuename=lastmodified,type,data
564 * ...
565 * subkeys
566 * ...
567 * keyname,valuename,stringdata:
568 * the usual ascii characters from 0x00-0xff (well, not 0x00)
569 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
570 * ( "=\\\t" escaped in \uXXXX form.)
571 * type,lastmodified:
572 * int
574 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
576 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
577 * SaveOnlyUpdatedKeys=yes
580 /******************************************************************************
581 * _save_check_tainted [Internal]
583 static int _save_check_tainted( LPKEYSTRUCT lpkey )
585 int tainted;
587 if (!lpkey)
588 return 0;
589 if (lpkey->flags & REG_OPTION_TAINTED)
590 tainted = 1;
591 else
592 tainted = 0;
593 while (lpkey) {
594 if (_save_check_tainted(lpkey->nextsub)) {
595 lpkey->flags |= REG_OPTION_TAINTED;
596 tainted = 1;
598 lpkey = lpkey->next;
600 return tainted;
603 /******************************************************************************
604 * _save_USTRING [Internal]
606 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
608 LPWSTR s;
609 int doescape;
611 if (wstr==NULL)
612 return;
613 s=wstr;
614 while (*s) {
615 doescape=0;
616 if (*s>0xff)
617 doescape = 1;
618 if (*s=='\n')
619 doescape = 1;
620 if (escapeeq && *s=='=')
621 doescape = 1;
622 if (*s=='\\')
623 fputc(*s,F); /* if \\ then put it twice. */
624 if (doescape)
625 fprintf(F,"\\u%04x",*((unsigned short*)s));
626 else
627 fputc(*s,F);
628 s++;
632 /******************************************************************************
633 * _savesubkey [Internal]
635 * NOTES
636 * REG_MULTI_SZ is handled as binary (like in win95) (js)
638 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
640 LPKEYSTRUCT lpxkey;
641 int i,tabs,j;
643 lpxkey = lpkey;
644 while (lpxkey) {
645 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
646 (all || (lpxkey->flags & REG_OPTION_TAINTED))
648 for (tabs=level;tabs--;)
649 fputc('\t',F);
650 _save_USTRING(F,lpxkey->keyname,1);
651 fputs("\n",F);
652 for (i=0;i<lpxkey->nrofvalues;i++) {
653 LPKEYVALUE val=lpxkey->values+i;
655 for (tabs=level+1;tabs--;)
656 fputc('\t',F);
657 _save_USTRING(F,val->name,0);
658 fputc('=',F);
659 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
660 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
661 _save_USTRING(F,(LPWSTR)val->data,0);
662 else
663 for (j=0;j<val->len;j++)
664 fprintf(F,"%02x",*((unsigned char*)val->data+j));
665 fputs("\n",F);
667 /* descend recursively */
668 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
669 return 0;
671 lpxkey=lpxkey->next;
673 return 1;
677 /******************************************************************************
678 * _savesubreg [Internal]
680 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
682 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
683 _save_check_tainted(lpkey->nextsub);
684 return _savesubkey(F,lpkey->nextsub,0,all);
688 /******************************************************************************
689 * _savereg [Internal]
691 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
693 FILE *F;
695 F=fopen(fn,"w");
696 if (F==NULL) {
697 WARN(reg,"Couldn't open %s for writing: %s\n",
698 fn,strerror(errno)
700 return FALSE;
702 if (!_savesubreg(F,lpkey,all)) {
703 fclose(F);
704 unlink(fn);
705 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
706 return FALSE;
708 fclose(F);
709 return TRUE;
713 /******************************************************************************
714 * SHELL_SaveRegistry [Internal]
716 void SHELL_SaveRegistry( void )
718 char *fn;
719 struct passwd *pwd;
720 char buf[4];
721 HKEY hkey;
722 int all;
723 int usedCfgUser = 0;
724 int usedCfgLM = 0;
726 TRACE(reg,"(void)\n");
728 all=0;
729 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
731 strcpy(buf,"yes");
733 else
735 DWORD len,junk,type;
737 len=4;
738 if ( (ERROR_SUCCESS!=RegQueryValueExA(
739 hkey,
740 VAL_SAVEUPDATED,
741 &junk,
742 &type,
743 buf,
744 &len)) || (type!=REG_SZ))
746 strcpy(buf,"yes");
748 RegCloseKey(hkey);
751 if (lstrcmpiA(buf,"yes"))
752 all=1;
754 pwd=getpwuid(getuid());
755 if ( (pwd!=NULL) && (pwd->pw_dir!=NULL))
757 char *tmp;
759 * Save HKEY_CURRENT_USER
760 * Try first saving according to the defined location in .winerc
762 fn = xmalloc( MAX_PATHNAME_LEN );
763 if (PROFILE_GetWineIniString (
764 "Registry",
765 "UserFileName",
766 "",
767 fn,
768 MAX_PATHNAME_LEN - 1))
770 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
771 usedCfgUser = 1;
773 free (fn);
775 if (usedCfgUser != 1)
777 fn=(char*)xmalloc(
778 strlen(pwd->pw_dir) +
779 strlen(WINE_PREFIX) +
780 strlen(SAVE_CURRENT_USER) + 2 );
782 strcpy(fn,pwd->pw_dir);
783 strcat(fn,WINE_PREFIX);
785 /* create the directory. don't care about errorcodes. */
786 mkdir(fn,0755); /* drwxr-xr-x */
787 strcat(fn,"/"SAVE_CURRENT_USER);
789 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
790 strcpy(tmp,fn);
791 strcat(tmp,".tmp");
793 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
794 if (-1==rename(tmp,fn)) {
795 perror("rename tmp registry");
796 unlink(tmp);
799 free(tmp);
800 free(fn);
804 * Save HKEY_LOCAL_MACHINE
805 * Try first saving according to the defined location in .winerc
807 fn = xmalloc ( MAX_PATHNAME_LEN);
808 if (PROFILE_GetWineIniString (
809 "Registry",
810 "LocalMachineFileName",
811 "",
812 fn,
813 MAX_PATHNAME_LEN - 1))
815 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
816 usedCfgLM = 1;
818 free (fn);
820 if ( usedCfgLM != 1)
822 fn=(char*)xmalloc(
823 strlen(pwd->pw_dir)+
824 strlen(WINE_PREFIX)+
825 strlen(SAVE_LOCAL_MACHINE)+2);
827 strcpy(fn,pwd->pw_dir);
828 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
830 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
831 strcpy(tmp,fn);
832 strcat(tmp,".tmp");
834 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
835 if (-1==rename(tmp,fn)) {
836 perror("rename tmp registry");
837 unlink(tmp);
840 free(tmp);
841 free(fn);
845 * Save HKEY_USERS
847 fn=(char*)xmalloc(
848 strlen(pwd->pw_dir)+
849 strlen(WINE_PREFIX)+
850 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
852 strcpy(fn,pwd->pw_dir);
853 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
855 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
856 strcpy(tmp,fn);strcat(tmp,".tmp");
857 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
858 if (-1==rename(tmp,fn)) {
859 perror("rename tmp registry");
860 unlink(tmp);
863 free(tmp);
864 free(fn);
866 else
868 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
873 /************************ LOAD Registry Function ****************************/
877 /******************************************************************************
878 * _find_or_add_key [Internal]
880 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
882 LPKEYSTRUCT lpxkey,*lplpkey;
884 if ((!keyname) || (keyname[0]==0)) {
885 free(keyname);
886 return lpkey;
888 lplpkey= &(lpkey->nextsub);
889 lpxkey = *lplpkey;
890 while (lpxkey) {
891 if ( (lpxkey->keyname[0]==keyname[0]) &&
892 !lstrcmpiW(lpxkey->keyname,keyname)
894 break;
895 lplpkey = &(lpxkey->next);
896 lpxkey = *lplpkey;
898 if (lpxkey==NULL) {
899 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
900 lpxkey = *lplpkey;
901 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
902 lpxkey->keyname = keyname;
903 } else
904 free(keyname);
905 return lpxkey;
908 /******************************************************************************
909 * _find_or_add_value [Internal]
911 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
912 LPBYTE data, DWORD len, DWORD lastmodified )
914 LPKEYVALUE val=NULL;
915 int i;
917 if (name && !*name) {/* empty string equals default (NULL) value */
918 free(name);
919 name = NULL;
922 for (i=0;i<lpkey->nrofvalues;i++) {
923 val=lpkey->values+i;
924 if (name==NULL) {
925 if (val->name==NULL)
926 break;
927 } else {
928 if ( val->name!=NULL &&
929 val->name[0]==name[0] &&
930 !lstrcmpiW(val->name,name)
932 break;
935 if (i==lpkey->nrofvalues) {
936 lpkey->values = xrealloc(
937 lpkey->values,
938 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
940 val=lpkey->values+i;
941 memset(val,'\0',sizeof(KEYVALUE));
942 val->name = name;
943 } else {
944 if (name)
945 free(name);
947 if (val->lastmodified<lastmodified) {
948 val->lastmodified=lastmodified;
949 val->type = type;
950 val->len = len;
951 if (val->data)
952 free(val->data);
953 val->data = data;
954 } else
955 free(data);
959 /******************************************************************************
960 * _wine_read_line [Internal]
962 * reads a line including dynamically enlarging the readbuffer and throwing
963 * away comments
965 static int _wine_read_line( FILE *F, char **buf, int *len )
967 char *s,*curread;
968 int mylen,curoff;
970 curread = *buf;
971 mylen = *len;
972 **buf = '\0';
973 while (1) {
974 while (1) {
975 s=fgets(curread,mylen,F);
976 if (s==NULL)
977 return 0; /* EOF */
978 if (NULL==(s=strchr(curread,'\n'))) {
979 /* buffer wasn't large enough */
980 curoff = strlen(*buf);
981 *buf = xrealloc(*buf,*len*2);
982 curread = *buf + curoff;
983 mylen = *len; /* we filled up the buffer and
984 * got new '*len' bytes to fill
986 *len = *len * 2;
987 } else {
988 *s='\0';
989 break;
992 /* throw away comments */
993 if (**buf=='#' || **buf==';') {
994 curread = *buf;
995 mylen = *len;
996 continue;
998 if (s) /* got end of line */
999 break;
1001 return 1;
1005 /******************************************************************************
1006 * _wine_read_USTRING [Internal]
1008 * converts a char* into a UNICODE string (up to a special char)
1009 * and returns the position exactly after that string
1011 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1013 char *s;
1014 LPWSTR ws;
1016 /* read up to "=" or "\0" or "\n" */
1017 s = buf;
1018 if (*s == '=') {
1019 /* empty string is the win3.1 default value(NULL)*/
1020 *str = NULL;
1021 return s;
1023 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1024 ws = *str;
1025 while (*s && (*s!='\n') && (*s!='=')) {
1026 if (*s!='\\')
1027 *ws++=*((unsigned char*)s++);
1028 else {
1029 s++;
1030 if (!*s) {
1031 /* Dangling \ ... may only happen if a registry
1032 * write was short. FIXME: What do to?
1034 break;
1036 if (*s=='\\') {
1037 *ws++='\\';
1038 s++;
1039 continue;
1041 if (*s!='u') {
1042 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1043 *ws++='\\';
1044 *ws++=*s++;
1045 } else {
1046 char xbuf[5];
1047 int wc;
1049 s++;
1050 memcpy(xbuf,s,4);xbuf[4]='\0';
1051 if (!sscanf(xbuf,"%x",&wc))
1052 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
1053 s+=4;
1054 *ws++ =(unsigned short)wc;
1058 *ws = 0;
1059 ws = *str;
1060 if (*ws)
1061 *str = strdupW(*str);
1062 else
1063 *str = NULL;
1064 free(ws);
1065 return s;
1069 /******************************************************************************
1070 * _wine_loadsubkey [Internal]
1072 * NOTES
1073 * It seems like this is returning a boolean. Should it?
1075 * RETURNS
1076 * Success: 1
1077 * Failure: 0
1079 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1080 int *buflen, DWORD optflag )
1082 LPKEYSTRUCT lpxkey;
1083 int i;
1084 char *s;
1085 LPWSTR name;
1087 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1088 *buflen, optflag);
1090 lpkey->flags |= optflag;
1092 /* Good. We already got a line here ... so parse it */
1093 lpxkey = NULL;
1094 while (1) {
1095 i=0;s=*buf;
1096 while (*s=='\t') {
1097 s++;
1098 i++;
1100 if (i>level) {
1101 if (lpxkey==NULL) {
1102 WARN(reg,"Got a subhierarchy without resp. key?\n");
1103 return 0;
1105 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1106 continue;
1109 /* let the caller handle this line */
1110 if (i<level || **buf=='\0')
1111 return 1;
1113 /* it can be: a value or a keyname. Parse the name first */
1114 s=_wine_read_USTRING(s,&name);
1116 /* switch() default: hack to avoid gotos */
1117 switch (0) {
1118 default:
1119 if (*s=='\0') {
1120 lpxkey=_find_or_add_key(lpkey,name);
1121 } else {
1122 LPBYTE data;
1123 int len,lastmodified,type;
1125 if (*s!='=') {
1126 WARN(reg,"Unexpected character: %c\n",*s);
1127 break;
1129 s++;
1130 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1131 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1132 break;
1134 /* skip the 2 , */
1135 s=strchr(s,',');s++;
1136 s=strchr(s,',');s++;
1137 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1138 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1139 if (data)
1140 len = lstrlenW((LPWSTR)data)*2+2;
1141 else
1142 len = 0;
1143 } else {
1144 len=strlen(s)/2;
1145 data = (LPBYTE)xmalloc(len+1);
1146 for (i=0;i<len;i++) {
1147 data[i]=0;
1148 if (*s>='0' && *s<='9')
1149 data[i]=(*s-'0')<<4;
1150 if (*s>='a' && *s<='f')
1151 data[i]=(*s-'a'+'\xa')<<4;
1152 if (*s>='A' && *s<='F')
1153 data[i]=(*s-'A'+'\xa')<<4;
1154 s++;
1155 if (*s>='0' && *s<='9')
1156 data[i]|=*s-'0';
1157 if (*s>='a' && *s<='f')
1158 data[i]|=*s-'a'+'\xa';
1159 if (*s>='A' && *s<='F')
1160 data[i]|=*s-'A'+'\xa';
1161 s++;
1164 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1167 /* read the next line */
1168 if (!_wine_read_line(F,buf,buflen))
1169 return 1;
1171 return 1;
1175 /******************************************************************************
1176 * _wine_loadsubreg [Internal]
1178 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1180 int ver;
1181 char *buf;
1182 int buflen;
1184 buf=xmalloc(10);buflen=10;
1185 if (!_wine_read_line(F,&buf,&buflen)) {
1186 free(buf);
1187 return 0;
1189 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1190 free(buf);
1191 return 0;
1193 if (ver!=REGISTRY_SAVE_VERSION) {
1194 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1195 free(buf);
1196 return 0;
1198 if (!_wine_read_line(F,&buf,&buflen)) {
1199 free(buf);
1200 return 0;
1202 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1203 free(buf);
1204 return 0;
1206 free(buf);
1207 return 1;
1211 /******************************************************************************
1212 * _wine_loadreg [Internal]
1214 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1216 FILE *F;
1218 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1220 F = fopen(fn,"rb");
1221 if (F==NULL) {
1222 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1223 return;
1225 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1226 fclose(F);
1227 unlink(fn);
1228 return;
1230 fclose(F);
1233 /******************************************************************************
1234 * _flush_registry [Internal]
1236 * This function allow to flush section of the internal registry. It is mainly
1237 * implements to fix a problem with the global HKU and the local HKU.
1238 * Those two files are read to build the HKU\.Default branch to finaly copy
1239 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1240 * all the global HKU are saved onto the user's personal version of HKU hive.
1241 * which is bad...
1244 /* Forward declaration of recusive agent */
1245 static void _flush_reg(LPKEYSTRUCT from);
1247 static void _flush_registry( LPKEYSTRUCT from )
1249 /* make sure we have something... */
1250 if (from == NULL)
1251 return;
1253 /* Launch the recusive agent on sub branches */
1254 _flush_reg( from->nextsub );
1255 _flush_reg( from->next );
1257 /* Initialize pointers */
1258 from->nextsub = NULL;
1259 from->next = NULL;
1261 static void _flush_reg( LPKEYSTRUCT from )
1263 int j;
1265 /* make sure we have something... */
1266 if (from == NULL)
1267 return;
1270 * do the same for the child keys
1272 if (from->nextsub != NULL)
1273 _flush_reg(from->nextsub);
1276 * do the same for the sibling keys
1278 if (from->next != NULL)
1279 _flush_reg(from->next);
1282 * iterate through this key's values and delete them
1284 for (j=0;j<from->nrofvalues;j++)
1286 free( (from->values+j)->name);
1287 free( (from->values+j)->data);
1291 * free the structure
1293 if ( from != NULL )
1294 free(from);
1298 /******************************************************************************
1299 * _copy_registry [Internal]
1301 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1303 LPKEYSTRUCT lpxkey;
1304 int j;
1305 LPKEYVALUE valfrom;
1307 from=from->nextsub;
1308 while (from) {
1309 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1311 for (j=0;j<from->nrofvalues;j++) {
1312 LPWSTR name;
1313 LPBYTE data;
1315 valfrom = from->values+j;
1316 name=valfrom->name;
1317 if (name) name=strdupW(name);
1318 data=(LPBYTE)xmalloc(valfrom->len);
1319 memcpy(data,valfrom->data,valfrom->len);
1321 _find_or_add_value(
1322 lpxkey,
1323 name,
1324 valfrom->type,
1325 data,
1326 valfrom->len,
1327 valfrom->lastmodified
1330 _copy_registry(from,lpxkey);
1331 from = from->next;
1336 /* WINDOWS 95 REGISTRY LOADER */
1338 * Structure of a win95 registry database.
1339 * main header:
1340 * 0 : "CREG" - magic
1341 * 4 : DWORD version
1342 * 8 : DWORD offset_of_RGDB_part
1343 * 0C..0F: ? (someone fill in please)
1344 * 10: WORD number of RGDB blocks
1345 * 12: WORD ?
1346 * 14: WORD always 0000?
1347 * 16: WORD always 0001?
1348 * 18..1F: ? (someone fill in please)
1350 * 20: RGKN_section:
1351 * header:
1352 * 0 : "RGKN" - magic
1353 * 4 : DWORD offset to first RGDB section
1354 * 8 : DWORD offset to the root record
1355 * C..0x1B: ? (fill in)
1356 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1358 * Disk Key Entry Structure:
1359 * 00: DWORD - Free entry indicator(?)
1360 * 04: DWORD - Hash = sum of bytes of keyname
1361 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1362 * 0C: DWORD - disk address of PreviousLevel Key.
1363 * 10: DWORD - disk address of Next Sublevel Key.
1364 * 14: DWORD - disk address of Next Key (on same level).
1365 * DKEP>18: WORD - Nr, Low Significant part.
1366 * 1A: WORD - Nr, High Significant part.
1368 * The disk address always points to the nr part of the previous key entry
1369 * of the referenced key. Don't ask me why, or even if I got this correct
1370 * from staring at 1kg of hexdumps. (DKEP)
1372 * The High significant part of the structure seems to equal the number
1373 * of the RGDB section. The low significant part is a unique ID within
1374 * that RGDB section
1376 * There are two minor corrections to the position of that structure.
1377 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1378 * the DKE reread from there.
1379 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1380 * CPS - I have not experienced the above phenomenon in my registry files
1382 * RGDB_section:
1383 * 00: "RGDB" - magic
1384 * 04: DWORD offset to next RGDB section
1385 * 08: DWORD ?
1386 * 0C: WORD always 000d?
1387 * 0E: WORD RGDB block number
1388 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1389 * 14..1F: ?
1390 * 20.....: disk keys
1392 * disk key:
1393 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1394 * 08: WORD nrLS - low significant part of NR
1395 * 0A: WORD nrHS - high significant part of NR
1396 * 0C: DWORD bytesused - bytes used in this structure.
1397 * 10: WORD name_len - length of name in bytes. without \0
1398 * 12: WORD nr_of_values - number of values.
1399 * 14: char name[name_len] - name string. No \0.
1400 * 14+name_len: disk values
1401 * nextkeyoffset: ... next disk key
1403 * disk value:
1404 * 00: DWORD type - value type (hmm, could be WORD too)
1405 * 04: DWORD - unknown, usually 0
1406 * 08: WORD namelen - length of Name. 0 means name=NULL
1407 * 0C: WORD datalen - length of Data.
1408 * 10: char name[namelen] - name, no \0
1409 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1410 * 10+namelen+datalen: next values or disk key
1412 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1413 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1414 * structure) and reading another RGDB_section.
1415 * repeat until end of file.
1417 * An interesting relationship exists in RGDB_section. The value at offset
1418 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1419 * idea at the moment what this means. (Kevin Cozens)
1421 * FIXME: this description needs some serious help, yes.
1424 struct _w95keyvalue {
1425 unsigned long type;
1426 unsigned short datalen;
1427 char *name;
1428 unsigned char *data;
1429 unsigned long x1;
1430 int lastmodified;
1433 struct _w95key {
1434 char *name;
1435 int nrofvals;
1436 struct _w95keyvalue *values;
1437 struct _w95key *prevlvl;
1438 struct _w95key *nextsub;
1439 struct _w95key *next;
1443 struct _w95_info {
1444 char *rgknbuffer;
1445 int rgknsize;
1446 char *rgdbbuffer;
1447 int rgdbsize;
1448 int depth;
1449 int lastmodified;
1453 /******************************************************************************
1454 * _w95_processKey [Internal]
1456 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1457 int nrLS, int nrMS, struct _w95_info *info )
1460 /* Disk Key Header structure (RGDB part) */
1461 struct dkh {
1462 unsigned long nextkeyoff;
1463 unsigned short nrLS;
1464 unsigned short nrMS;
1465 unsigned long bytesused;
1466 unsigned short keynamelen;
1467 unsigned short values;
1468 unsigned long xx1;
1469 /* keyname */
1470 /* disk key values or nothing */
1472 /* Disk Key Value structure */
1473 struct dkv {
1474 unsigned long type;
1475 unsigned long x1;
1476 unsigned short valnamelen;
1477 unsigned short valdatalen;
1478 /* valname, valdata */
1482 struct dkh dkh;
1483 int bytesread = 0;
1484 char *rgdbdata = info->rgdbbuffer;
1485 int nbytes = info->rgdbsize;
1486 char *curdata = rgdbdata;
1487 char *end = rgdbdata + nbytes;
1488 int off_next_rgdb;
1489 char *next = rgdbdata;
1490 int nrgdb, i;
1491 LPKEYSTRUCT lpxkey;
1493 do {
1494 curdata = next;
1495 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1497 memcpy(&off_next_rgdb,curdata+4,4);
1498 next = curdata + off_next_rgdb;
1499 nrgdb = (int) *((short *)curdata + 7);
1501 } while (nrgdb != nrMS && (next < end));
1503 /* curdata now points to the start of the right RGDB section */
1504 curdata += 0x20;
1506 #define XREAD(whereto,len) \
1507 if ((curdata + len) <= end) {\
1508 memcpy(whereto,curdata,len);\
1509 curdata+=len;\
1510 bytesread+=len;\
1513 while (curdata < next) {
1514 struct dkh *xdkh = (struct dkh*)curdata;
1516 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1517 if (xdkh->nrLS == nrLS) {
1518 memcpy(&dkh,xdkh,sizeof(dkh));
1519 curdata += sizeof(dkh);
1520 break;
1522 curdata += xdkh->nextkeyoff;
1525 if (dkh.nrLS != nrLS) return (NULL);
1527 if (nrgdb != dkh.nrMS)
1528 return (NULL);
1530 assert((dkh.keynamelen<2) || curdata[0]);
1531 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1532 curdata += dkh.keynamelen;
1534 for (i=0;i< dkh.values; i++) {
1535 struct dkv dkv;
1536 LPBYTE data;
1537 int len;
1538 LPWSTR name;
1540 XREAD(&dkv,sizeof(dkv));
1542 name = strcvtA2W(curdata, dkv.valnamelen);
1543 curdata += dkv.valnamelen;
1545 if ((1 << dkv.type) & UNICONVMASK) {
1546 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1547 len = 2*(dkv.valdatalen + 1);
1548 } else {
1549 /* I don't think we want to NULL terminate all data */
1550 data = xmalloc(dkv.valdatalen);
1551 memcpy (data, curdata, dkv.valdatalen);
1552 len = dkv.valdatalen;
1555 curdata += dkv.valdatalen;
1557 _find_or_add_value(
1558 lpxkey,
1559 name,
1560 dkv.type,
1561 data,
1562 len,
1563 info->lastmodified
1566 return (lpxkey);
1569 /******************************************************************************
1570 * _w95_walkrgkn [Internal]
1572 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1573 struct _w95_info *info )
1576 /* Disk Key Entry structure (RGKN part) */
1577 struct dke {
1578 unsigned long x1;
1579 unsigned long x2;
1580 unsigned long x3;/*usually 0xFFFFFFFF */
1581 unsigned long prevlvl;
1582 unsigned long nextsub;
1583 unsigned long next;
1584 unsigned short nrLS;
1585 unsigned short nrMS;
1586 } *dke = (struct dke *)off;
1587 LPKEYSTRUCT lpxkey;
1589 if (dke == NULL) {
1590 dke = (struct dke *) ((char *)info->rgknbuffer);
1593 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1594 /* XXX <-- This is a hack*/
1595 if (!lpxkey) {
1596 lpxkey = prevkey;
1599 if (dke->nextsub != -1 &&
1600 ((dke->nextsub - 0x20) < info->rgknsize)
1601 && (dke->nextsub > 0x20)) {
1603 _w95_walkrgkn(lpxkey,
1604 info->rgknbuffer + dke->nextsub - 0x20,
1605 info);
1608 if (dke->next != -1 &&
1609 ((dke->next - 0x20) < info->rgknsize) &&
1610 (dke->next > 0x20)) {
1611 _w95_walkrgkn(prevkey,
1612 info->rgknbuffer + dke->next - 0x20,
1613 info);
1616 return;
1620 /******************************************************************************
1621 * _w95_loadreg [Internal]
1623 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1625 HFILE hfd;
1626 char magic[5];
1627 unsigned long where,version,rgdbsection,end;
1628 struct _w95_info info;
1629 OFSTRUCT ofs;
1630 BY_HANDLE_FILE_INFORMATION hfdinfo;
1632 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1633 hfd=OpenFile(fn,&ofs,OF_READ);
1634 if (hfd==HFILE_ERROR)
1635 return;
1636 magic[4]=0;
1637 if (4!=_lread(hfd,magic,4))
1638 return;
1639 if (strcmp(magic,"CREG")) {
1640 WARN(reg,"%s is not a w95 registry.\n",fn);
1641 return;
1643 if (4!=_lread(hfd,&version,4))
1644 return;
1645 if (4!=_lread(hfd,&rgdbsection,4))
1646 return;
1647 if (-1==_llseek(hfd,0x20,SEEK_SET))
1648 return;
1649 if (4!=_lread(hfd,magic,4))
1650 return;
1651 if (strcmp(magic,"RGKN")) {
1652 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1653 return;
1656 /* STEP 1: Keylink structures */
1657 if (-1==_llseek(hfd,0x40,SEEK_SET))
1658 return;
1659 where = 0x40;
1660 end = rgdbsection;
1662 info.rgknsize = end - where;
1663 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1664 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1665 return;
1667 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1668 return;
1670 end = hfdinfo.nFileSizeLow;
1671 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1673 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1674 return;
1676 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1677 info.rgdbsize = end - rgdbsection;
1679 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1680 return;
1681 _lclose(hfd);
1683 _w95_walkrgkn(lpkey, NULL, &info);
1685 free (info.rgdbbuffer);
1686 free (info.rgknbuffer);
1690 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1693 reghack - windows 3.11 registry data format demo program.
1695 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1696 a combined hash table and tree description, and finally a text table.
1698 The header is obvious from the struct header. The taboff1 and taboff2
1699 fields are always 0x20, and their usage is unknown.
1701 The 8-byte entry table has various entry types.
1703 tabent[0] is a root index. The second word has the index of the root of
1704 the directory.
1705 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1706 the index of the key/value that has that hash. Data with the same
1707 hash value are on a circular list. The other three words in the
1708 hash entry are always zero.
1709 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1710 entry: dirent and keyent/valent. They are identified by context.
1711 tabent[freeidx] is the first free entry. The first word in a free entry
1712 is the index of the next free entry. The last has 0 as a link.
1713 The other three words in the free list are probably irrelevant.
1715 Entries in text table are preceeded by a word at offset-2. This word
1716 has the value (2*index)+1, where index is the referring keyent/valent
1717 entry in the table. I have no suggestion for the 2* and the +1.
1718 Following the word, there are N bytes of data, as per the keyent/valent
1719 entry length. The offset of the keyent/valent entry is from the start
1720 of the text table to the first data byte.
1722 This information is not available from Microsoft. The data format is
1723 deduced from the reg.dat file by me. Mistakes may
1724 have been made. I claim no rights and give no guarantees for this program.
1726 Tor Sjøwall, tor@sn.no
1729 /* reg.dat header format */
1730 struct _w31_header {
1731 char cookie[8]; /* 'SHCC3.10' */
1732 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1733 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1734 unsigned long tabcnt; /* number of entries in index table */
1735 unsigned long textoff; /* offset of text part */
1736 unsigned long textsize; /* byte size of text part */
1737 unsigned short hashsize; /* hash size */
1738 unsigned short freeidx; /* free index */
1741 /* generic format of table entries */
1742 struct _w31_tabent {
1743 unsigned short w0, w1, w2, w3;
1746 /* directory tabent: */
1747 struct _w31_dirent {
1748 unsigned short sibling_idx; /* table index of sibling dirent */
1749 unsigned short child_idx; /* table index of child dirent */
1750 unsigned short key_idx; /* table index of key keyent */
1751 unsigned short value_idx; /* table index of value valent */
1754 /* key tabent: */
1755 struct _w31_keyent {
1756 unsigned short hash_idx; /* hash chain index for string */
1757 unsigned short refcnt; /* reference count */
1758 unsigned short length; /* length of string */
1759 unsigned short string_off; /* offset of string in text table */
1762 /* value tabent: */
1763 struct _w31_valent {
1764 unsigned short hash_idx; /* hash chain index for string */
1765 unsigned short refcnt; /* reference count */
1766 unsigned short length; /* length of string */
1767 unsigned short string_off; /* offset of string in text table */
1770 /* recursive helper function to display a directory tree */
1771 void
1772 __w31_dumptree( unsigned short idx,
1773 unsigned char *txt,
1774 struct _w31_tabent *tab,
1775 struct _w31_header *head,
1776 LPKEYSTRUCT lpkey,
1777 time_t lastmodified,
1778 int level
1780 struct _w31_dirent *dir;
1781 struct _w31_keyent *key;
1782 struct _w31_valent *val;
1783 LPKEYSTRUCT xlpkey = NULL;
1784 LPWSTR name,value;
1785 static char tail[400];
1787 while (idx!=0) {
1788 dir=(struct _w31_dirent*)&tab[idx];
1790 if (dir->key_idx) {
1791 key = (struct _w31_keyent*)&tab[dir->key_idx];
1793 memcpy(tail,&txt[key->string_off],key->length);
1794 tail[key->length]='\0';
1795 /* all toplevel entries AND the entries in the
1796 * toplevel subdirectory belong to \SOFTWARE\Classes
1798 if (!level && !lstrcmpA(tail,".classes")) {
1799 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1800 idx=dir->sibling_idx;
1801 continue;
1803 name=strdupA2W(tail);
1805 xlpkey=_find_or_add_key(lpkey,name);
1807 /* only add if leaf node or valued node */
1808 if (dir->value_idx!=0||dir->child_idx==0) {
1809 if (dir->value_idx) {
1810 val=(struct _w31_valent*)&tab[dir->value_idx];
1811 memcpy(tail,&txt[val->string_off],val->length);
1812 tail[val->length]='\0';
1813 value=strdupA2W(tail);
1814 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1817 } else {
1818 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1820 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1821 idx=dir->sibling_idx;
1826 /******************************************************************************
1827 * _w31_loadreg [Internal]
1829 void _w31_loadreg(void) {
1830 HFILE hf;
1831 struct _w31_header head;
1832 struct _w31_tabent *tab;
1833 unsigned char *txt;
1834 int len;
1835 OFSTRUCT ofs;
1836 BY_HANDLE_FILE_INFORMATION hfinfo;
1837 time_t lastmodified;
1838 LPKEYSTRUCT lpkey;
1840 TRACE(reg,"(void)\n");
1842 hf = OpenFile("reg.dat",&ofs,OF_READ);
1843 if (hf==HFILE_ERROR)
1844 return;
1846 /* read & dump header */
1847 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1848 ERR(reg, "reg.dat is too short.\n");
1849 _lclose(hf);
1850 return;
1852 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1853 ERR(reg, "reg.dat has bad signature.\n");
1854 _lclose(hf);
1855 return;
1858 len = head.tabcnt * sizeof(struct _w31_tabent);
1859 /* read and dump index table */
1860 tab = xmalloc(len);
1861 if (len!=_lread(hf,tab,len)) {
1862 ERR(reg,"couldn't read %d bytes.\n",len);
1863 free(tab);
1864 _lclose(hf);
1865 return;
1868 /* read text */
1869 txt = xmalloc(head.textsize);
1870 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1871 ERR(reg,"couldn't seek to textblock.\n");
1872 free(tab);
1873 free(txt);
1874 _lclose(hf);
1875 return;
1877 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1878 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1879 free(tab);
1880 free(txt);
1881 _lclose(hf);
1882 return;
1885 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1886 ERR(reg,"GetFileInformationByHandle failed?.\n");
1887 free(tab);
1888 free(txt);
1889 _lclose(hf);
1890 return;
1892 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1893 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1894 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1895 free(tab);
1896 free(txt);
1897 _lclose(hf);
1898 return;
1902 /**********************************************************************************
1903 * SHELL_LoadRegistry [Internal]
1905 void SHELL_LoadRegistry( void )
1907 char *fn;
1908 struct passwd *pwd;
1909 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1910 HKEY hkey;
1912 TRACE(reg,"(void)\n");
1914 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1915 HKU = lookup_hkey(HKEY_USERS);
1916 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1918 /* Load windows 3.1 entries */
1919 _w31_loadreg();
1920 /* Load windows 95 entries */
1921 _w95_loadreg("C:\\system.1st", HKLM);
1922 _w95_loadreg("system.dat", HKLM);
1923 _w95_loadreg("user.dat", HKU);
1926 * Load the global HKU hive directly from /usr/local/etc
1928 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1931 * Load the global machine defaults directly form /usr/local/etc
1933 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1935 /* Get current user info */
1936 pwd=getpwuid(getuid());
1939 * Load the user saved registries
1941 if ( (pwd != NULL) &&
1942 (pwd->pw_dir != NULL) )
1945 * Load user's personal versions of global HKU/.Default keys
1947 fn=(char*)xmalloc(
1948 strlen(pwd->pw_dir)+
1949 strlen(WINE_PREFIX)+
1950 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1952 strcpy(fn, pwd->pw_dir);
1953 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1954 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1955 free(fn);
1958 * Load HKCU, attempt to get the registry location from the config
1959 * file first, if exist, load and keep going.
1961 fn = xmalloc( MAX_PATHNAME_LEN );
1962 if ( PROFILE_GetWineIniString(
1963 "Registry",
1964 "UserFileName",
1965 "",
1966 fn,
1967 MAX_PATHNAME_LEN - 1))
1969 _wine_loadreg(HKCU,fn,0);
1971 free (fn);
1973 fn=(char*)xmalloc(
1974 strlen(pwd->pw_dir)+
1975 strlen(WINE_PREFIX)+
1976 strlen(SAVE_CURRENT_USER)+2);
1978 strcpy(fn, pwd->pw_dir);
1979 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1980 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1981 free(fn);
1984 * Load HKLM, attempt to get the registry location from the config
1985 * file first, if exist, load and keep going.
1987 fn = xmalloc ( MAX_PATHNAME_LEN);
1988 if ( PROFILE_GetWineIniString(
1989 "Registry",
1990 "LocalMachineFileName",
1991 "",
1992 fn,
1993 MAX_PATHNAME_LEN - 1))
1995 _wine_loadreg(HKLM, fn, 0);
1997 free(fn);
1999 fn=(char*)xmalloc(
2000 strlen(pwd->pw_dir)+
2001 strlen(WINE_PREFIX)+
2002 strlen(SAVE_LOCAL_MACHINE)+2);
2004 strcpy(fn,pwd->pw_dir);
2005 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2006 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2007 free(fn);
2009 else
2011 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
2015 * Obtain the handle of the HKU\.Default key.
2016 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2018 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2019 lpkey = lookup_hkey(hkey);
2020 if(!lpkey)
2021 WARN(reg,"Could not create global user default key\n");
2022 else
2023 _copy_registry(lpkey, HKCU );
2025 RegCloseKey(hkey);
2028 * Since HKU is built from the global HKU and the local user HKU file we must
2029 * flush the HKU tree we have built at this point otherwise the part brought
2030 * in from the global HKU is saved into the local HKU. To avoid this
2031 * useless dupplication of HKU keys we reread the local HKU key.
2034 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2035 _flush_registry(HKU);
2037 /* Reload user's local HKU hive */
2038 fn=(char*)xmalloc(
2039 strlen(pwd->pw_dir)+
2040 strlen(WINE_PREFIX)+
2041 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2043 strcpy(fn,pwd->pw_dir);
2044 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2046 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2048 free(fn);
2051 * Make sure the update mode is there
2053 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2055 DWORD junk,type,len;
2056 char data[5];
2058 len=4;
2059 if (( RegQueryValueExA(
2060 hkey,
2061 VAL_SAVEUPDATED,
2062 &junk,
2063 &type,
2064 data,
2065 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2067 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2070 RegCloseKey(hkey);
2075 /********************* API FUNCTIONS ***************************************/
2077 * Open Keys.
2079 * All functions are stubs to RegOpenKeyEx32W where all the
2080 * magic happens.
2082 * Callpath:
2083 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2084 * RegOpenKey32W -> RegOpenKeyEx32W
2088 /******************************************************************************
2089 * RegOpenKeyEx32W [ADVAPI32.150]
2090 * Opens the specified key
2092 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2094 * PARAMS
2095 * hkey [I] Handle of open key
2096 * lpszSubKey [I] Name of subkey to open
2097 * dwReserved [I] Reserved - must be zero
2098 * samDesired [I] Security access mask
2099 * retkey [O] Address of handle of open key
2101 * RETURNS
2102 * Success: ERROR_SUCCESS
2103 * Failure: Error code
2105 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2106 REGSAM samDesired, LPHKEY retkey )
2108 LPKEYSTRUCT lpNextKey,lpxkey;
2109 LPWSTR *wps;
2110 int wpc,i;
2112 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2113 samDesired,retkey);
2115 lpNextKey = lookup_hkey( hkey );
2116 if (!lpNextKey)
2117 return ERROR_INVALID_HANDLE;
2119 if (!lpszSubKey || !*lpszSubKey) {
2120 /* Either NULL or pointer to empty string, so return a new handle
2121 to the original hkey */
2122 currenthandle += 2;
2123 add_handle(currenthandle,lpNextKey,samDesired);
2124 *retkey=currenthandle;
2125 return ERROR_SUCCESS;
2128 if (lpszSubKey[0] == '\\') {
2129 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2130 return ERROR_BAD_PATHNAME;
2133 split_keypath(lpszSubKey,&wps,&wpc);
2134 i = 0;
2135 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2136 lpxkey = lpNextKey;
2138 while (wps[i]) {
2139 lpxkey=lpNextKey->nextsub;
2140 while (lpxkey) {
2141 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2142 break;
2144 lpxkey=lpxkey->next;
2147 if (!lpxkey) {
2148 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
2149 FREE_KEY_PATH;
2150 return ERROR_FILE_NOT_FOUND;
2152 i++;
2153 lpNextKey = lpxkey;
2156 currenthandle += 2;
2157 add_handle(currenthandle,lpxkey,samDesired);
2158 *retkey = currenthandle;
2159 TRACE(reg," Returning %x\n", currenthandle);
2160 FREE_KEY_PATH;
2161 return ERROR_SUCCESS;
2165 /******************************************************************************
2166 * RegOpenKeyEx32A [ADVAPI32.149]
2168 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2169 REGSAM samDesired, LPHKEY retkey )
2171 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2172 DWORD ret;
2174 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2175 samDesired,retkey);
2176 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2177 free(lpszSubKeyW);
2178 return ret;
2182 /******************************************************************************
2183 * RegOpenKey32W [ADVAPI32.151]
2185 * PARAMS
2186 * hkey [I] Handle of open key
2187 * lpszSubKey [I] Address of name of subkey to open
2188 * retkey [O] Address of handle of open key
2190 * RETURNS
2191 * Success: ERROR_SUCCESS
2192 * Failure: Error code
2194 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2196 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2197 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2201 /******************************************************************************
2202 * RegOpenKey32A [ADVAPI32.148]
2204 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2206 DWORD ret;
2207 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2208 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2209 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2210 free(lpszSubKeyW);
2211 return ret;
2215 /******************************************************************************
2216 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2218 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2220 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2221 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2226 * Create keys
2228 * All those functions convert their respective
2229 * arguments and call RegCreateKeyExW at the end.
2231 * We stay away from the Ex functions as long as possible because there are
2232 * differences in the return values
2234 * Callpath:
2235 * RegCreateKeyEx32A \
2236 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2240 /******************************************************************************
2241 * RegCreateKeyEx32W [ADVAPI32.131]
2243 * PARAMS
2244 * hkey [I] Handle of an open key
2245 * lpszSubKey [I] Address of subkey name
2246 * dwReserved [I] Reserved - must be 0
2247 * lpszClass [I] Address of class string
2248 * fdwOptions [I] Special options flag
2249 * samDesired [I] Desired security access
2250 * lpSecAttribs [I] Address of key security structure
2251 * retkey [O] Address of buffer for opened handle
2252 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2254 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2255 DWORD dwReserved, LPWSTR lpszClass,
2256 DWORD fdwOptions, REGSAM samDesired,
2257 LPSECURITY_ATTRIBUTES lpSecAttribs,
2258 LPHKEY retkey, LPDWORD lpDispos )
2260 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2261 LPWSTR *wps;
2262 int wpc,i;
2264 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2265 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2266 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2268 lpNextKey = lookup_hkey(hkey);
2269 if (!lpNextKey)
2270 return ERROR_INVALID_HANDLE;
2272 /* Check for valid options */
2273 switch(fdwOptions) {
2274 case REG_OPTION_NON_VOLATILE:
2275 case REG_OPTION_VOLATILE:
2276 case REG_OPTION_BACKUP_RESTORE:
2277 break;
2278 default:
2279 return ERROR_INVALID_PARAMETER;
2282 /* Sam has to be a combination of the following */
2283 if (!(samDesired &
2284 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2285 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2286 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2287 return ERROR_INVALID_PARAMETER;
2289 if (!lpszSubKey || !*lpszSubKey) {
2290 currenthandle += 2;
2291 add_handle(currenthandle,lpNextKey,samDesired);
2292 *retkey=currenthandle;
2293 TRACE(reg, "Returning %x\n", currenthandle);
2294 lpNextKey->flags|=REG_OPTION_TAINTED;
2295 return ERROR_SUCCESS;
2298 if (lpszSubKey[0] == '\\') {
2299 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2300 return ERROR_BAD_PATHNAME;
2303 split_keypath(lpszSubKey,&wps,&wpc);
2304 i = 0;
2305 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2306 lpxkey = lpNextKey;
2307 while (wps[i]) {
2308 lpxkey=lpNextKey->nextsub;
2309 while (lpxkey) {
2310 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2311 break;
2312 lpxkey=lpxkey->next;
2314 if (!lpxkey)
2315 break;
2316 i++;
2317 lpNextKey = lpxkey;
2319 if (lpxkey) {
2320 currenthandle += 2;
2321 add_handle(currenthandle,lpxkey,samDesired);
2322 lpxkey->flags |= REG_OPTION_TAINTED;
2323 *retkey = currenthandle;
2324 TRACE(reg, "Returning %x\n", currenthandle);
2325 if (lpDispos)
2326 *lpDispos = REG_OPENED_EXISTING_KEY;
2327 FREE_KEY_PATH;
2328 return ERROR_SUCCESS;
2331 /* Good. Now the hard part */
2332 while (wps[i]) {
2333 lplpPrevKey = &(lpNextKey->nextsub);
2334 lpxkey = *lplpPrevKey;
2335 while (lpxkey) {
2336 lplpPrevKey = &(lpxkey->next);
2337 lpxkey = *lplpPrevKey;
2339 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2340 if (!*lplpPrevKey) {
2341 FREE_KEY_PATH;
2342 TRACE(reg, "Returning OUTOFMEMORY\n");
2343 return ERROR_OUTOFMEMORY;
2345 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2346 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2347 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2348 (*lplpPrevKey)->next = NULL;
2349 (*lplpPrevKey)->nextsub = NULL;
2350 (*lplpPrevKey)->values = NULL;
2351 (*lplpPrevKey)->nrofvalues = 0;
2352 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2353 if (lpszClass)
2354 (*lplpPrevKey)->class = strdupW(lpszClass);
2355 else
2356 (*lplpPrevKey)->class = NULL;
2357 lpNextKey = *lplpPrevKey;
2358 i++;
2360 currenthandle += 2;
2361 add_handle(currenthandle,lpNextKey,samDesired);
2363 /*FIXME: flag handling correct? */
2364 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2365 if (lpszClass)
2366 lpNextKey->class = strdupW(lpszClass);
2367 else
2368 lpNextKey->class = NULL;
2369 *retkey = currenthandle;
2370 TRACE(reg, "Returning %x\n", currenthandle);
2371 if (lpDispos)
2372 *lpDispos = REG_CREATED_NEW_KEY;
2373 FREE_KEY_PATH;
2374 return ERROR_SUCCESS;
2378 /******************************************************************************
2379 * RegCreateKeyEx32A [ADVAPI32.130]
2381 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2382 LPSTR lpszClass, DWORD fdwOptions,
2383 REGSAM samDesired,
2384 LPSECURITY_ATTRIBUTES lpSecAttribs,
2385 LPHKEY retkey, LPDWORD lpDispos )
2387 LPWSTR lpszSubKeyW, lpszClassW;
2388 DWORD ret;
2390 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2391 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2392 retkey,lpDispos);
2394 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2395 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2397 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2398 fdwOptions, samDesired, lpSecAttribs, retkey,
2399 lpDispos );
2401 if(lpszSubKeyW) free(lpszSubKeyW);
2402 if(lpszClassW) free(lpszClassW);
2404 return ret;
2408 /******************************************************************************
2409 * RegCreateKey32W [ADVAPI32.132]
2411 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2413 DWORD junk;
2414 LPKEYSTRUCT lpNextKey;
2416 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2418 /* This check is here because the return value is different than the
2419 one from the Ex functions */
2420 lpNextKey = lookup_hkey(hkey);
2421 if (!lpNextKey)
2422 return ERROR_BADKEY;
2424 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2425 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2426 retkey, &junk);
2430 /******************************************************************************
2431 * RegCreateKey32A [ADVAPI32.129]
2433 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2435 DWORD ret;
2436 LPWSTR lpszSubKeyW;
2438 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2439 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2440 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2441 if(lpszSubKeyW) free(lpszSubKeyW);
2442 return ret;
2446 /******************************************************************************
2447 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2449 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2451 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2452 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2457 * Query Value Functions
2458 * Win32 differs between keynames and valuenames.
2459 * multiple values may belong to one key, the special value
2460 * with name NULL is the default value used by the win31
2461 * compat functions.
2463 * Callpath:
2464 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2465 * RegQueryValue32W -> RegQueryValueEx32W
2469 /******************************************************************************
2470 * RegQueryValueEx32W [ADVAPI32.158]
2471 * Retrieves type and data for a specified name associated with an open key
2473 * PARAMS
2474 * hkey [I] Handle of key to query
2475 * lpValueName [I] Name of value to query
2476 * lpdwReserved [I] Reserved - must be NULL
2477 * lpdwType [O] Address of buffer for value type. If NULL, the type
2478 * is not required.
2479 * lpbData [O] Address of data buffer. If NULL, the actual data is
2480 * not required.
2481 * lpcbData [I/O] Address of data buffer size
2483 * RETURNS
2484 * ERROR_SUCCESS: Success
2485 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2486 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2488 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2489 LPDWORD lpdwReserved, LPDWORD lpdwType,
2490 LPBYTE lpbData, LPDWORD lpcbData )
2492 LPKEYSTRUCT lpkey;
2493 int i;
2494 DWORD ret;
2496 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2497 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2499 lpkey = lookup_hkey(hkey);
2501 if (!lpkey)
2502 return ERROR_INVALID_HANDLE;
2504 if ((lpbData && ! lpcbData) || lpdwReserved)
2505 return ERROR_INVALID_PARAMETER;
2507 /* An empty name string is equivalent to NULL */
2508 if (lpValueName && !*lpValueName)
2509 lpValueName = NULL;
2511 if (lpValueName==NULL)
2512 { /* Use key's unnamed or default value, if any */
2513 for (i=0;i<lpkey->nrofvalues;i++)
2514 if (lpkey->values[i].name==NULL)
2515 break;
2517 else
2518 { /* Search for the key name */
2519 for (i=0;i<lpkey->nrofvalues;i++)
2520 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2521 break;
2524 if (i==lpkey->nrofvalues)
2525 { TRACE(reg," Key not found\n");
2526 if (lpValueName==NULL)
2527 { /* Empty keyname not found */
2528 if (lpbData)
2529 { *(WCHAR*)lpbData = 0;
2530 *lpcbData = 2;
2532 if (lpdwType)
2533 *lpdwType = REG_SZ;
2534 TRACE(reg, " Returning an empty string\n");
2535 return ERROR_SUCCESS;
2537 return ERROR_FILE_NOT_FOUND;
2540 ret = ERROR_SUCCESS;
2542 if (lpdwType) /* type required ?*/
2543 *lpdwType = lpkey->values[i].type;
2545 if (lpbData) /* data required ?*/
2546 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2547 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2548 else
2549 ret = ERROR_MORE_DATA;
2552 if (lpcbData) /* size required ?*/
2553 { *lpcbData = lpkey->values[i].len;
2556 debug_print_value ( lpbData, &lpkey->values[i]);
2558 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2560 return ret;
2564 /******************************************************************************
2565 * RegQueryValue32W [ADVAPI32.159]
2567 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2568 LPLONG lpcbData )
2570 HKEY xhkey;
2571 DWORD ret,lpdwType;
2573 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2574 lpcbData?*lpcbData:0);
2576 /* Only open subkey, if we really do descend */
2577 if (lpszSubKey && *lpszSubKey) {
2578 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2579 if (ret != ERROR_SUCCESS) {
2580 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2581 return ret;
2583 } else
2584 xhkey = hkey;
2586 lpdwType = REG_SZ;
2587 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2588 lpcbData );
2589 if (xhkey != hkey)
2590 RegCloseKey(xhkey);
2591 return ret;
2595 /******************************************************************************
2596 * RegQueryValueEx32A [ADVAPI32.157]
2598 * NOTES:
2599 * the documantation is wrong: if the buffer is to small it remains untouched
2601 * FIXME: check returnvalue (len) for an empty key
2603 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2604 LPDWORD lpdwReserved, LPDWORD lpdwType,
2605 LPBYTE lpbData, LPDWORD lpcbData )
2607 LPWSTR lpszValueNameW;
2608 LPBYTE mybuf = NULL;
2609 DWORD ret, mytype, mylen = 0;
2611 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2612 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2614 if (!lpcbData && lpbData) /* buffer without size is illegal */
2615 { return ERROR_INVALID_PARAMETER;
2618 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2620 /* get just the type first */
2621 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2623 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2624 { if(lpszValueNameW) free(lpszValueNameW);
2625 return ret;
2628 if (lpcbData) /* at least length requested? */
2629 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2630 { if (lpbData ) /* value requested? */
2631 { mylen = 2*( *lpcbData );
2632 mybuf = (LPBYTE)xmalloc( mylen );
2635 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2637 if (ret == ERROR_SUCCESS )
2638 { if ( lpbData )
2639 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2643 *lpcbData = mylen/2; /* size is in byte! */
2645 else /* no strings, call it straight */
2646 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2650 if (lpdwType) /* type when requested */
2651 { *lpdwType = mytype;
2654 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2656 if(mybuf) free(mybuf);
2657 if(lpszValueNameW) free(lpszValueNameW);
2658 return ret;
2662 /******************************************************************************
2663 * RegQueryValueEx16 [KERNEL.225]
2665 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2666 LPDWORD lpdwReserved, LPDWORD lpdwType,
2667 LPBYTE lpbData, LPDWORD lpcbData )
2669 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2670 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2671 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2672 lpbData, lpcbData );
2676 /******************************************************************************
2677 * RegQueryValue32A [ADVAPI32.156]
2679 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2680 LPLONG lpcbData )
2682 HKEY xhkey;
2683 DWORD ret, dwType;
2685 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2686 lpcbData?*lpcbData:0);
2688 if (lpszSubKey && *lpszSubKey) {
2689 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2690 if( ret != ERROR_SUCCESS )
2691 return ret;
2692 } else
2693 xhkey = hkey;
2695 dwType = REG_SZ;
2696 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2697 lpcbData );
2698 if( xhkey != hkey )
2699 RegCloseKey( xhkey );
2700 return ret;
2704 /******************************************************************************
2705 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2707 * NOTES
2708 * Is this HACK still applicable?
2710 * HACK
2711 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2712 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2713 * Aldus FH4)
2715 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2716 LPDWORD lpcbData )
2718 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2719 lpcbData?*lpcbData:0);
2721 if (lpcbData)
2722 *lpcbData &= 0xFFFF;
2723 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2728 * Setting values of Registry keys
2730 * Callpath:
2731 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2732 * RegSetValue32W -> RegSetValueEx32W
2736 /******************************************************************************
2737 * RegSetValueEx32W [ADVAPI32.170]
2738 * Sets the data and type of a value under a register key
2740 * PARAMS
2741 * hkey [I] Handle of key to set value for
2742 * lpszValueName [I] Name of value to set
2743 * dwReserved [I] Reserved - must be zero
2744 * dwType [I] Flag for value type
2745 * lpbData [I] Address of value data
2746 * cbData [I] Size of value data
2748 * RETURNS
2749 * Success: ERROR_SUCCESS
2750 * Failure: Error code
2752 * NOTES
2753 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2755 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2756 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2757 DWORD cbData)
2759 LPKEYSTRUCT lpkey;
2760 int i;
2762 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2763 dwReserved, dwType, lpbData, cbData);
2765 lpkey = lookup_hkey( hkey );
2767 if (!lpkey)
2768 return ERROR_INVALID_HANDLE;
2770 lpkey->flags |= REG_OPTION_TAINTED;
2772 if (lpszValueName==NULL) {
2773 /* Sets type and name for key's unnamed or default value */
2774 for (i=0;i<lpkey->nrofvalues;i++)
2775 if (lpkey->values[i].name==NULL)
2776 break;
2777 } else {
2778 for (i=0;i<lpkey->nrofvalues;i++)
2779 if ( lpkey->values[i].name &&
2780 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2782 break;
2784 if (i==lpkey->nrofvalues) {
2785 lpkey->values = (LPKEYVALUE)xrealloc(
2786 lpkey->values,
2787 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2789 lpkey->nrofvalues++;
2790 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2792 if (lpkey->values[i].name==NULL) {
2793 if (lpszValueName)
2794 lpkey->values[i].name = strdupW(lpszValueName);
2795 else
2796 lpkey->values[i].name = NULL;
2799 if (dwType == REG_SZ)
2800 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2802 lpkey->values[i].len = cbData;
2803 lpkey->values[i].type = dwType;
2804 if (lpkey->values[i].data !=NULL)
2805 free(lpkey->values[i].data);
2806 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2807 lpkey->values[i].lastmodified = time(NULL);
2808 memcpy(lpkey->values[i].data,lpbData,cbData);
2809 return ERROR_SUCCESS;
2813 /******************************************************************************
2814 * RegSetValueEx32A [ADVAPI32.169]
2816 * NOTES
2817 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2819 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2820 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2821 DWORD cbData )
2823 LPBYTE buf;
2824 LPWSTR lpszValueNameW;
2825 DWORD ret;
2827 if (!lpbData)
2828 return (ERROR_INVALID_PARAMETER);
2830 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2831 dwReserved,dwType,lpbData,cbData);
2833 if ((1<<dwType) & UNICONVMASK)
2834 { if (dwType == REG_SZ)
2835 cbData = strlen ((LPCSTR)lpbData)+1;
2837 buf = (LPBYTE)xmalloc( cbData *2 );
2838 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2839 cbData=2*cbData;
2841 else
2842 buf=lpbData;
2844 if (lpszValueName)
2845 lpszValueNameW = strdupA2W(lpszValueName);
2846 else
2847 lpszValueNameW = NULL;
2849 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2851 if (lpszValueNameW)
2852 free(lpszValueNameW);
2854 if (buf!=lpbData)
2855 free(buf);
2857 return ret;
2861 /******************************************************************************
2862 * RegSetValueEx16 [KERNEL.226]
2864 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2865 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2867 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2868 dwReserved,dwType,lpbData,cbData);
2869 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2870 cbData );
2874 /******************************************************************************
2875 * RegSetValue32W [ADVAPI32.171]
2877 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2878 LPCWSTR lpszData, DWORD cbData )
2880 HKEY xhkey;
2881 DWORD ret;
2883 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2884 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2886 if (lpszSubKey && *lpszSubKey) {
2887 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2888 if (ret!=ERROR_SUCCESS)
2889 return ret;
2890 } else
2891 xhkey=hkey;
2892 if (dwType!=REG_SZ) {
2893 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2894 dwType=REG_SZ;
2896 if (cbData!=2*lstrlenW(lpszData)+2) {
2897 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2898 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2900 cbData=2*lstrlenW(lpszData)+2;
2902 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2903 if (hkey!=xhkey)
2904 RegCloseKey(xhkey);
2905 return ret;
2909 /******************************************************************************
2910 * RegSetValue32A [ADVAPI32.168]
2913 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2914 LPCSTR lpszData, DWORD cbData )
2916 DWORD ret;
2917 HKEY xhkey;
2919 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2920 if (lpszSubKey && *lpszSubKey) {
2921 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2922 if (ret!=ERROR_SUCCESS)
2923 return ret;
2924 } else
2925 xhkey=hkey;
2927 if (dwType!=REG_SZ) {
2928 TRACE(reg,"dwType=%ld!\n",dwType);
2929 dwType=REG_SZ;
2931 if (cbData!=strlen(lpszData)+1)
2932 cbData=strlen(lpszData)+1;
2933 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2934 if (xhkey!=hkey)
2935 RegCloseKey(xhkey);
2936 return ret;
2940 /******************************************************************************
2941 * RegSetValue16 [KERNEL.221] [SHELL.5]
2943 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2944 LPCSTR lpszData, DWORD cbData )
2946 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2947 debugstr_a(lpszData),cbData);
2948 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2953 * Key Enumeration
2955 * Callpath:
2956 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2957 * RegEnumKey32W -> RegEnumKeyEx32W
2961 /******************************************************************************
2962 * RegEnumKeyEx32W [ADVAPI32.139]
2964 * PARAMS
2965 * hkey [I] Handle to key to enumerate
2966 * iSubKey [I] Index of subkey to enumerate
2967 * lpszName [O] Buffer for subkey name
2968 * lpcchName [O] Size of subkey buffer
2969 * lpdwReserved [I] Reserved
2970 * lpszClass [O] Buffer for class string
2971 * lpcchClass [O] Size of class buffer
2972 * ft [O] Time key last written to
2974 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2975 LPDWORD lpcchName, LPDWORD lpdwReserved,
2976 LPWSTR lpszClass, LPDWORD lpcchClass,
2977 FILETIME *ft )
2979 LPKEYSTRUCT lpkey,lpxkey;
2981 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2982 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2984 lpkey = lookup_hkey( hkey );
2985 if (!lpkey)
2986 return ERROR_INVALID_HANDLE;
2988 if (!lpkey->nextsub)
2989 return ERROR_NO_MORE_ITEMS;
2990 lpxkey=lpkey->nextsub;
2992 /* Traverse the subkeys */
2993 while (iSubkey && lpxkey) {
2994 iSubkey--;
2995 lpxkey=lpxkey->next;
2998 if (iSubkey || !lpxkey)
2999 return ERROR_NO_MORE_ITEMS;
3000 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
3001 return ERROR_MORE_DATA;
3002 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3004 if (*lpcchName)
3005 *lpcchName = lstrlenW(lpszName);
3007 if (lpszClass) {
3008 /* FIXME: what should we write into it? */
3009 *lpszClass = 0;
3010 *lpcchClass = 2;
3012 return ERROR_SUCCESS;
3016 /******************************************************************************
3017 * RegEnumKey32W [ADVAPI32.140]
3019 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3020 DWORD lpcchName )
3022 FILETIME ft;
3024 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3025 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3029 /******************************************************************************
3030 * RegEnumKeyEx32A [ADVAPI32.138]
3032 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3033 LPDWORD lpcchName, LPDWORD lpdwReserved,
3034 LPSTR lpszClass, LPDWORD lpcchClass,
3035 FILETIME *ft )
3037 DWORD ret,lpcchNameW,lpcchClassW;
3038 LPWSTR lpszNameW,lpszClassW;
3041 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3042 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3044 if (lpszName) {
3045 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3046 lpcchNameW = *lpcchName;
3047 } else {
3048 lpszNameW = NULL;
3049 lpcchNameW = 0;
3051 if (lpszClass) {
3052 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3053 lpcchClassW = *lpcchClass;
3054 } else {
3055 lpszClassW =0;
3056 lpcchClassW=0;
3058 ret=RegEnumKeyExW(
3059 hkey,
3060 iSubkey,
3061 lpszNameW,
3062 &lpcchNameW,
3063 lpdwReserved,
3064 lpszClassW,
3065 &lpcchClassW,
3068 if (ret==ERROR_SUCCESS) {
3069 lstrcpyWtoA(lpszName,lpszNameW);
3070 *lpcchName=strlen(lpszName);
3071 if (lpszClassW) {
3072 lstrcpyWtoA(lpszClass,lpszClassW);
3073 *lpcchClass=strlen(lpszClass);
3076 if (lpszNameW)
3077 free(lpszNameW);
3078 if (lpszClassW)
3079 free(lpszClassW);
3080 return ret;
3084 /******************************************************************************
3085 * RegEnumKey32A [ADVAPI32.137]
3087 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3088 DWORD lpcchName )
3090 FILETIME ft;
3092 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3093 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3094 NULL, &ft );
3098 /******************************************************************************
3099 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3101 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3102 DWORD lpcchName )
3104 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3105 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3110 * Enumerate Registry Values
3112 * Callpath:
3113 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3117 /******************************************************************************
3118 * RegEnumValue32W [ADVAPI32.142]
3120 * PARAMS
3121 * hkey [I] Handle to key to query
3122 * iValue [I] Index of value to query
3123 * lpszValue [O] Value string
3124 * lpcchValue [I/O] Size of value buffer (in wchars)
3125 * lpdReserved [I] Reserved
3126 * lpdwType [O] Type code
3127 * lpbData [O] Value data
3128 * lpcbData [I/O] Size of data buffer (in bytes)
3130 * Note: wide character functions that take and/or return "character counts"
3131 * use TCHAR (that is unsigned short or char) not byte counts.
3133 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3134 LPDWORD lpcchValue, LPDWORD lpdReserved,
3135 LPDWORD lpdwType, LPBYTE lpbData,
3136 LPDWORD lpcbData )
3138 LPKEYSTRUCT lpkey;
3139 LPKEYVALUE val;
3141 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3142 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3144 lpkey = lookup_hkey( hkey );
3146 if (!lpcbData && lpbData)
3147 return ERROR_INVALID_PARAMETER;
3149 if (!lpkey)
3150 return ERROR_INVALID_HANDLE;
3152 if (lpkey->nrofvalues <= iValue)
3153 return ERROR_NO_MORE_ITEMS;
3155 val = &(lpkey->values[iValue]);
3157 if (val->name) {
3158 if (lstrlenW(val->name)+1>*lpcchValue) {
3159 *lpcchValue = lstrlenW(val->name)+1;
3160 return ERROR_MORE_DATA;
3162 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3163 *lpcchValue=lstrlenW(val->name);
3164 } else {
3165 *lpszValue = 0;
3166 *lpcchValue = 0;
3169 /* Can be NULL if the type code is not required */
3170 if (lpdwType)
3171 *lpdwType = val->type;
3173 if (lpbData) {
3174 if (val->len>*lpcbData)
3175 return ERROR_MORE_DATA;
3176 memcpy(lpbData,val->data,val->len);
3177 *lpcbData = val->len;
3180 debug_print_value ( val->data, val );
3181 return ERROR_SUCCESS;
3185 /******************************************************************************
3186 * RegEnumValue32A [ADVAPI32.141]
3188 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3189 LPDWORD lpcchValue, LPDWORD lpdReserved,
3190 LPDWORD lpdwType, LPBYTE lpbData,
3191 LPDWORD lpcbData )
3193 LPWSTR lpszValueW;
3194 LPBYTE lpbDataW;
3195 DWORD ret,lpcbDataW;
3196 DWORD dwType;
3198 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3199 lpdReserved,lpdwType,lpbData,lpcbData);
3201 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3202 if (lpbData) {
3203 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3204 lpcbDataW = *lpcbData;
3205 } else
3206 lpbDataW = NULL;
3208 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3209 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3211 if (lpdwType)
3212 *lpdwType = dwType;
3214 if (ret==ERROR_SUCCESS) {
3215 lstrcpyWtoA(lpszValue,lpszValueW);
3216 if (lpbData) {
3217 if ((1<<dwType) & UNICONVMASK) {
3218 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3219 } else {
3220 if (lpcbDataW > *lpcbData)
3221 ret = ERROR_MORE_DATA;
3222 else
3223 memcpy(lpbData,lpbDataW,lpcbDataW);
3225 *lpcbData = lpcbDataW;
3228 if (lpbDataW) free(lpbDataW);
3229 if (lpszValueW) free(lpszValueW);
3230 return ret;
3234 /******************************************************************************
3235 * RegEnumValue16 [KERNEL.223]
3237 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3238 LPDWORD lpcchValue, LPDWORD lpdReserved,
3239 LPDWORD lpdwType, LPBYTE lpbData,
3240 LPDWORD lpcbData )
3242 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3243 lpdReserved,lpdwType,lpbData,lpcbData);
3244 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3245 lpdwType, lpbData, lpcbData );
3249 /******************************************************************************
3250 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3251 * Releases the handle of the specified key
3253 * PARAMS
3254 * hkey [I] Handle of key to close
3256 * RETURNS
3257 * Success: ERROR_SUCCESS
3258 * Failure: Error code
3260 DWORD WINAPI RegCloseKey( HKEY hkey )
3262 TRACE(reg,"(%x)\n",hkey);
3264 /* The standard handles are allowed to succeed, even though they are not
3265 closed */
3266 if (is_standard_hkey(hkey))
3267 return ERROR_SUCCESS;
3269 return remove_handle(hkey);
3274 * Delete registry key
3276 * Callpath:
3277 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3281 /******************************************************************************
3282 * RegDeleteKey32W [ADVAPI32.134]
3284 * PARAMS
3285 * hkey [I] Handle to open key
3286 * lpszSubKey [I] Name of subkey to delete
3288 * RETURNS
3289 * Success: ERROR_SUCCESS
3290 * Failure: Error code
3292 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3294 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3295 LPWSTR *wps;
3296 int wpc,i;
3298 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3300 lpNextKey = lookup_hkey(hkey);
3301 if (!lpNextKey)
3302 return ERROR_INVALID_HANDLE;
3304 /* Subkey param cannot be NULL */
3305 if (!lpszSubKey || !*lpszSubKey)
3306 return ERROR_BADKEY;
3308 /* We need to know the previous key in the hier. */
3309 split_keypath(lpszSubKey,&wps,&wpc);
3310 i = 0;
3311 lpxkey = lpNextKey;
3312 while (i<wpc-1) {
3313 lpxkey=lpNextKey->nextsub;
3314 while (lpxkey) {
3315 TRACE(reg, " Scanning [%s]\n",
3316 debugstr_w(lpxkey->keyname));
3317 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3318 break;
3319 lpxkey=lpxkey->next;
3321 if (!lpxkey) {
3322 FREE_KEY_PATH;
3323 TRACE(reg, " Not found.\n");
3324 /* not found is success */
3325 return ERROR_SUCCESS;
3327 i++;
3328 lpNextKey = lpxkey;
3330 lpxkey = lpNextKey->nextsub;
3331 lplpPrevKey = &(lpNextKey->nextsub);
3332 while (lpxkey) {
3333 TRACE(reg, " Scanning [%s]\n",
3334 debugstr_w(lpxkey->keyname));
3335 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3336 break;
3337 lplpPrevKey = &(lpxkey->next);
3338 lpxkey = lpxkey->next;
3341 if (!lpxkey) {
3342 FREE_KEY_PATH;
3343 WARN(reg , " Not found.\n");
3344 return ERROR_FILE_NOT_FOUND;
3347 if (lpxkey->nextsub) {
3348 FREE_KEY_PATH;
3349 WARN(reg , " Not empty.\n");
3350 return ERROR_CANTWRITE;
3352 *lplpPrevKey = lpxkey->next;
3353 free(lpxkey->keyname);
3354 if (lpxkey->class)
3355 free(lpxkey->class);
3356 if (lpxkey->values)
3357 free(lpxkey->values);
3358 free(lpxkey);
3359 FREE_KEY_PATH;
3360 TRACE(reg, " Done.\n");
3361 return ERROR_SUCCESS;
3365 /******************************************************************************
3366 * RegDeleteKey32A [ADVAPI32.133]
3368 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3370 LPWSTR lpszSubKeyW;
3371 DWORD ret;
3373 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3374 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3375 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3376 if(lpszSubKeyW) free(lpszSubKeyW);
3377 return ret;
3381 /******************************************************************************
3382 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3384 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3386 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3387 return RegDeleteKeyA( hkey, lpszSubKey );
3392 * Delete registry value
3394 * Callpath:
3395 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3399 /******************************************************************************
3400 * RegDeleteValue32W [ADVAPI32.136]
3402 * PARAMS
3403 * hkey [I]
3404 * lpszValue [I]
3406 * RETURNS
3408 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3410 DWORD i;
3411 LPKEYSTRUCT lpkey;
3412 LPKEYVALUE val;
3414 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3416 lpkey = lookup_hkey( hkey );
3417 if (!lpkey)
3418 return ERROR_INVALID_HANDLE;
3420 if (lpszValue) {
3421 for (i=0;i<lpkey->nrofvalues;i++)
3422 if ( lpkey->values[i].name &&
3423 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3425 break;
3426 } else {
3427 for (i=0;i<lpkey->nrofvalues;i++)
3428 if (lpkey->values[i].name==NULL)
3429 break;
3432 if (i == lpkey->nrofvalues)
3433 return ERROR_FILE_NOT_FOUND;
3435 val = lpkey->values+i;
3436 if (val->name) free(val->name);
3437 if (val->data) free(val->data);
3438 memcpy(
3439 lpkey->values+i,
3440 lpkey->values+i+1,
3441 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3443 lpkey->values = (LPKEYVALUE)xrealloc(
3444 lpkey->values,
3445 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3447 lpkey->nrofvalues--;
3448 return ERROR_SUCCESS;
3452 /******************************************************************************
3453 * RegDeleteValue32A [ADVAPI32.135]
3455 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3457 LPWSTR lpszValueW;
3458 DWORD ret;
3460 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3461 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3462 ret = RegDeleteValueW( hkey, lpszValueW );
3463 if(lpszValueW) free(lpszValueW);
3464 return ret;
3468 /******************************************************************************
3469 * RegDeleteValue16 [KERNEL.222]
3471 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3473 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3474 return RegDeleteValueA( hkey, lpszValue );
3478 /******************************************************************************
3479 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3480 * Writes key to registry
3482 * PARAMS
3483 * hkey [I] Handle of key to write
3485 * RETURNS
3486 * Success: ERROR_SUCCESS
3487 * Failure: Error code
3489 DWORD WINAPI RegFlushKey( HKEY hkey )
3491 LPKEYSTRUCT lpkey;
3492 BOOL ret;
3494 TRACE(reg, "(%x)\n", hkey);
3496 lpkey = lookup_hkey( hkey );
3497 if (!lpkey)
3498 return ERROR_BADKEY;
3500 ERR(reg, "What is the correct filename?\n");
3502 ret = _savereg( lpkey, "foo.bar", TRUE);
3504 if( ret ) {
3505 return ERROR_SUCCESS;
3506 } else
3507 return ERROR_UNKNOWN; /* FIXME */
3511 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3514 /******************************************************************************
3515 * RegQueryInfoKey32W [ADVAPI32.153]
3517 * PARAMS
3518 * hkey [I] Handle to key to query
3519 * lpszClass [O] Buffer for class string
3520 * lpcchClass [O] Size of class string buffer
3521 * lpdwReserved [I] Reserved
3522 * lpcSubKeys [I] Buffer for number of subkeys
3523 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3524 * lpcchMaxClass [O] Buffer for longest class string length
3525 * lpcValues [O] Buffer for number of value entries
3526 * lpcchMaxValueName [O] Buffer for longest value name length
3527 * lpccbMaxValueData [O] Buffer for longest value data length
3528 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3529 * ft
3530 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3531 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3532 * lpcchClass is NULL
3533 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3534 * (it's hard to test validity, so test !NULL instead)
3536 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3537 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3538 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3539 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3540 LPDWORD lpcchMaxValueName,
3541 LPDWORD lpccbMaxValueData,
3542 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3544 LPKEYSTRUCT lpkey,lpxkey;
3545 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3546 int i;
3548 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3549 lpkey = lookup_hkey(hkey);
3550 if (!lpkey)
3551 return ERROR_INVALID_HANDLE;
3552 if (lpszClass) {
3553 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3554 return ERROR_INVALID_PARAMETER;
3556 /* either lpcchClass is valid or this is win95 and lpcchClass
3557 could be invalid */
3558 if (lpkey->class) {
3559 DWORD classLen = lstrlenW(lpkey->class);
3561 if (lpcchClass && classLen+1>*lpcchClass) {
3562 *lpcchClass=classLen+1;
3563 return ERROR_MORE_DATA;
3565 if (lpcchClass)
3566 *lpcchClass=classLen;
3567 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3568 } else {
3569 *lpszClass = 0;
3570 if (lpcchClass)
3571 *lpcchClass = 0;
3573 } else {
3574 if (lpcchClass)
3575 *lpcchClass = lstrlenW(lpkey->class);
3577 lpxkey=lpkey->nextsub;
3578 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3579 while (lpxkey) {
3580 nrofkeys++;
3581 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3582 maxsubkey=lstrlenW(lpxkey->keyname);
3583 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3584 maxclass=lstrlenW(lpxkey->class);
3585 lpxkey=lpxkey->next;
3587 for (i=0;i<lpkey->nrofvalues;i++) {
3588 LPKEYVALUE val=lpkey->values+i;
3590 if (val->name && lstrlenW(val->name)>maxvname)
3591 maxvname=lstrlenW(val->name);
3592 if (val->len>maxvdata)
3593 maxvdata=val->len;
3595 if (!maxclass) maxclass = 1;
3596 if (!maxvname) maxvname = 1;
3597 if (lpcValues)
3598 *lpcValues = lpkey->nrofvalues;
3599 if (lpcSubKeys)
3600 *lpcSubKeys = nrofkeys;
3601 if (lpcchMaxSubkey)
3602 *lpcchMaxSubkey = maxsubkey;
3603 if (lpcchMaxClass)
3604 *lpcchMaxClass = maxclass;
3605 if (lpcchMaxValueName)
3606 *lpcchMaxValueName= maxvname;
3607 if (lpccbMaxValueData)
3608 *lpccbMaxValueData= maxvdata;
3609 return ERROR_SUCCESS;
3613 /******************************************************************************
3614 * RegQueryInfoKey32A [ADVAPI32.152]
3616 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3617 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3618 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3619 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3620 LPDWORD lpccbMaxValueData,
3621 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3623 LPWSTR lpszClassW = NULL;
3624 DWORD ret;
3626 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3627 if (lpszClass) {
3628 if (lpcchClass) {
3629 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3630 } else if (VERSION_GetVersion() == WIN95) {
3631 /* win95 allows lpcchClass to be null */
3632 /* we don't know how big lpszClass is, would
3633 MAX_PATHNAME_LEN be the correct default? */
3634 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3637 } else
3638 lpszClassW = NULL;
3639 ret=RegQueryInfoKeyW(
3640 hkey,
3641 lpszClassW,
3642 lpcchClass,
3643 lpdwReserved,
3644 lpcSubKeys,
3645 lpcchMaxSubkey,
3646 lpcchMaxClass,
3647 lpcValues,
3648 lpcchMaxValueName,
3649 lpccbMaxValueData,
3650 lpcbSecurityDescriptor,
3653 if (ret==ERROR_SUCCESS && lpszClass)
3654 lstrcpyWtoA(lpszClass,lpszClassW);
3655 if (lpszClassW)
3656 free(lpszClassW);
3657 return ret;
3661 /******************************************************************************
3662 * RegConnectRegistry32W [ADVAPI32.128]
3664 * PARAMS
3665 * lpMachineName [I] Address of name of remote computer
3666 * hHey [I] Predefined registry handle
3667 * phkResult [I] Address of buffer for remote registry handle
3669 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3670 LPHKEY phkResult )
3672 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3674 if (!lpMachineName || !*lpMachineName) {
3675 /* Use the local machine name */
3676 return RegOpenKey16( hKey, "", phkResult );
3679 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3680 return ERROR_BAD_NETPATH;
3684 /******************************************************************************
3685 * RegConnectRegistry32A [ADVAPI32.127]
3687 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3689 DWORD ret;
3690 LPWSTR machineW = strdupA2W(machine);
3691 ret = RegConnectRegistryW( machineW, hkey, reskey );
3692 free(machineW);
3693 return ret;
3697 /******************************************************************************
3698 * RegGetKeySecurity [ADVAPI32.144]
3699 * Retrieves a copy of security descriptor protecting the registry key
3701 * PARAMS
3702 * hkey [I] Open handle of key to set
3703 * SecurityInformation [I] Descriptor contents
3704 * pSecurityDescriptor [O] Address of descriptor for key
3705 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3707 * RETURNS
3708 * Success: ERROR_SUCCESS
3709 * Failure: Error code
3711 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3712 SECURITY_INFORMATION SecurityInformation,
3713 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3714 LPDWORD lpcbSecurityDescriptor )
3716 LPKEYSTRUCT lpkey;
3718 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3719 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3721 lpkey = lookup_hkey( hkey );
3722 if (!lpkey)
3723 return ERROR_INVALID_HANDLE;
3725 /* FIXME: Check for valid SecurityInformation values */
3727 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3728 return ERROR_INSUFFICIENT_BUFFER;
3730 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3731 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3733 return ERROR_SUCCESS;
3737 /******************************************************************************
3738 * RegLoadKey32W [ADVAPI32.???]
3740 * PARAMS
3741 * hkey [I] Handle of open key
3742 * lpszSubKey [I] Address of name of subkey
3743 * lpszFile [I] Address of filename for registry information
3745 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3747 LPKEYSTRUCT lpkey;
3748 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3750 /* Do this check before the hkey check */
3751 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3752 return ERROR_INVALID_PARAMETER;
3754 lpkey = lookup_hkey( hkey );
3755 if (!lpkey)
3756 return ERROR_INVALID_HANDLE;
3758 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3759 debugstr_w(lpszFile));
3761 return ERROR_SUCCESS;
3765 /******************************************************************************
3766 * RegLoadKey32A [ADVAPI32.???]
3768 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3770 LONG ret;
3771 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3772 LPWSTR lpszFileW = strdupA2W(lpszFile);
3773 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3774 if(lpszFileW) free(lpszFileW);
3775 if(lpszSubKeyW) free(lpszSubKeyW);
3776 return ret;
3780 /******************************************************************************
3781 * RegNotifyChangeKeyValue [ADVAPI32.???]
3783 * PARAMS
3784 * hkey [I] Handle of key to watch
3785 * fWatchSubTree [I] Flag for subkey notification
3786 * fdwNotifyFilter [I] Changes to be reported
3787 * hEvent [I] Handle of signaled event
3788 * fAsync [I] Flag for asynchronous reporting
3790 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3791 DWORD fdwNotifyFilter, HANDLE hEvent,
3792 BOOL fAsync )
3794 LPKEYSTRUCT lpkey;
3795 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3796 hEvent,fAsync);
3798 lpkey = lookup_hkey( hkey );
3799 if (!lpkey)
3800 return ERROR_INVALID_HANDLE;
3802 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3803 hEvent,fAsync);
3805 return ERROR_SUCCESS;
3809 /******************************************************************************
3810 * RegUnLoadKey32W [ADVAPI32.173]
3812 * PARAMS
3813 * hkey [I] Handle of open key
3814 * lpSubKey [I] Address of name of subkey to unload
3816 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3818 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3819 return ERROR_SUCCESS;
3823 /******************************************************************************
3824 * RegUnLoadKey32A [ADVAPI32.172]
3826 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3828 LONG ret;
3829 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3830 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3831 if(lpSubKeyW) free(lpSubKeyW);
3832 return ret;
3836 /******************************************************************************
3837 * RegSetKeySecurity [ADVAPI32.167]
3839 * PARAMS
3840 * hkey [I] Open handle of key to set
3841 * SecurityInfo [I] Descriptor contents
3842 * pSecurityDesc [I] Address of descriptor for key
3844 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3845 PSECURITY_DESCRIPTOR pSecurityDesc )
3847 LPKEYSTRUCT lpkey;
3849 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3851 /* It seems to perform this check before the hkey check */
3852 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3853 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3854 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3855 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3856 /* Param OK */
3857 } else
3858 return ERROR_INVALID_PARAMETER;
3860 if (!pSecurityDesc)
3861 return ERROR_INVALID_PARAMETER;
3863 lpkey = lookup_hkey( hkey );
3864 if (!lpkey)
3865 return ERROR_INVALID_HANDLE;
3867 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3869 return ERROR_SUCCESS;
3873 /******************************************************************************
3874 * RegSaveKey32W [ADVAPI32.166]
3876 * PARAMS
3877 * hkey [I] Handle of key where save begins
3878 * lpFile [I] Address of filename to save to
3879 * sa [I] Address of security structure
3881 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3882 LPSECURITY_ATTRIBUTES sa )
3884 LPKEYSTRUCT lpkey;
3886 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3888 /* It appears to do this check before the hkey check */
3889 if (!lpFile || !*lpFile)
3890 return ERROR_INVALID_PARAMETER;
3892 lpkey = lookup_hkey( hkey );
3893 if (!lpkey)
3894 return ERROR_INVALID_HANDLE;
3896 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3898 return ERROR_SUCCESS;
3902 /******************************************************************************
3903 * RegSaveKey32A [ADVAPI32.165]
3905 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3906 LPSECURITY_ATTRIBUTES sa )
3908 LONG ret;
3909 LPWSTR lpFileW = strdupA2W(lpFile);
3910 ret = RegSaveKeyW( hkey, lpFileW, sa );
3911 free(lpFileW);
3912 return ret;
3916 /******************************************************************************
3917 * RegRestoreKey32W [ADVAPI32.164]
3919 * PARAMS
3920 * hkey [I] Handle of key where restore begins
3921 * lpFile [I] Address of filename containing saved tree
3922 * dwFlags [I] Optional flags
3924 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3926 LPKEYSTRUCT lpkey;
3928 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3930 /* It seems to do this check before the hkey check */
3931 if (!lpFile || !*lpFile)
3932 return ERROR_INVALID_PARAMETER;
3934 lpkey = lookup_hkey( hkey );
3935 if (!lpkey)
3936 return ERROR_INVALID_HANDLE;
3938 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3940 /* Check for file existence */
3942 return ERROR_SUCCESS;
3946 /******************************************************************************
3947 * RegRestoreKey32A [ADVAPI32.163]
3949 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3951 LONG ret;
3952 LPWSTR lpFileW = strdupA2W(lpFile);
3953 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3954 if(lpFileW) free(lpFileW);
3955 return ret;
3959 /******************************************************************************
3960 * RegReplaceKey32W [ADVAPI32.162]
3962 * PARAMS
3963 * hkey [I] Handle of open key
3964 * lpSubKey [I] Address of name of subkey
3965 * lpNewFile [I] Address of filename for file with new data
3966 * lpOldFile [I] Address of filename for backup file
3968 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3969 LPCWSTR lpOldFile )
3971 LPKEYSTRUCT lpkey;
3973 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3974 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3976 lpkey = lookup_hkey( hkey );
3977 if (!lpkey)
3978 return ERROR_INVALID_HANDLE;
3980 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3981 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3983 return ERROR_SUCCESS;
3987 /******************************************************************************
3988 * RegReplaceKey32A [ADVAPI32.161]
3990 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3991 LPCSTR lpOldFile )
3993 LONG ret;
3994 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3995 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3996 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3997 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3998 free(lpOldFileW);
3999 free(lpNewFileW);
4000 free(lpSubKeyW);
4001 return ret;