Fix save_check_tainted to properly scan the tree so that all tainted
[wine.git] / misc / registry.c
blob2c93d17da2a70b19980b9e896e131bbdb5b16b85
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 "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_ERRNO_H
30 #include <sys/errno.h>
31 #endif
32 #include <sys/types.h>
33 #include <sys/fcntl.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36 #include <time.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/winbase16.h"
40 #include "wine/winestring.h"
41 #include "winerror.h"
42 #include "file.h"
43 #include "heap.h"
44 #include "debugtools.h"
45 #include "xmalloc.h"
46 #include "options.h"
47 #include "winreg.h"
48 #include "winversion.h"
50 DECLARE_DEBUG_CHANNEL(reg)
51 DECLARE_DEBUG_CHANNEL(string)
53 static void REGISTRY_Init(void);
54 /* FIXME: following defines should be configured global ... */
56 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
57 #define WINE_PREFIX "/.wine"
58 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
59 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
61 /* relative in ~user/.wine/ : */
62 #define SAVE_CURRENT_USER "user.reg"
63 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
64 #define SAVE_LOCAL_MACHINE "system.reg"
66 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
67 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
69 /* one value of a key */
70 typedef struct tagKEYVALUE
72 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
73 DWORD type; /* type of value */
74 DWORD len; /* length of data in BYTEs */
75 DWORD lastmodified; /* time of seconds since 1.1.1970 */
76 LPBYTE data; /* content, may be strings, binaries, etc. */
77 } KEYVALUE,*LPKEYVALUE;
79 /* a registry key */
80 typedef struct tagKEYSTRUCT
82 LPWSTR keyname; /* name of THIS key (UNICODE) */
83 DWORD flags; /* flags. */
84 LPWSTR class;
85 /* values */
86 DWORD nrofvalues; /* nr of values in THIS key */
87 LPKEYVALUE values; /* values in THIS key */
88 /* key management pointers */
89 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
90 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
91 } KEYSTRUCT, *LPKEYSTRUCT;
94 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
95 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
96 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
97 static KEYSTRUCT *key_users=NULL; /* all users? */
99 /* dynamic, not saved */
100 static KEYSTRUCT *key_performance_data=NULL;
101 static KEYSTRUCT *key_current_config=NULL;
102 static KEYSTRUCT *key_dyn_data=NULL;
104 /* what valuetypes do we need to convert? */
105 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
108 static struct openhandle {
109 LPKEYSTRUCT lpkey;
110 HKEY hkey;
111 REGSAM accessmask;
112 } *openhandles=NULL;
113 static int nrofopenhandles=0;
114 /* Starts after 1 because 0,1 are reserved for Win16 */
115 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
116 HKEYs for remote registry access */
117 static int currenthandle=2;
121 * QUESTION
122 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
123 * If so, can we remove them?
124 * ANSWER
125 * No, the memory handling functions are called very often in here,
126 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
127 * loading 100 times slower. -MM
129 static LPWSTR strdupA2W(LPCSTR src)
131 if(src) {
132 LPWSTR dest=xmalloc(2*strlen(src)+2);
133 lstrcpyAtoW(dest,src);
134 return dest;
136 return NULL;
139 static LPWSTR strdupW(LPCWSTR a) {
140 LPWSTR b;
141 int len;
143 if(a) {
144 len=sizeof(WCHAR)*(lstrlenW(a)+1);
145 b=(LPWSTR)xmalloc(len);
146 memcpy(b,a,len);
147 return b;
149 return NULL;
152 LPWSTR strcvtA2W(LPCSTR src, int nchars)
155 LPWSTR dest = xmalloc (2 * nchars + 2);
157 lstrcpynAtoW(dest,src,nchars+1);
158 dest[nchars] = 0;
159 return dest;
162 * we need to convert A to W with '\0' in strings (MULTI_SZ)
165 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
166 { LPWSTR p = dst;
168 TRACE_(reg)("\"%s\" %i\n",src, n);
170 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
172 return dst;
174 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
175 { LPSTR p = dst;
177 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
179 while (n-- > 0) *p++ = (CHAR)*src++;
181 return dst;
184 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
186 if (TRACE_ON(reg) && lpbData)
188 switch(key->type)
190 case REG_EXPAND_SZ:
191 case REG_SZ:
192 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
193 debugstr_w(key->name),
194 debugstr_w((LPCWSTR)lpbData));
195 break;
197 case REG_DWORD:
198 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
199 debugstr_w(key->name),
200 (DWORD)*lpbData);
201 break;
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 default:
221 char szTemp[100]; /* 3*32 + 3 + 1 */
222 int i;
223 for ( i = 0; i < key->len ; i++)
225 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
226 if (i>=31)
228 sprintf (&(szTemp[i*3+3]),"...");
229 break;
232 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
233 debugstr_w(key->name),
234 szTemp);
236 } /* switch */
237 } /* if */
241 /******************************************************************************
242 * is_standard_hkey [Internal]
243 * Determines if a hkey is a standard key
245 static BOOL is_standard_hkey( HKEY hkey )
247 switch(hkey) {
248 case 0x00000000:
249 case 0x00000001:
250 case HKEY_CLASSES_ROOT:
251 case HKEY_CURRENT_CONFIG:
252 case HKEY_CURRENT_USER:
253 case HKEY_LOCAL_MACHINE:
254 case HKEY_USERS:
255 case HKEY_PERFORMANCE_DATA:
256 case HKEY_DYN_DATA:
257 return TRUE;
258 default:
259 return FALSE;
263 /******************************************************************************
264 * add_handle [Internal]
266 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
268 int i;
270 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
271 /* Check for duplicates */
272 for (i=0;i<nrofopenhandles;i++) {
273 if (openhandles[i].lpkey==lpkey) {
274 /* This is not really an error - the user is allowed to create
275 two (or more) handles to the same key */
276 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
278 if (openhandles[i].hkey==hkey) {
279 WARN_(reg)("Adding handle %x twice\n",hkey);
282 openhandles=xrealloc( openhandles,
283 sizeof(struct openhandle)*(nrofopenhandles+1));
285 openhandles[i].lpkey = lpkey;
286 openhandles[i].hkey = hkey;
287 openhandles[i].accessmask = accessmask;
288 nrofopenhandles++;
292 /******************************************************************************
293 * get_handle [Internal]
295 * RETURNS
296 * Success: Pointer to key
297 * Failure: NULL
299 static LPKEYSTRUCT get_handle( HKEY hkey )
301 int i;
303 for (i=0; i<nrofopenhandles; i++)
304 if (openhandles[i].hkey == hkey)
305 return openhandles[i].lpkey;
306 WARN_(reg)("Could not find handle 0x%x\n",hkey);
307 return NULL;
311 /******************************************************************************
312 * remove_handle [Internal]
314 * PARAMS
315 * hkey [I] Handle of key to remove
317 * RETURNS
318 * Success: ERROR_SUCCESS
319 * Failure: ERROR_INVALID_HANDLE
321 static DWORD remove_handle( HKEY hkey )
323 int i;
325 for (i=0;i<nrofopenhandles;i++)
326 if (openhandles[i].hkey==hkey)
327 break;
329 if (i == nrofopenhandles) {
330 WARN_(reg)("Could not find handle 0x%x\n",hkey);
331 return ERROR_INVALID_HANDLE;
334 memcpy( openhandles+i,
335 openhandles+i+1,
336 sizeof(struct openhandle)*(nrofopenhandles-i-1)
338 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
339 nrofopenhandles--;
340 return ERROR_SUCCESS;
343 /******************************************************************************
344 * lookup_hkey [Internal]
346 * Just as the name says. Creates the root keys on demand, so we can call the
347 * Reg* functions at any time.
349 * RETURNS
350 * Success: Pointer to key structure
351 * Failure: NULL
353 #define ADD_ROOT_KEY(xx) \
354 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
355 memset(xx,'\0',sizeof(KEYSTRUCT));\
356 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
358 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
360 switch (hkey) {
361 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
362 * some programs. Do not remove those cases. -MM
364 case 0x00000000:
365 case 0x00000001:
366 case HKEY_CLASSES_ROOT:
368 if (!key_classes_root)
370 HKEY cl_r_hkey;
372 /* calls lookup_hkey recursively, TWICE */
373 if ( RegCreateKey16(
374 HKEY_LOCAL_MACHINE,
375 "SOFTWARE\\Classes",
376 &cl_r_hkey) != ERROR_SUCCESS)
378 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
379 exit(1);
382 key_classes_root = lookup_hkey(cl_r_hkey);
384 return key_classes_root;
387 case HKEY_CURRENT_USER:
388 if (!key_current_user) {
389 ADD_ROOT_KEY(key_current_user);
391 return key_current_user;
393 case HKEY_LOCAL_MACHINE:
394 if (!key_local_machine) {
395 ADD_ROOT_KEY(key_local_machine);
396 REGISTRY_Init();
398 return key_local_machine;
400 case HKEY_USERS:
401 if (!key_users) {
402 ADD_ROOT_KEY(key_users);
404 return key_users;
406 case HKEY_PERFORMANCE_DATA:
407 if (!key_performance_data) {
408 ADD_ROOT_KEY(key_performance_data);
410 return key_performance_data;
412 case HKEY_DYN_DATA:
413 if (!key_dyn_data) {
414 ADD_ROOT_KEY(key_dyn_data);
416 return key_dyn_data;
418 case HKEY_CURRENT_CONFIG:
419 if (!key_current_config) {
420 ADD_ROOT_KEY(key_current_config);
422 return key_current_config;
424 default:
425 return get_handle(hkey);
428 /*NOTREACHED*/
433 * recursively searches for lpkey_to_find in the root key branch
434 * given in lpcurrkey.
436 static int subkey_found(LPKEYSTRUCT lpcurrkey, LPKEYSTRUCT lpkey_to_find)
438 while (lpcurrkey)
440 if (lpcurrkey == lpkey_to_find)
441 return 1;
442 if (subkey_found(lpcurrkey->nextsub, lpkey_to_find))
443 return 1;
445 lpcurrkey = lpcurrkey->next;
448 TRACE_(reg)("No key found in this root key branch\n");
449 return 0;
454 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
456 static HKEY find_root_key(LPKEYSTRUCT lpkey)
458 typedef struct tagROOT_KEYS {
459 KEYSTRUCT *lpkey;
460 HKEY hkey;
461 } ROOT_KEYS;
462 ROOT_KEYS root_keys[4];
463 int i;
465 root_keys[0].lpkey = key_classes_root;
466 root_keys[0].hkey = HKEY_CLASSES_ROOT;
467 root_keys[1].lpkey = key_current_user;
468 root_keys[1].hkey = HKEY_CURRENT_USER;
469 root_keys[2].lpkey = key_local_machine;
470 root_keys[2].hkey = HKEY_LOCAL_MACHINE;
471 root_keys[3].lpkey = key_users;
472 root_keys[3].hkey = HKEY_USERS;
474 for (i=0; i<4;i++)
476 if (subkey_found(root_keys[i].lpkey, lpkey))
477 return root_keys[i].hkey;
479 ERR_(reg)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
480 return 0;
481 #undef ROOT_KEYS
483 #undef ADD_ROOT_KEY
484 /* so we don't accidently access them ... */
485 #define key_current_config NULL NULL
486 #define key_current_user NULL NULL
487 #define key_users NULL NULL
488 #define key_local_machine NULL NULL
489 #define key_classes_root NULL NULL
490 #define key_dyn_data NULL NULL
491 #define key_performance_data NULL NULL
493 /******************************************************************************
494 * split_keypath [Internal]
495 * splits the unicode string 'wp' into an array of strings.
496 * the array is allocated by this function.
497 * Free the array using FREE_KEY_PATH
499 * PARAMS
500 * wp [I] String to split up
501 * wpv [O] Array of pointers to strings
502 * wpc [O] Number of components
504 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
506 int i,j,len;
507 LPWSTR ws;
509 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
511 ws = HEAP_strdupW( SystemHeap, 0, wp );
513 /* We know we have at least one substring */
514 *wpc = 1;
516 /* Replace each backslash with NULL, and increment the count */
517 for (i=0;ws[i];i++) {
518 if (ws[i]=='\\') {
519 ws[i]=0;
520 (*wpc)++;
524 len = i;
526 /* Allocate the space for the array of pointers, leaving room for the
527 NULL at the end */
528 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
529 (*wpv)[0]= ws;
531 /* Assign each pointer to the appropriate character in the string */
532 j = 1;
533 for (i=1;i<len;i++)
534 if (ws[i-1]==0) {
535 (*wpv)[j++]=ws+i;
536 /*TRACE_(reg) (" Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1]));*/
539 (*wpv)[j]=NULL;
541 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
546 /******************************************************************************
547 * REGISTRY_Init [Internal]
548 * Registry initialisation, allocates some default keys.
550 static void REGISTRY_Init(void) {
551 HKEY hkey;
552 char buf[200];
554 TRACE_(reg)("(void)\n");
556 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
557 RegCloseKey(hkey);
559 /* This was an Open, but since it is called before the real registries
560 are loaded, it was changed to a Create - MTB 980507*/
561 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
562 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
563 RegCloseKey(hkey);
565 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
566 * CurrentVersion
567 * CurrentBuildNumber
568 * CurrentType
569 * string RegisteredOwner
570 * string RegisteredOrganization
573 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
574 * string SysContact
575 * string SysLocation
576 * SysServices
578 if (-1!=gethostname(buf,200)) {
579 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
580 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
581 RegCloseKey(hkey);
586 /************************ SAVE Registry Function ****************************/
588 #define REGISTRY_SAVE_VERSION 0x00000001
590 /* Registry saveformat:
591 * If you change it, increase above number by 1, which will flush
592 * old registry database files.
594 * Global:
595 * "WINE REGISTRY Version %d"
596 * subkeys....
597 * Subkeys:
598 * keyname
599 * valuename=lastmodified,type,data
600 * ...
601 * subkeys
602 * ...
603 * keyname,valuename,stringdata:
604 * the usual ascii characters from 0x00-0xff (well, not 0x00)
605 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
606 * ( "=\\\t" escaped in \uXXXX form.)
607 * type,lastmodified:
608 * int
610 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
612 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
613 * SaveOnlyUpdatedKeys=yes
616 /******************************************************************************
617 * _save_check_tainted [Internal]
619 static int _save_check_tainted( LPKEYSTRUCT lpkey )
621 int tainted = 0;
623 while (lpkey) {
624 if (_save_check_tainted(lpkey->nextsub))
625 lpkey->flags |= REG_OPTION_TAINTED;
626 if (lpkey->flags & REG_OPTION_TAINTED)
627 tainted = 1;
628 lpkey = lpkey->next;
630 return tainted;
633 /******************************************************************************
634 * _save_USTRING [Internal]
636 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
638 LPWSTR s;
639 int doescape;
641 if (wstr==NULL)
642 return;
643 s=wstr;
644 while (*s) {
645 doescape=0;
646 if (*s>0x7f)
647 doescape = 1;
648 if (*s=='\n')
649 doescape = 1;
650 if (escapeeq && *s=='=')
651 doescape = 1;
652 if (*s=='\\')
653 fputc(*s,F); /* if \\ then put it twice. */
654 if (doescape)
655 fprintf(F,"\\u%04x",*((unsigned short*)s));
656 else
657 fputc(*s,F);
658 s++;
662 /******************************************************************************
663 * _savesubkey [Internal]
665 * NOTES
666 * REG_MULTI_SZ is handled as binary (like in win95) (js)
668 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
670 LPKEYSTRUCT lpxkey;
671 int i,tabs,j;
673 lpxkey = lpkey;
674 while (lpxkey) {
675 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
676 (all || (lpxkey->flags & REG_OPTION_TAINTED))
678 for (tabs=level;tabs--;)
679 fputc('\t',F);
680 _save_USTRING(F,lpxkey->keyname,1);
681 fputs("\n",F);
682 for (i=0;i<lpxkey->nrofvalues;i++) {
683 LPKEYVALUE val=lpxkey->values+i;
685 for (tabs=level+1;tabs--;)
686 fputc('\t',F);
687 _save_USTRING(F,val->name,0);
688 fputc('=',F);
689 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
690 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
691 _save_USTRING(F,(LPWSTR)val->data,0);
692 else
693 for (j=0;j<val->len;j++)
694 fprintf(F,"%02x",*((unsigned char*)val->data+j));
695 fputs("\n",F);
697 /* descend recursively */
698 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
699 return 0;
701 lpxkey=lpxkey->next;
703 return 1;
707 /******************************************************************************
708 * _savesubreg [Internal]
710 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
712 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
713 _save_check_tainted(lpkey->nextsub);
714 return _savesubkey(F,lpkey->nextsub,0,all);
718 /******************************************************************************
719 * _savereg [Internal]
721 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
723 FILE *F;
725 F=fopen(fn,"w");
726 if (F==NULL) {
727 WARN_(reg)("Couldn't open %s for writing: %s\n",
728 fn,strerror(errno)
730 return FALSE;
732 if (!_savesubreg(F,lpkey,all)) {
733 fclose(F);
734 unlink(fn);
735 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
736 return FALSE;
738 fclose(F);
739 return TRUE;
743 /******************************************************************************
744 * SHELL_SaveRegistryBranch [Internal]
746 * Saves main registry branch specified by hkey.
748 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
750 char *fn, *home, *tmp;
752 /* Find out what to save to, get from config file */
753 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
754 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
756 /* FIXME: does this check apply to all keys written below ? */
757 if (!(home = getenv( "HOME" )))
758 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
760 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
761 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
763 switch (hkey)
765 case HKEY_CURRENT_USER:
766 fn = xmalloc( MAX_PATHNAME_LEN );
767 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
768 fn, MAX_PATHNAME_LEN - 1))
769 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
770 free (fn);
772 if (home && writeToHome)
774 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
775 strlen(SAVE_CURRENT_USER) + 2 );
776 strcpy(fn,home);
777 strcat(fn,WINE_PREFIX);
779 /* create the directory. don't care about errorcodes. */
780 mkdir(fn,0755); /* drwxr-xr-x */
781 strcat(fn,"/"SAVE_CURRENT_USER);
783 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
784 strcpy(tmp,fn);
785 strcat(tmp,".tmp");
787 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
788 if (-1==rename(tmp,fn)) {
789 perror("rename tmp registry");
790 unlink(tmp);
793 free(tmp);
794 free(fn);
796 break;
797 case HKEY_LOCAL_MACHINE:
798 /* Try first saving according to the defined location in .winerc */
799 fn = xmalloc ( MAX_PATHNAME_LEN);
800 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
801 fn, MAX_PATHNAME_LEN - 1))
802 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
803 free (fn);
805 if (home && writeToHome)
807 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
808 strlen(SAVE_LOCAL_MACHINE) + 2);
809 strcpy(fn,home);
810 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
812 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
813 strcpy(tmp,fn);
814 strcat(tmp,".tmp");
816 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
817 if (-1==rename(tmp,fn)) {
818 perror("rename tmp registry");
819 unlink(tmp);
822 free(tmp);
823 free(fn);
825 break;
826 case HKEY_USERS:
827 fn = xmalloc( MAX_PATHNAME_LEN );
828 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
829 fn, MAX_PATHNAME_LEN - 1))
830 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
831 free (fn);
833 if (home && writeToHome)
835 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
836 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
837 strcpy(fn,home);
838 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
840 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
841 strcpy(tmp,fn);
842 strcat(tmp,".tmp");
843 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
844 if (-1==rename(tmp,fn)) {
845 perror("rename tmp registry");
846 unlink(tmp);
849 free(tmp);
850 free(fn);
852 break;
853 default:
854 ERR_(reg)("unknown/invalid key handle !\n");
855 break;
860 /******************************************************************************
861 * SHELL_SaveRegistry [Internal]
863 void SHELL_SaveRegistry( void )
865 char buf[4];
866 HKEY hkey;
867 int all;
869 TRACE_(reg)("(void)\n");
871 all=0;
872 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
874 strcpy(buf,"yes");
876 else
878 DWORD len,junk,type;
880 len=4;
881 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
882 VAL_SAVEUPDATED,
883 &junk,
884 &type,
885 buf,
886 &len)) || (type!=REG_SZ))
888 strcpy(buf,"yes");
890 RegCloseKey(hkey);
893 if (lstrcmpiA(buf,"yes"))
894 all = 1;
896 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
897 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
898 SHELL_SaveRegistryBranch(HKEY_USERS, all);
902 /************************ LOAD Registry Function ****************************/
906 /******************************************************************************
907 * _find_or_add_key [Internal]
909 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
911 LPKEYSTRUCT lpxkey,*lplpkey;
913 if ((!keyname) || (keyname[0]==0)) {
914 free(keyname);
915 return lpkey;
917 lplpkey= &(lpkey->nextsub);
918 lpxkey = *lplpkey;
919 while (lpxkey) {
920 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
921 !lstrcmpiW(lpxkey->keyname,keyname)
923 break;
924 lplpkey = &(lpxkey->next);
925 lpxkey = *lplpkey;
927 if (lpxkey==NULL) {
928 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
929 lpxkey = *lplpkey;
930 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
931 lpxkey->keyname = keyname;
932 } else
933 free(keyname);
934 return lpxkey;
937 /******************************************************************************
938 * _find_or_add_value [Internal]
940 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
941 LPBYTE data, DWORD len, DWORD lastmodified )
943 LPKEYVALUE val=NULL;
944 int i;
946 if (name && !*name) {/* empty string equals default (NULL) value */
947 free(name);
948 name = NULL;
951 for (i=0;i<lpkey->nrofvalues;i++) {
952 val=lpkey->values+i;
953 if (name==NULL) {
954 if (val->name==NULL)
955 break;
956 } else {
957 if ( val->name!=NULL &&
958 tolower(val->name[0])==tolower(name[0]) &&
959 !lstrcmpiW(val->name,name)
961 break;
964 if (i==lpkey->nrofvalues) {
965 lpkey->values = xrealloc(
966 lpkey->values,
967 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
969 val=lpkey->values+i;
970 memset(val,'\0',sizeof(KEYVALUE));
971 val->name = name;
972 } else {
973 if (name)
974 free(name);
976 if (val->lastmodified<lastmodified) {
977 val->lastmodified=lastmodified;
978 val->type = type;
980 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
982 data=xmalloc(sizeof(WCHAR));
983 memset(data,0,sizeof(WCHAR));
984 len =sizeof(WCHAR);
987 val->len = len;
988 if (val->data)
989 free(val->data);
990 val->data = data;
991 } else
992 free(data);
996 /******************************************************************************
997 * _wine_read_line [Internal]
999 * reads a line including dynamically enlarging the readbuffer and throwing
1000 * away comments
1002 static int _wine_read_line( FILE *F, char **buf, int *len )
1004 char *s,*curread;
1005 int mylen,curoff;
1007 curread = *buf;
1008 mylen = *len;
1009 **buf = '\0';
1010 while (1) {
1011 while (1) {
1012 s=fgets(curread,mylen,F);
1013 if (s==NULL)
1014 return 0; /* EOF */
1015 if (NULL==(s=strchr(curread,'\n'))) {
1016 /* buffer wasn't large enough */
1017 curoff = strlen(*buf);
1018 *buf = xrealloc(*buf,*len*2);
1019 curread = *buf + curoff;
1020 mylen = *len; /* we filled up the buffer and
1021 * got new '*len' bytes to fill
1023 *len = *len * 2;
1024 } else {
1025 *s='\0';
1026 break;
1029 /* throw away comments */
1030 if (**buf=='#' || **buf==';') {
1031 curread = *buf;
1032 mylen = *len;
1033 continue;
1035 if (s) /* got end of line */
1036 break;
1038 return 1;
1042 /******************************************************************************
1043 * _wine_read_USTRING [Internal]
1045 * converts a char* into a UNICODE string (up to a special char)
1046 * and returns the position exactly after that string
1048 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1050 char *s;
1051 LPWSTR ws;
1053 /* read up to "=" or "\0" or "\n" */
1054 s = buf;
1055 if (*s == '=') {
1056 /* empty string is the win3.1 default value(NULL)*/
1057 *str = NULL;
1058 return s;
1060 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1061 ws = *str;
1062 while (*s && (*s!='\n') && (*s!='=')) {
1063 if (*s!='\\')
1064 *ws++=*((unsigned char*)s++);
1065 else {
1066 s++;
1067 if (!*s) {
1068 /* Dangling \ ... may only happen if a registry
1069 * write was short. FIXME: What do to?
1071 break;
1073 if (*s=='\\') {
1074 *ws++='\\';
1075 s++;
1076 continue;
1078 if (*s!='u') {
1079 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1080 *ws++='\\';
1081 *ws++=*s++;
1082 } else {
1083 char xbuf[5];
1084 int wc;
1086 s++;
1087 memcpy(xbuf,s,4);xbuf[4]='\0';
1088 if (!sscanf(xbuf,"%x",&wc))
1089 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1090 s+=4;
1091 *ws++ =(unsigned short)wc;
1095 *ws = 0;
1096 ws = *str;
1097 if (*ws)
1098 *str = strdupW(*str);
1099 else
1100 *str = NULL;
1101 free(ws);
1102 return s;
1106 /******************************************************************************
1107 * _wine_loadsubkey [Internal]
1109 * NOTES
1110 * It seems like this is returning a boolean. Should it?
1112 * RETURNS
1113 * Success: 1
1114 * Failure: 0
1116 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1117 int *buflen, DWORD optflag )
1119 LPKEYSTRUCT lpxkey;
1120 int i;
1121 char *s;
1122 LPWSTR name;
1124 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1125 *buflen, optflag);
1127 lpkey->flags |= optflag;
1129 /* Good. We already got a line here ... so parse it */
1130 lpxkey = NULL;
1131 while (1) {
1132 i=0;s=*buf;
1133 while (*s=='\t') {
1134 s++;
1135 i++;
1137 if (i>level) {
1138 if (lpxkey==NULL) {
1139 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1140 return 0;
1142 if (!_wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag))
1143 if (!_wine_read_line(F,buf,buflen))
1144 return 1;
1145 continue;
1148 /* let the caller handle this line */
1149 if (i<level || **buf=='\0')
1150 return 1;
1152 /* it can be: a value or a keyname. Parse the name first */
1153 s=_wine_read_USTRING(s,&name);
1155 /* switch() default: hack to avoid gotos */
1156 switch (0) {
1157 default:
1158 if (*s=='\0') {
1159 lpxkey=_find_or_add_key(lpkey,name);
1160 } else {
1161 LPBYTE data;
1162 int len,lastmodified,type;
1164 if (*s!='=') {
1165 WARN_(reg)("Unexpected character: %c\n",*s);
1166 break;
1168 s++;
1169 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1170 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1171 break;
1173 /* skip the 2 , */
1174 s=strchr(s,',');s++;
1175 s=strchr(s,',');
1176 if (!s++) {
1177 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1178 break;
1180 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1181 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1182 if (data)
1183 len = lstrlenW((LPWSTR)data)*2+2;
1184 else
1185 len = 0;
1186 } else {
1187 len=strlen(s)/2;
1188 data = (LPBYTE)xmalloc(len+1);
1189 for (i=0;i<len;i++) {
1190 data[i]=0;
1191 if (*s>='0' && *s<='9')
1192 data[i]=(*s-'0')<<4;
1193 if (*s>='a' && *s<='f')
1194 data[i]=(*s-'a'+'\xa')<<4;
1195 if (*s>='A' && *s<='F')
1196 data[i]=(*s-'A'+'\xa')<<4;
1197 s++;
1198 if (*s>='0' && *s<='9')
1199 data[i]|=*s-'0';
1200 if (*s>='a' && *s<='f')
1201 data[i]|=*s-'a'+'\xa';
1202 if (*s>='A' && *s<='F')
1203 data[i]|=*s-'A'+'\xa';
1204 s++;
1207 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1210 /* read the next line */
1211 if (!_wine_read_line(F,buf,buflen))
1212 return 1;
1214 return 1;
1218 /******************************************************************************
1219 * _wine_loadsubreg [Internal]
1221 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1223 int ver;
1224 char *buf;
1225 int buflen;
1227 buf=xmalloc(10);buflen=10;
1228 if (!_wine_read_line(F,&buf,&buflen)) {
1229 free(buf);
1230 return 0;
1232 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1233 free(buf);
1234 return 0;
1236 if (ver!=REGISTRY_SAVE_VERSION) {
1237 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1238 free(buf);
1239 return 0;
1241 if (!_wine_read_line(F,&buf,&buflen)) {
1242 free(buf);
1243 return 0;
1245 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1246 free(buf);
1247 return 0;
1249 free(buf);
1250 return 1;
1254 /******************************************************************************
1255 * _wine_loadreg [Internal]
1257 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1259 FILE *F;
1261 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1263 F = fopen(fn,"rb");
1264 if (F==NULL) {
1265 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1266 return;
1268 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1269 fclose(F);
1270 unlink(fn);
1271 return;
1273 fclose(F);
1276 /******************************************************************************
1277 * _flush_registry [Internal]
1279 * This function allow to flush section of the internal registry. It is mainly
1280 * implements to fix a problem with the global HKU and the local HKU.
1281 * Those two files are read to build the HKU\.Default branch to finaly copy
1282 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1283 * all the global HKU are saved onto the user's personal version of HKU hive.
1284 * which is bad...
1287 /* Forward declaration of recusive agent */
1288 static void _flush_reg(LPKEYSTRUCT from);
1290 static void _flush_registry( LPKEYSTRUCT from )
1292 /* make sure we have something... */
1293 if (from == NULL)
1294 return;
1296 /* Launch the recusive agent on sub branches */
1297 _flush_reg( from->nextsub );
1298 _flush_reg( from->next );
1300 /* Initialize pointers */
1301 from->nextsub = NULL;
1302 from->next = NULL;
1304 static void _flush_reg( LPKEYSTRUCT from )
1306 int j;
1308 /* make sure we have something... */
1309 if (from == NULL)
1310 return;
1313 * do the same for the child keys
1315 if (from->nextsub != NULL)
1316 _flush_reg(from->nextsub);
1319 * do the same for the sibling keys
1321 if (from->next != NULL)
1322 _flush_reg(from->next);
1325 * iterate through this key's values and delete them
1327 for (j=0;j<from->nrofvalues;j++)
1329 free( (from->values+j)->name);
1330 free( (from->values+j)->data);
1334 * free the structure
1336 if ( from != NULL )
1337 free(from);
1341 /******************************************************************************
1342 * _copy_registry [Internal]
1344 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1346 LPKEYSTRUCT lpxkey;
1347 int j;
1348 LPKEYVALUE valfrom;
1350 from=from->nextsub;
1351 while (from) {
1352 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1354 for (j=0;j<from->nrofvalues;j++) {
1355 LPWSTR name;
1356 LPBYTE data;
1358 valfrom = from->values+j;
1359 name=valfrom->name;
1360 if (name) name=strdupW(name);
1361 data=(LPBYTE)xmalloc(valfrom->len);
1362 memcpy(data,valfrom->data,valfrom->len);
1364 _find_or_add_value(
1365 lpxkey,
1366 name,
1367 valfrom->type,
1368 data,
1369 valfrom->len,
1370 valfrom->lastmodified
1373 _copy_registry(from,lpxkey);
1374 from = from->next;
1379 /* WINDOWS 95 REGISTRY LOADER */
1381 * Structure of a win95 registry database.
1382 * main header:
1383 * 0 : "CREG" - magic
1384 * 4 : DWORD version
1385 * 8 : DWORD offset_of_RGDB_part
1386 * 0C..0F: ? (someone fill in please)
1387 * 10: WORD number of RGDB blocks
1388 * 12: WORD ?
1389 * 14: WORD always 0000?
1390 * 16: WORD always 0001?
1391 * 18..1F: ? (someone fill in please)
1393 * 20: RGKN_section:
1394 * header:
1395 * 0 : "RGKN" - magic
1396 * 4 : DWORD offset to first RGDB section
1397 * 8 : DWORD offset to the root record
1398 * C..0x1B: ? (fill in)
1399 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1401 * Disk Key Entry Structure:
1402 * 00: DWORD - Free entry indicator(?)
1403 * 04: DWORD - Hash = sum of bytes of keyname
1404 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1405 * 0C: DWORD - disk address of PreviousLevel Key.
1406 * 10: DWORD - disk address of Next Sublevel Key.
1407 * 14: DWORD - disk address of Next Key (on same level).
1408 * DKEP>18: WORD - Nr, Low Significant part.
1409 * 1A: WORD - Nr, High Significant part.
1411 * The disk address always points to the nr part of the previous key entry
1412 * of the referenced key. Don't ask me why, or even if I got this correct
1413 * from staring at 1kg of hexdumps. (DKEP)
1415 * The High significant part of the structure seems to equal the number
1416 * of the RGDB section. The low significant part is a unique ID within
1417 * that RGDB section
1419 * There are two minor corrections to the position of that structure.
1420 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1421 * the DKE reread from there.
1422 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1423 * CPS - I have not experienced the above phenomenon in my registry files
1425 * RGDB_section:
1426 * 00: "RGDB" - magic
1427 * 04: DWORD offset to next RGDB section
1428 * 08: DWORD ?
1429 * 0C: WORD always 000d?
1430 * 0E: WORD RGDB block number
1431 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1432 * 14..1F: ?
1433 * 20.....: disk keys
1435 * disk key:
1436 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1437 * 08: WORD nrLS - low significant part of NR
1438 * 0A: WORD nrHS - high significant part of NR
1439 * 0C: DWORD bytesused - bytes used in this structure.
1440 * 10: WORD name_len - length of name in bytes. without \0
1441 * 12: WORD nr_of_values - number of values.
1442 * 14: char name[name_len] - name string. No \0.
1443 * 14+name_len: disk values
1444 * nextkeyoffset: ... next disk key
1446 * disk value:
1447 * 00: DWORD type - value type (hmm, could be WORD too)
1448 * 04: DWORD - unknown, usually 0
1449 * 08: WORD namelen - length of Name. 0 means name=NULL
1450 * 0C: WORD datalen - length of Data.
1451 * 10: char name[namelen] - name, no \0
1452 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1453 * 10+namelen+datalen: next values or disk key
1455 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1456 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1457 * structure) and reading another RGDB_section.
1458 * repeat until end of file.
1460 * An interesting relationship exists in RGDB_section. The value at offset
1461 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1462 * idea at the moment what this means. (Kevin Cozens)
1464 * FIXME: this description needs some serious help, yes.
1467 struct _w95keyvalue {
1468 unsigned long type;
1469 unsigned short datalen;
1470 char *name;
1471 unsigned char *data;
1472 unsigned long x1;
1473 int lastmodified;
1476 struct _w95key {
1477 char *name;
1478 int nrofvals;
1479 struct _w95keyvalue *values;
1480 struct _w95key *prevlvl;
1481 struct _w95key *nextsub;
1482 struct _w95key *next;
1486 struct _w95_info {
1487 char *rgknbuffer;
1488 int rgknsize;
1489 char *rgdbbuffer;
1490 int rgdbsize;
1491 int depth;
1492 int lastmodified;
1496 /******************************************************************************
1497 * _w95_processKey [Internal]
1499 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1500 int nrLS, int nrMS, struct _w95_info *info )
1503 /* Disk Key Header structure (RGDB part) */
1504 struct dkh {
1505 unsigned long nextkeyoff;
1506 unsigned short nrLS;
1507 unsigned short nrMS;
1508 unsigned long bytesused;
1509 unsigned short keynamelen;
1510 unsigned short values;
1511 unsigned long xx1;
1512 /* keyname */
1513 /* disk key values or nothing */
1515 /* Disk Key Value structure */
1516 struct dkv {
1517 unsigned long type;
1518 unsigned long x1;
1519 unsigned short valnamelen;
1520 unsigned short valdatalen;
1521 /* valname, valdata */
1525 struct dkh dkh;
1526 int bytesread = 0;
1527 char *rgdbdata = info->rgdbbuffer;
1528 int nbytes = info->rgdbsize;
1529 char *curdata = rgdbdata;
1530 char *end = rgdbdata + nbytes;
1531 int off_next_rgdb;
1532 char *next = rgdbdata;
1533 int nrgdb, i;
1534 LPKEYSTRUCT lpxkey;
1536 do {
1537 curdata = next;
1538 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1540 memcpy(&off_next_rgdb,curdata+4,4);
1541 next = curdata + off_next_rgdb;
1542 nrgdb = (int) *((short *)curdata + 7);
1544 } while (nrgdb != nrMS && (next < end));
1546 /* curdata now points to the start of the right RGDB section */
1547 curdata += 0x20;
1549 #define XREAD(whereto,len) \
1550 if ((curdata + len) <= end) {\
1551 memcpy(whereto,curdata,len);\
1552 curdata+=len;\
1553 bytesread+=len;\
1556 while (curdata < next) {
1557 struct dkh *xdkh = (struct dkh*)curdata;
1559 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1560 if (xdkh->nrLS == nrLS) {
1561 memcpy(&dkh,xdkh,sizeof(dkh));
1562 curdata += sizeof(dkh);
1563 break;
1565 curdata += xdkh->nextkeyoff;
1568 if (dkh.nrLS != nrLS) return (NULL);
1570 if (nrgdb != dkh.nrMS)
1571 return (NULL);
1573 assert((dkh.keynamelen<2) || curdata[0]);
1574 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1575 curdata += dkh.keynamelen;
1577 for (i=0;i< dkh.values; i++) {
1578 struct dkv dkv;
1579 LPBYTE data;
1580 int len;
1581 LPWSTR name;
1583 XREAD(&dkv,sizeof(dkv));
1585 name = strcvtA2W(curdata, dkv.valnamelen);
1586 curdata += dkv.valnamelen;
1588 if ((1 << dkv.type) & UNICONVMASK) {
1589 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1590 len = 2*(dkv.valdatalen + 1);
1591 } else {
1592 /* I don't think we want to NULL terminate all data */
1593 data = xmalloc(dkv.valdatalen);
1594 memcpy (data, curdata, dkv.valdatalen);
1595 len = dkv.valdatalen;
1598 curdata += dkv.valdatalen;
1600 _find_or_add_value(
1601 lpxkey,
1602 name,
1603 dkv.type,
1604 data,
1605 len,
1606 info->lastmodified
1609 return (lpxkey);
1612 /******************************************************************************
1613 * _w95_walkrgkn [Internal]
1615 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1616 struct _w95_info *info )
1619 /* Disk Key Entry structure (RGKN part) */
1620 struct dke {
1621 unsigned long x1;
1622 unsigned long x2;
1623 unsigned long x3;/*usually 0xFFFFFFFF */
1624 unsigned long prevlvl;
1625 unsigned long nextsub;
1626 unsigned long next;
1627 unsigned short nrLS;
1628 unsigned short nrMS;
1629 } *dke = (struct dke *)off;
1630 LPKEYSTRUCT lpxkey;
1632 if (dke == NULL) {
1633 dke = (struct dke *) ((char *)info->rgknbuffer);
1636 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1637 /* XXX <-- This is a hack*/
1638 if (!lpxkey) {
1639 lpxkey = prevkey;
1642 if (dke->nextsub != -1 &&
1643 ((dke->nextsub - 0x20) < info->rgknsize)
1644 && (dke->nextsub > 0x20)) {
1646 _w95_walkrgkn(lpxkey,
1647 info->rgknbuffer + dke->nextsub - 0x20,
1648 info);
1651 if (dke->next != -1 &&
1652 ((dke->next - 0x20) < info->rgknsize) &&
1653 (dke->next > 0x20)) {
1654 _w95_walkrgkn(prevkey,
1655 info->rgknbuffer + dke->next - 0x20,
1656 info);
1659 return;
1663 /******************************************************************************
1664 * _w95_loadreg [Internal]
1666 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1668 HFILE hfd;
1669 char magic[5];
1670 unsigned long where,version,rgdbsection,end;
1671 struct _w95_info info;
1672 OFSTRUCT ofs;
1673 BY_HANDLE_FILE_INFORMATION hfdinfo;
1675 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1676 hfd=OpenFile(fn,&ofs,OF_READ);
1677 if (hfd==HFILE_ERROR)
1678 return;
1679 magic[4]=0;
1680 if (4!=_lread(hfd,magic,4))
1681 return;
1682 if (strcmp(magic,"CREG")) {
1683 WARN_(reg)("%s is not a w95 registry.\n",fn);
1684 return;
1686 if (4!=_lread(hfd,&version,4))
1687 return;
1688 if (4!=_lread(hfd,&rgdbsection,4))
1689 return;
1690 if (-1==_llseek(hfd,0x20,SEEK_SET))
1691 return;
1692 if (4!=_lread(hfd,magic,4))
1693 return;
1694 if (strcmp(magic,"RGKN")) {
1695 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1696 return;
1699 /* STEP 1: Keylink structures */
1700 if (-1==_llseek(hfd,0x40,SEEK_SET))
1701 return;
1702 where = 0x40;
1703 end = rgdbsection;
1705 info.rgknsize = end - where;
1706 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1707 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1708 return;
1710 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1711 return;
1713 end = hfdinfo.nFileSizeLow;
1714 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1716 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1717 return;
1719 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1720 info.rgdbsize = end - rgdbsection;
1722 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1723 return;
1724 _lclose(hfd);
1726 _w95_walkrgkn(lpkey, NULL, &info);
1728 free (info.rgdbbuffer);
1729 free (info.rgknbuffer);
1733 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1736 reghack - windows 3.11 registry data format demo program.
1738 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1739 a combined hash table and tree description, and finally a text table.
1741 The header is obvious from the struct header. The taboff1 and taboff2
1742 fields are always 0x20, and their usage is unknown.
1744 The 8-byte entry table has various entry types.
1746 tabent[0] is a root index. The second word has the index of the root of
1747 the directory.
1748 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1749 the index of the key/value that has that hash. Data with the same
1750 hash value are on a circular list. The other three words in the
1751 hash entry are always zero.
1752 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1753 entry: dirent and keyent/valent. They are identified by context.
1754 tabent[freeidx] is the first free entry. The first word in a free entry
1755 is the index of the next free entry. The last has 0 as a link.
1756 The other three words in the free list are probably irrelevant.
1758 Entries in text table are preceeded by a word at offset-2. This word
1759 has the value (2*index)+1, where index is the referring keyent/valent
1760 entry in the table. I have no suggestion for the 2* and the +1.
1761 Following the word, there are N bytes of data, as per the keyent/valent
1762 entry length. The offset of the keyent/valent entry is from the start
1763 of the text table to the first data byte.
1765 This information is not available from Microsoft. The data format is
1766 deduced from the reg.dat file by me. Mistakes may
1767 have been made. I claim no rights and give no guarantees for this program.
1769 Tor Sjøwall, tor@sn.no
1772 /* reg.dat header format */
1773 struct _w31_header {
1774 char cookie[8]; /* 'SHCC3.10' */
1775 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1776 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1777 unsigned long tabcnt; /* number of entries in index table */
1778 unsigned long textoff; /* offset of text part */
1779 unsigned long textsize; /* byte size of text part */
1780 unsigned short hashsize; /* hash size */
1781 unsigned short freeidx; /* free index */
1784 /* generic format of table entries */
1785 struct _w31_tabent {
1786 unsigned short w0, w1, w2, w3;
1789 /* directory tabent: */
1790 struct _w31_dirent {
1791 unsigned short sibling_idx; /* table index of sibling dirent */
1792 unsigned short child_idx; /* table index of child dirent */
1793 unsigned short key_idx; /* table index of key keyent */
1794 unsigned short value_idx; /* table index of value valent */
1797 /* key tabent: */
1798 struct _w31_keyent {
1799 unsigned short hash_idx; /* hash chain index for string */
1800 unsigned short refcnt; /* reference count */
1801 unsigned short length; /* length of string */
1802 unsigned short string_off; /* offset of string in text table */
1805 /* value tabent: */
1806 struct _w31_valent {
1807 unsigned short hash_idx; /* hash chain index for string */
1808 unsigned short refcnt; /* reference count */
1809 unsigned short length; /* length of string */
1810 unsigned short string_off; /* offset of string in text table */
1813 /* recursive helper function to display a directory tree */
1814 void
1815 __w31_dumptree( unsigned short idx,
1816 unsigned char *txt,
1817 struct _w31_tabent *tab,
1818 struct _w31_header *head,
1819 LPKEYSTRUCT lpkey,
1820 time_t lastmodified,
1821 int level
1823 struct _w31_dirent *dir;
1824 struct _w31_keyent *key;
1825 struct _w31_valent *val;
1826 LPKEYSTRUCT xlpkey = NULL;
1827 LPWSTR name,value;
1828 static char tail[400];
1830 while (idx!=0) {
1831 dir=(struct _w31_dirent*)&tab[idx];
1833 if (dir->key_idx) {
1834 key = (struct _w31_keyent*)&tab[dir->key_idx];
1836 memcpy(tail,&txt[key->string_off],key->length);
1837 tail[key->length]='\0';
1838 /* all toplevel entries AND the entries in the
1839 * toplevel subdirectory belong to \SOFTWARE\Classes
1841 if (!level && !lstrcmpA(tail,".classes")) {
1842 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1843 idx=dir->sibling_idx;
1844 continue;
1846 name=strdupA2W(tail);
1848 xlpkey=_find_or_add_key(lpkey,name);
1850 /* only add if leaf node or valued node */
1851 if (dir->value_idx!=0||dir->child_idx==0) {
1852 if (dir->value_idx) {
1853 val=(struct _w31_valent*)&tab[dir->value_idx];
1854 memcpy(tail,&txt[val->string_off],val->length);
1855 tail[val->length]='\0';
1856 value=strdupA2W(tail);
1857 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1860 } else {
1861 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1863 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1864 idx=dir->sibling_idx;
1869 /******************************************************************************
1870 * _w31_loadreg [Internal]
1872 void _w31_loadreg(void) {
1873 HFILE hf;
1874 struct _w31_header head;
1875 struct _w31_tabent *tab;
1876 unsigned char *txt;
1877 int len;
1878 OFSTRUCT ofs;
1879 BY_HANDLE_FILE_INFORMATION hfinfo;
1880 time_t lastmodified;
1881 LPKEYSTRUCT lpkey;
1883 TRACE_(reg)("(void)\n");
1885 hf = OpenFile("reg.dat",&ofs,OF_READ);
1886 if (hf==HFILE_ERROR)
1887 return;
1889 /* read & dump header */
1890 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1891 ERR_(reg)("reg.dat is too short.\n");
1892 _lclose(hf);
1893 return;
1895 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1896 ERR_(reg)("reg.dat has bad signature.\n");
1897 _lclose(hf);
1898 return;
1901 len = head.tabcnt * sizeof(struct _w31_tabent);
1902 /* read and dump index table */
1903 tab = xmalloc(len);
1904 if (len!=_lread(hf,tab,len)) {
1905 ERR_(reg)("couldn't read %d bytes.\n",len);
1906 free(tab);
1907 _lclose(hf);
1908 return;
1911 /* read text */
1912 txt = xmalloc(head.textsize);
1913 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1914 ERR_(reg)("couldn't seek to textblock.\n");
1915 free(tab);
1916 free(txt);
1917 _lclose(hf);
1918 return;
1920 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1921 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1922 free(tab);
1923 free(txt);
1924 _lclose(hf);
1925 return;
1928 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1929 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1930 free(tab);
1931 free(txt);
1932 _lclose(hf);
1933 return;
1935 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1936 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1937 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1938 free(tab);
1939 free(txt);
1940 _lclose(hf);
1941 return;
1945 /**********************************************************************************
1946 * SHELL_LoadRegistry [Internal]
1948 void SHELL_LoadRegistry( void )
1950 char *fn, *home;
1951 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1952 HKEY hkey;
1954 TRACE_(reg)("(void)\n");
1956 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1957 HKU = lookup_hkey(HKEY_USERS);
1958 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1960 if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1))
1962 /* Load windows 3.1 entries */
1963 _w31_loadreg();
1964 /* Load windows 95 entries */
1965 _w95_loadreg("C:\\system.1st", HKLM);
1966 _w95_loadreg("system.dat", HKLM);
1967 _w95_loadreg("user.dat", HKU);
1970 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1973 * Load the global HKU hive directly from sysconfdir
1975 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1978 * Load the global machine defaults directly form sysconfdir
1980 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1984 * Load the user saved registries
1986 if (!(home = getenv( "HOME" )))
1987 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1988 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1991 * Load user's personal versions of global HKU/.Default keys
1993 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
1994 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1995 strcpy(fn, home);
1996 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1997 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1998 free(fn);
2000 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
2001 strcpy(fn, home);
2002 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2003 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2004 free(fn);
2007 * Load HKLM, attempt to get the registry location from the config
2008 * file first, if exist, load and keep going.
2010 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
2011 strcpy(fn,home);
2012 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2013 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2014 free(fn);
2018 * Load HKCU, get the registry location from the config
2019 * file, if exist, load and keep going.
2021 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
2023 fn = xmalloc( MAX_PATHNAME_LEN );
2024 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
2025 fn, MAX_PATHNAME_LEN - 1))
2027 _wine_loadreg(HKCU,fn,REG_OPTION_TAINTED);
2029 free (fn);
2031 * Load HKU, get the registry location from the config
2032 * file, if exist, load and keep going.
2034 fn = xmalloc ( MAX_PATHNAME_LEN );
2035 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
2036 fn, MAX_PATHNAME_LEN - 1))
2038 _wine_loadreg(HKU,fn,REG_OPTION_TAINTED);
2040 free (fn);
2042 * Load HKLM, get the registry location from the config
2043 * file, if exist, load and keep going.
2045 fn = xmalloc ( MAX_PATHNAME_LEN );
2046 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
2047 fn, MAX_PATHNAME_LEN - 1))
2049 _wine_loadreg(HKLM,fn,REG_OPTION_TAINTED);
2051 free (fn);
2055 * Obtain the handle of the HKU\.Default key.
2056 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2058 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2059 lpkey = lookup_hkey(hkey);
2060 if(!lpkey){
2061 WARN_(reg)("Could not create global user default key\n");
2062 } else {
2063 _copy_registry(lpkey, HKCU );
2066 RegCloseKey(hkey);
2069 * Since HKU is built from the global HKU and the local user HKU file we must
2070 * flush the HKU tree we have built at this point otherwise the part brought
2071 * in from the global HKU is saved into the local HKU. To avoid this
2072 * useless dupplication of HKU keys we reread the local HKU key.
2075 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2076 _flush_registry(HKU);
2078 /* Reload user's local HKU hive */
2079 if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
2081 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2082 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2084 strcpy(fn,home);
2085 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2087 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2089 free(fn);
2093 * Make sure the update mode is there
2095 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2097 DWORD junk,type,len;
2098 char data[5];
2100 len=4;
2101 if (( RegQueryValueExA(
2102 hkey,
2103 VAL_SAVEUPDATED,
2104 &junk,
2105 &type,
2106 data,
2107 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2109 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2112 RegCloseKey(hkey);
2117 /********************* API FUNCTIONS ***************************************/
2119 * Open Keys.
2121 * All functions are stubs to RegOpenKeyEx32W where all the
2122 * magic happens.
2124 * Callpath:
2125 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2126 * RegOpenKey32W -> RegOpenKeyEx32W
2130 /******************************************************************************
2131 * RegOpenKeyEx32W [ADVAPI32.150]
2132 * Opens the specified key
2134 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2136 * PARAMS
2137 * hkey [I] Handle of open key
2138 * lpszSubKey [I] Name of subkey to open
2139 * dwReserved [I] Reserved - must be zero
2140 * samDesired [I] Security access mask
2141 * retkey [O] Address of handle of open key
2143 * RETURNS
2144 * Success: ERROR_SUCCESS
2145 * Failure: Error code
2147 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2148 REGSAM samDesired, LPHKEY retkey )
2150 LPKEYSTRUCT lpNextKey,lpxkey;
2151 LPWSTR *wps;
2152 int wpc,i;
2154 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2155 samDesired,retkey);
2157 lpNextKey = lookup_hkey( hkey );
2158 if (!lpNextKey)
2159 return ERROR_INVALID_HANDLE;
2161 if (!lpszSubKey || !*lpszSubKey) {
2162 /* Either NULL or pointer to empty string, so return a new handle
2163 to the original hkey */
2164 currenthandle += 2;
2165 add_handle(currenthandle,lpNextKey,samDesired);
2166 *retkey=currenthandle;
2167 return ERROR_SUCCESS;
2170 if (lpszSubKey[0] == '\\') {
2171 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2172 return ERROR_BAD_PATHNAME;
2175 split_keypath(lpszSubKey,&wps,&wpc);
2176 i = 0;
2177 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2178 lpxkey = lpNextKey;
2180 while (wps[i]) {
2181 lpxkey=lpNextKey->nextsub;
2182 while (lpxkey) {
2183 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2184 break;
2186 lpxkey=lpxkey->next;
2189 if (!lpxkey) {
2190 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2191 FREE_KEY_PATH;
2192 return ERROR_FILE_NOT_FOUND;
2194 i++;
2195 lpNextKey = lpxkey;
2198 currenthandle += 2;
2199 add_handle(currenthandle,lpxkey,samDesired);
2200 *retkey = currenthandle;
2201 TRACE_(reg)(" Returning %x\n", currenthandle);
2202 FREE_KEY_PATH;
2203 return ERROR_SUCCESS;
2207 /******************************************************************************
2208 * RegOpenKeyEx32A [ADVAPI32.149]
2210 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2211 REGSAM samDesired, LPHKEY retkey )
2213 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2214 DWORD ret;
2216 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2217 samDesired,retkey);
2218 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2219 free(lpszSubKeyW);
2220 return ret;
2224 /******************************************************************************
2225 * RegOpenKey32W [ADVAPI32.151]
2227 * PARAMS
2228 * hkey [I] Handle of open key
2229 * lpszSubKey [I] Address of name of subkey to open
2230 * retkey [O] Address of handle of open key
2232 * RETURNS
2233 * Success: ERROR_SUCCESS
2234 * Failure: Error code
2236 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2238 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2239 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2243 /******************************************************************************
2244 * RegOpenKey32A [ADVAPI32.148]
2246 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2248 DWORD ret;
2249 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2250 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2251 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2252 free(lpszSubKeyW);
2253 return ret;
2257 /******************************************************************************
2258 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2260 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2262 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2263 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2268 * Create keys
2270 * All those functions convert their respective
2271 * arguments and call RegCreateKeyExW at the end.
2273 * We stay away from the Ex functions as long as possible because there are
2274 * differences in the return values
2276 * Callpath:
2277 * RegCreateKeyEx32A \
2278 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2282 /******************************************************************************
2283 * RegCreateKeyEx32W [ADVAPI32.131]
2285 * PARAMS
2286 * hkey [I] Handle of an open key
2287 * lpszSubKey [I] Address of subkey name
2288 * dwReserved [I] Reserved - must be 0
2289 * lpszClass [I] Address of class string
2290 * fdwOptions [I] Special options flag
2291 * samDesired [I] Desired security access
2292 * lpSecAttribs [I] Address of key security structure
2293 * retkey [O] Address of buffer for opened handle
2294 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2296 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2297 DWORD dwReserved, LPWSTR lpszClass,
2298 DWORD fdwOptions, REGSAM samDesired,
2299 LPSECURITY_ATTRIBUTES lpSecAttribs,
2300 LPHKEY retkey, LPDWORD lpDispos )
2302 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2303 LPWSTR *wps;
2304 int wpc,i;
2306 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2307 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2308 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2310 lpNextKey = lookup_hkey(hkey);
2311 if (!lpNextKey)
2312 return ERROR_INVALID_HANDLE;
2314 /* Check for valid options */
2315 switch(fdwOptions) {
2316 case REG_OPTION_NON_VOLATILE:
2317 case REG_OPTION_VOLATILE:
2318 case REG_OPTION_BACKUP_RESTORE:
2319 break;
2320 default:
2321 return ERROR_INVALID_PARAMETER;
2324 /* Sam has to be a combination of the following */
2325 if (!(samDesired &
2326 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2327 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2328 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2329 return ERROR_INVALID_PARAMETER;
2331 if (!lpszSubKey || !*lpszSubKey) {
2332 currenthandle += 2;
2333 add_handle(currenthandle,lpNextKey,samDesired);
2334 *retkey=currenthandle;
2335 TRACE_(reg)("Returning %x\n", currenthandle);
2336 lpNextKey->flags|=REG_OPTION_TAINTED;
2337 return ERROR_SUCCESS;
2340 if (lpszSubKey[0] == '\\') {
2341 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2342 return ERROR_BAD_PATHNAME;
2345 split_keypath(lpszSubKey,&wps,&wpc);
2346 i = 0;
2347 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2348 lpxkey = lpNextKey;
2349 while (wps[i]) {
2350 lpxkey=lpNextKey->nextsub;
2351 while (lpxkey) {
2352 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2353 break;
2354 lpxkey=lpxkey->next;
2356 if (!lpxkey)
2357 break;
2358 i++;
2359 lpNextKey = lpxkey;
2361 if (lpxkey) {
2362 currenthandle += 2;
2363 add_handle(currenthandle,lpxkey,samDesired);
2364 lpxkey->flags |= REG_OPTION_TAINTED;
2365 *retkey = currenthandle;
2366 TRACE_(reg)("Returning %x\n", currenthandle);
2367 if (lpDispos)
2368 *lpDispos = REG_OPENED_EXISTING_KEY;
2369 FREE_KEY_PATH;
2370 return ERROR_SUCCESS;
2373 /* Good. Now the hard part */
2374 while (wps[i]) {
2375 lplpPrevKey = &(lpNextKey->nextsub);
2376 lpxkey = *lplpPrevKey;
2377 while (lpxkey) {
2378 lplpPrevKey = &(lpxkey->next);
2379 lpxkey = *lplpPrevKey;
2381 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2382 if (!*lplpPrevKey) {
2383 FREE_KEY_PATH;
2384 TRACE_(reg)("Returning OUTOFMEMORY\n");
2385 return ERROR_OUTOFMEMORY;
2387 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2388 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2389 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2390 (*lplpPrevKey)->next = NULL;
2391 (*lplpPrevKey)->nextsub = NULL;
2392 (*lplpPrevKey)->values = NULL;
2393 (*lplpPrevKey)->nrofvalues = 0;
2394 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2395 if (lpszClass)
2396 (*lplpPrevKey)->class = strdupW(lpszClass);
2397 else
2398 (*lplpPrevKey)->class = NULL;
2399 lpNextKey = *lplpPrevKey;
2400 i++;
2402 currenthandle += 2;
2403 add_handle(currenthandle,lpNextKey,samDesired);
2405 /*FIXME: flag handling correct? */
2406 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2407 if (lpszClass)
2408 lpNextKey->class = strdupW(lpszClass);
2409 else
2410 lpNextKey->class = NULL;
2411 *retkey = currenthandle;
2412 TRACE_(reg)("Returning %x\n", currenthandle);
2413 if (lpDispos)
2414 *lpDispos = REG_CREATED_NEW_KEY;
2415 FREE_KEY_PATH;
2416 return ERROR_SUCCESS;
2420 /******************************************************************************
2421 * RegCreateKeyEx32A [ADVAPI32.130]
2423 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2424 LPSTR lpszClass, DWORD fdwOptions,
2425 REGSAM samDesired,
2426 LPSECURITY_ATTRIBUTES lpSecAttribs,
2427 LPHKEY retkey, LPDWORD lpDispos )
2429 LPWSTR lpszSubKeyW, lpszClassW;
2430 DWORD ret;
2432 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2433 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2434 retkey,lpDispos);
2436 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2437 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2439 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2440 fdwOptions, samDesired, lpSecAttribs, retkey,
2441 lpDispos );
2443 if(lpszSubKeyW) free(lpszSubKeyW);
2444 if(lpszClassW) free(lpszClassW);
2446 return ret;
2450 /******************************************************************************
2451 * RegCreateKey32W [ADVAPI32.132]
2453 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2455 DWORD junk;
2456 LPKEYSTRUCT lpNextKey;
2458 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2460 /* This check is here because the return value is different than the
2461 one from the Ex functions */
2462 lpNextKey = lookup_hkey(hkey);
2463 if (!lpNextKey)
2464 return ERROR_BADKEY;
2466 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2467 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2468 retkey, &junk);
2472 /******************************************************************************
2473 * RegCreateKey32A [ADVAPI32.129]
2475 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2477 DWORD ret;
2478 LPWSTR lpszSubKeyW;
2480 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2481 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2482 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2483 if(lpszSubKeyW) free(lpszSubKeyW);
2484 return ret;
2488 /******************************************************************************
2489 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2491 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2493 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2494 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2499 * Query Value Functions
2500 * Win32 differs between keynames and valuenames.
2501 * multiple values may belong to one key, the special value
2502 * with name NULL is the default value used by the win31
2503 * compat functions.
2505 * Callpath:
2506 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2507 * RegQueryValue32W -> RegQueryValueEx32W
2511 /******************************************************************************
2512 * RegQueryValueEx32W [ADVAPI32.158]
2513 * Retrieves type and data for a specified name associated with an open key
2515 * PARAMS
2516 * hkey [I] Handle of key to query
2517 * lpValueName [I] Name of value to query
2518 * lpdwReserved [I] Reserved - must be NULL
2519 * lpdwType [O] Address of buffer for value type. If NULL, the type
2520 * is not required.
2521 * lpbData [O] Address of data buffer. If NULL, the actual data is
2522 * not required.
2523 * lpcbData [I/O] Address of data buffer size
2525 * RETURNS
2526 * ERROR_SUCCESS: Success
2527 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2528 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2530 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2531 LPDWORD lpdwReserved, LPDWORD lpdwType,
2532 LPBYTE lpbData, LPDWORD lpcbData )
2534 LPKEYSTRUCT lpkey;
2535 int i;
2536 DWORD ret;
2538 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2539 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2541 lpkey = lookup_hkey(hkey);
2543 if (!lpkey)
2544 return ERROR_INVALID_HANDLE;
2546 if ((lpbData && ! lpcbData) || lpdwReserved)
2547 return ERROR_INVALID_PARAMETER;
2549 /* An empty name string is equivalent to NULL */
2550 if (lpValueName && !*lpValueName)
2551 lpValueName = NULL;
2553 if (lpValueName==NULL)
2554 { /* Use key's unnamed or default value, if any */
2555 for (i=0;i<lpkey->nrofvalues;i++)
2556 if (lpkey->values[i].name==NULL)
2557 break;
2559 else
2560 { /* Search for the key name */
2561 for (i=0;i<lpkey->nrofvalues;i++)
2562 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2563 break;
2566 if (i==lpkey->nrofvalues)
2567 { TRACE_(reg)(" Key not found\n");
2568 if (lpValueName==NULL)
2569 { /* Empty keyname not found */
2570 if (lpbData)
2571 { *(WCHAR*)lpbData = 0;
2572 *lpcbData = 2;
2574 if (lpdwType)
2575 *lpdwType = REG_SZ;
2576 TRACE_(reg)(" Returning an empty string\n");
2577 return ERROR_SUCCESS;
2579 return ERROR_FILE_NOT_FOUND;
2582 ret = ERROR_SUCCESS;
2584 if (lpdwType) /* type required ?*/
2585 *lpdwType = lpkey->values[i].type;
2587 if (lpbData) /* data required ?*/
2588 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2589 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2590 else {
2591 *lpcbData = lpkey->values[i].len;
2592 ret = ERROR_MORE_DATA;
2596 if (lpcbData) /* size required ?*/
2597 { *lpcbData = lpkey->values[i].len;
2600 debug_print_value ( lpbData, &lpkey->values[i]);
2602 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2604 return ret;
2608 /******************************************************************************
2609 * RegQueryValue32W [ADVAPI32.159]
2611 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2612 LPLONG lpcbData )
2614 HKEY xhkey;
2615 DWORD ret,lpdwType;
2617 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2618 lpcbData?*lpcbData:0);
2620 /* Only open subkey, if we really do descend */
2621 if (lpszSubKey && *lpszSubKey) {
2622 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2623 if (ret != ERROR_SUCCESS) {
2624 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2625 return ret;
2627 } else
2628 xhkey = hkey;
2630 lpdwType = REG_SZ;
2631 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2632 lpcbData );
2633 if (xhkey != hkey)
2634 RegCloseKey(xhkey);
2635 return ret;
2639 /******************************************************************************
2640 * RegQueryValueEx32A [ADVAPI32.157]
2642 * NOTES:
2643 * the documantation is wrong: if the buffer is to small it remains untouched
2645 * FIXME: check returnvalue (len) for an empty key
2647 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2648 LPDWORD lpdwReserved, LPDWORD lpdwType,
2649 LPBYTE lpbData, LPDWORD lpcbData )
2651 LPWSTR lpszValueNameW;
2652 LPBYTE mybuf = NULL;
2653 DWORD ret, mytype, mylen = 0;
2655 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2656 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2658 if (!lpcbData && lpbData) /* buffer without size is illegal */
2659 { return ERROR_INVALID_PARAMETER;
2662 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2664 /* get just the type first */
2665 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2667 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2668 { if(lpszValueNameW) free(lpszValueNameW);
2669 return ret;
2672 if (lpcbData) /* at least length requested? */
2673 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2674 { if (lpbData ) /* value requested? */
2675 { mylen = 2*( *lpcbData );
2676 mybuf = (LPBYTE)xmalloc( mylen );
2679 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2681 if (ret == ERROR_SUCCESS )
2682 { if ( lpbData )
2683 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2687 *lpcbData = mylen/2; /* size is in byte! */
2689 else /* no strings, call it straight */
2690 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2694 if (lpdwType) /* type when requested */
2695 { *lpdwType = mytype;
2698 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2700 if(mybuf) free(mybuf);
2701 if(lpszValueNameW) free(lpszValueNameW);
2702 return ret;
2706 /******************************************************************************
2707 * RegQueryValueEx16 [KERNEL.225]
2709 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2710 LPDWORD lpdwReserved, LPDWORD lpdwType,
2711 LPBYTE lpbData, LPDWORD lpcbData )
2713 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2714 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2715 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2716 lpbData, lpcbData );
2720 /******************************************************************************
2721 * RegQueryValue32A [ADVAPI32.156]
2723 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2724 LPLONG lpcbData )
2726 HKEY xhkey;
2727 DWORD ret, dwType;
2729 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2730 lpcbData?*lpcbData:0);
2732 if (lpszSubKey && *lpszSubKey) {
2733 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2734 if( ret != ERROR_SUCCESS )
2735 return ret;
2736 } else
2737 xhkey = hkey;
2739 dwType = REG_SZ;
2740 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2741 lpcbData );
2742 if( xhkey != hkey )
2743 RegCloseKey( xhkey );
2744 return ret;
2748 /******************************************************************************
2749 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2751 * NOTES
2752 * Is this HACK still applicable?
2754 * HACK
2755 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2756 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2757 * Aldus FH4)
2759 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2760 LPDWORD lpcbData )
2762 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2763 lpcbData?*lpcbData:0);
2765 if (lpcbData)
2766 *lpcbData &= 0xFFFF;
2767 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2772 * Setting values of Registry keys
2774 * Callpath:
2775 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2776 * RegSetValue32W -> RegSetValueEx32W
2780 /******************************************************************************
2781 * RegSetValueEx32W [ADVAPI32.170]
2782 * Sets the data and type of a value under a register key
2784 * PARAMS
2785 * hkey [I] Handle of key to set value for
2786 * lpszValueName [I] Name of value to set
2787 * dwReserved [I] Reserved - must be zero
2788 * dwType [I] Flag for value type
2789 * lpbData [I] Address of value data
2790 * cbData [I] Size of value data
2792 * RETURNS
2793 * Success: ERROR_SUCCESS
2794 * Failure: Error code
2796 * NOTES
2797 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2799 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2800 DWORD dwReserved, DWORD dwType,
2801 CONST BYTE *lpbData, DWORD cbData)
2803 LPKEYSTRUCT lpkey;
2804 int i;
2806 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2807 dwReserved, dwType, lpbData, cbData);
2809 lpkey = lookup_hkey( hkey );
2811 if (!lpkey)
2812 return ERROR_INVALID_HANDLE;
2814 lpkey->flags |= REG_OPTION_TAINTED;
2816 if (lpszValueName==NULL) {
2817 /* Sets type and name for key's unnamed or default value */
2818 for (i=0;i<lpkey->nrofvalues;i++)
2819 if (lpkey->values[i].name==NULL)
2820 break;
2821 } else {
2822 for (i=0;i<lpkey->nrofvalues;i++)
2823 if ( lpkey->values[i].name &&
2824 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2826 break;
2828 if (i==lpkey->nrofvalues) {
2829 lpkey->values = (LPKEYVALUE)xrealloc(
2830 lpkey->values,
2831 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2833 lpkey->nrofvalues++;
2834 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2836 if (lpkey->values[i].name==NULL) {
2837 if (lpszValueName)
2838 lpkey->values[i].name = strdupW(lpszValueName);
2839 else
2840 lpkey->values[i].name = NULL;
2843 if (dwType == REG_SZ)
2844 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2846 lpkey->values[i].len = cbData;
2847 lpkey->values[i].type = dwType;
2848 if (lpkey->values[i].data !=NULL)
2849 free(lpkey->values[i].data);
2850 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2851 lpkey->values[i].lastmodified = time(NULL);
2852 memcpy(lpkey->values[i].data,lpbData,cbData);
2853 return ERROR_SUCCESS;
2857 /******************************************************************************
2858 * RegSetValueEx32A [ADVAPI32.169]
2860 * NOTES
2861 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2863 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2864 DWORD dwReserved, DWORD dwType,
2865 CONST BYTE *lpbData, DWORD cbData )
2867 LPBYTE buf;
2868 LPWSTR lpszValueNameW;
2869 DWORD ret;
2871 if (!lpbData)
2872 return (ERROR_INVALID_PARAMETER);
2874 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2875 dwReserved,dwType,lpbData,cbData);
2877 if ((1<<dwType) & UNICONVMASK)
2878 { if (dwType == REG_SZ)
2879 cbData = strlen ((LPCSTR)lpbData)+1;
2881 buf = (LPBYTE)xmalloc( cbData *2 );
2882 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2883 cbData=2*cbData;
2885 else
2886 buf=(LPBYTE)lpbData;
2888 if (lpszValueName)
2889 lpszValueNameW = strdupA2W(lpszValueName);
2890 else
2891 lpszValueNameW = NULL;
2893 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2895 if (lpszValueNameW)
2896 free(lpszValueNameW);
2898 if (buf!=lpbData)
2899 free(buf);
2901 return ret;
2905 /******************************************************************************
2906 * RegSetValueEx16 [KERNEL.226]
2908 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2909 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2911 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2912 dwReserved,dwType,lpbData,cbData);
2913 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2914 cbData );
2918 /******************************************************************************
2919 * RegSetValue32W [ADVAPI32.171]
2921 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2922 LPCWSTR lpszData, DWORD cbData )
2924 HKEY xhkey;
2925 DWORD ret;
2927 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2928 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2930 if (lpszSubKey && *lpszSubKey) {
2931 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2932 if (ret!=ERROR_SUCCESS)
2933 return ret;
2934 } else
2935 xhkey=hkey;
2936 if (dwType!=REG_SZ) {
2937 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2938 dwType=REG_SZ;
2940 if (cbData!=2*lstrlenW(lpszData)+2) {
2941 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2942 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2944 cbData=2*lstrlenW(lpszData)+2;
2946 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2947 if (hkey!=xhkey)
2948 RegCloseKey(xhkey);
2949 return ret;
2953 /******************************************************************************
2954 * RegSetValue32A [ADVAPI32.168]
2957 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2958 LPCSTR lpszData, DWORD cbData )
2960 DWORD ret;
2961 HKEY xhkey;
2963 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2964 if (lpszSubKey && *lpszSubKey) {
2965 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2966 if (ret!=ERROR_SUCCESS)
2967 return ret;
2968 } else
2969 xhkey=hkey;
2971 if (dwType!=REG_SZ) {
2972 TRACE_(reg)("dwType=%ld!\n",dwType);
2973 dwType=REG_SZ;
2975 if (cbData!=strlen(lpszData)+1)
2976 cbData=strlen(lpszData)+1;
2977 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2978 if (xhkey!=hkey)
2979 RegCloseKey(xhkey);
2980 return ret;
2984 /******************************************************************************
2985 * RegSetValue16 [KERNEL.221] [SHELL.5]
2987 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2988 LPCSTR lpszData, DWORD cbData )
2990 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2991 debugstr_a(lpszData),cbData);
2992 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2997 * Key Enumeration
2999 * Callpath:
3000 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
3001 * RegEnumKey32W -> RegEnumKeyEx32W
3005 /******************************************************************************
3006 * RegEnumKeyEx32W [ADVAPI32.139]
3008 * PARAMS
3009 * hkey [I] Handle to key to enumerate
3010 * iSubKey [I] Index of subkey to enumerate
3011 * lpszName [O] Buffer for subkey name
3012 * lpcchName [O] Size of subkey buffer
3013 * lpdwReserved [I] Reserved
3014 * lpszClass [O] Buffer for class string
3015 * lpcchClass [O] Size of class buffer
3016 * ft [O] Time key last written to
3018 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3019 LPDWORD lpcchName, LPDWORD lpdwReserved,
3020 LPWSTR lpszClass, LPDWORD lpcchClass,
3021 FILETIME *ft )
3023 LPKEYSTRUCT lpkey,lpxkey;
3025 TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3026 lpcchName,lpcchName? *lpcchName : -1,lpdwReserved,lpszClass,
3027 lpcchClass,ft);
3029 lpkey = lookup_hkey( hkey );
3030 if (!lpkey)
3031 return ERROR_INVALID_HANDLE;
3033 if (!lpcchName)
3034 return ERROR_INVALID_PARAMETER;
3036 if (!lpkey->nextsub)
3037 return ERROR_NO_MORE_ITEMS;
3038 lpxkey=lpkey->nextsub;
3040 /* Traverse the subkeys */
3041 while (iSubkey && lpxkey) {
3042 iSubkey--;
3043 lpxkey=lpxkey->next;
3046 if (iSubkey || !lpxkey)
3047 return ERROR_NO_MORE_ITEMS;
3048 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3049 *lpcchName = lstrlenW(lpxkey->keyname);
3050 return ERROR_MORE_DATA;
3052 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3053 *lpcchName = lstrlenW(lpszName);
3055 if (lpszClass) {
3056 /* FIXME: what should we write into it? */
3057 *lpszClass = 0;
3058 *lpcchClass = 2;
3060 return ERROR_SUCCESS;
3064 /******************************************************************************
3065 * RegEnumKeyW [ADVAPI32.140]
3067 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3068 DWORD lpcchName )
3070 DWORD ret;
3071 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3072 ret = RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,NULL);
3074 /* If lpszName is NULL then we have a slightly different behaviour than
3075 RegEnumKeyExW */
3076 if(lpszName == NULL && ret == ERROR_MORE_DATA)
3077 ret = ERROR_SUCCESS;
3079 return ret;
3083 /******************************************************************************
3084 * RegEnumKeyEx32A [ADVAPI32.138]
3086 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3087 LPDWORD lpcchName, LPDWORD lpdwReserved,
3088 LPSTR lpszClass, LPDWORD lpcchClass,
3089 FILETIME *ft )
3091 DWORD ret;
3092 LPWSTR lpszNameW, lpszClassW;
3094 TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",
3095 hkey,iSubkey,lpszName,lpcchName,lpcchName? *lpcchName : -1,
3096 lpdwReserved,lpszClass,lpcchClass,ft);
3098 lpszNameW = lpszName ? (LPWSTR)xmalloc(*lpcchName * 2) : NULL;
3099 lpszClassW = lpszClass ? (LPWSTR)xmalloc(*lpcchClass * 2) : NULL;
3101 ret = RegEnumKeyExW(hkey, iSubkey, lpszNameW, lpcchName, lpdwReserved,
3102 lpszClassW, lpcchClass, ft);
3104 if (ret == ERROR_SUCCESS) {
3105 lstrcpyWtoA(lpszName,lpszNameW);
3106 if (lpszClassW)
3107 lstrcpyWtoA(lpszClass,lpszClassW);
3109 if (lpszNameW)
3110 free(lpszNameW);
3111 if (lpszClassW)
3112 free(lpszClassW);
3113 return ret;
3117 /******************************************************************************
3118 * RegEnumKeyA [ADVAPI32.137]
3120 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3121 DWORD lpcchName )
3123 DWORD ret;
3124 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3125 ret = RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3126 NULL, NULL );
3128 /* If lpszName is NULL then we have a slightly different behaviour than
3129 RegEnumKeyExA */
3130 if(lpszName == NULL && ret == ERROR_MORE_DATA)
3131 ret = ERROR_SUCCESS;
3133 return ret;
3137 /******************************************************************************
3138 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3140 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3141 DWORD lpcchName )
3143 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3144 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3149 * Enumerate Registry Values
3151 * Callpath:
3152 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3156 /******************************************************************************
3157 * RegEnumValue32W [ADVAPI32.142]
3159 * PARAMS
3160 * hkey [I] Handle to key to query
3161 * iValue [I] Index of value to query
3162 * lpszValue [O] Value string
3163 * lpcchValue [I/O] Size of value buffer (in wchars)
3164 * lpdReserved [I] Reserved
3165 * lpdwType [O] Type code
3166 * lpbData [O] Value data
3167 * lpcbData [I/O] Size of data buffer (in bytes)
3169 * Note: wide character functions that take and/or return "character counts"
3170 * use TCHAR (that is unsigned short or char) not byte counts.
3172 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3173 LPDWORD lpcchValue, LPDWORD lpdReserved,
3174 LPDWORD lpdwType, LPBYTE lpbData,
3175 LPDWORD lpcbData )
3177 LPKEYSTRUCT lpkey;
3178 LPKEYVALUE val;
3180 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3181 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3183 lpkey = lookup_hkey( hkey );
3185 if (!lpcbData && lpbData)
3186 return ERROR_INVALID_PARAMETER;
3188 if (!lpkey)
3189 return ERROR_INVALID_HANDLE;
3191 if (lpkey->nrofvalues <= iValue)
3192 return ERROR_NO_MORE_ITEMS;
3194 val = &(lpkey->values[iValue]);
3196 if (val->name) {
3197 if (lstrlenW(val->name)+1>*lpcchValue) {
3198 *lpcchValue = lstrlenW(val->name)+1;
3199 return ERROR_MORE_DATA;
3201 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3202 *lpcchValue=lstrlenW(val->name);
3203 } else {
3204 *lpszValue = 0;
3205 *lpcchValue = 0;
3208 /* Can be NULL if the type code is not required */
3209 if (lpdwType)
3210 *lpdwType = val->type;
3212 if (lpbData) {
3213 if (val->len>*lpcbData) {
3214 *lpcbData = val->len;
3215 return ERROR_MORE_DATA;
3217 memcpy(lpbData,val->data,val->len);
3218 *lpcbData = val->len;
3221 debug_print_value ( val->data, val );
3222 return ERROR_SUCCESS;
3226 /******************************************************************************
3227 * RegEnumValue32A [ADVAPI32.141]
3229 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3230 LPDWORD lpcchValue, LPDWORD lpdReserved,
3231 LPDWORD lpdwType, LPBYTE lpbData,
3232 LPDWORD lpcbData )
3234 LPWSTR lpszValueW;
3235 LPBYTE lpbDataW;
3236 DWORD ret,lpcbDataW;
3237 DWORD dwType;
3239 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3240 lpdReserved,lpdwType,lpbData,lpcbData);
3242 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3243 if (lpbData) {
3244 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3245 lpcbDataW = *lpcbData;
3246 } else
3247 lpbDataW = NULL;
3249 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3250 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3252 if (lpdwType)
3253 *lpdwType = dwType;
3255 if (ret==ERROR_SUCCESS) {
3256 lstrcpyWtoA(lpszValue,lpszValueW);
3257 if (lpbData) {
3258 if ((1<<dwType) & UNICONVMASK) {
3259 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3260 } else {
3261 if (lpcbDataW > *lpcbData) {
3262 *lpcbData = lpcbDataW;
3263 ret = ERROR_MORE_DATA;
3264 } else
3265 memcpy(lpbData,lpbDataW,lpcbDataW);
3267 *lpcbData = lpcbDataW;
3270 if (lpbDataW) free(lpbDataW);
3271 if (lpszValueW) free(lpszValueW);
3272 return ret;
3276 /******************************************************************************
3277 * RegEnumValue16 [KERNEL.223]
3279 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3280 LPDWORD lpcchValue, LPDWORD lpdReserved,
3281 LPDWORD lpdwType, LPBYTE lpbData,
3282 LPDWORD lpcbData )
3284 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3285 lpdReserved,lpdwType,lpbData,lpcbData);
3286 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3287 lpdwType, lpbData, lpcbData );
3291 /******************************************************************************
3292 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3293 * Releases the handle of the specified key
3295 * PARAMS
3296 * hkey [I] Handle of key to close
3298 * RETURNS
3299 * Success: ERROR_SUCCESS
3300 * Failure: Error code
3302 DWORD WINAPI RegCloseKey( HKEY hkey )
3304 TRACE_(reg)("(%x)\n",hkey);
3306 /* The standard handles are allowed to succeed, even though they are not
3307 closed */
3308 if (is_standard_hkey(hkey))
3309 return ERROR_SUCCESS;
3311 return remove_handle(hkey);
3316 * Delete registry key
3318 * Callpath:
3319 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3323 /******************************************************************************
3324 * RegDeleteKey32W [ADVAPI32.134]
3326 * PARAMS
3327 * hkey [I] Handle to open key
3328 * lpszSubKey [I] Name of subkey to delete
3330 * RETURNS
3331 * Success: ERROR_SUCCESS
3332 * Failure: Error code
3334 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3336 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3337 LPWSTR *wps;
3338 int wpc,i;
3340 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3342 lpNextKey = lookup_hkey(hkey);
3343 if (!lpNextKey)
3344 return ERROR_INVALID_HANDLE;
3346 /* Subkey param cannot be NULL */
3347 if (!lpszSubKey || !*lpszSubKey)
3348 return ERROR_BADKEY;
3350 /* We need to know the previous key in the hier. */
3351 split_keypath(lpszSubKey,&wps,&wpc);
3352 i = 0;
3353 lpxkey = lpNextKey;
3354 while (i<wpc-1) {
3355 lpxkey=lpNextKey->nextsub;
3356 while (lpxkey) {
3357 TRACE_(reg)(" Scanning [%s]\n",
3358 debugstr_w(lpxkey->keyname));
3359 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3360 break;
3361 lpxkey=lpxkey->next;
3363 if (!lpxkey) {
3364 FREE_KEY_PATH;
3365 TRACE_(reg)(" Not found.\n");
3366 /* not found is success */
3367 return ERROR_SUCCESS;
3369 i++;
3370 lpNextKey = lpxkey;
3372 lpxkey = lpNextKey->nextsub;
3373 lplpPrevKey = &(lpNextKey->nextsub);
3374 while (lpxkey) {
3375 TRACE_(reg)(" Scanning [%s]\n",
3376 debugstr_w(lpxkey->keyname));
3377 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3378 break;
3379 lplpPrevKey = &(lpxkey->next);
3380 lpxkey = lpxkey->next;
3383 if (!lpxkey) {
3384 FREE_KEY_PATH;
3385 WARN_(reg)(" Not found.\n");
3386 return ERROR_FILE_NOT_FOUND;
3389 if (lpxkey->nextsub) {
3390 FREE_KEY_PATH;
3391 WARN_(reg)(" Not empty.\n");
3392 return ERROR_CANTWRITE;
3394 *lplpPrevKey = lpxkey->next;
3395 free(lpxkey->keyname);
3396 if (lpxkey->class)
3397 free(lpxkey->class);
3398 if (lpxkey->values)
3399 free(lpxkey->values);
3400 free(lpxkey);
3401 FREE_KEY_PATH;
3402 TRACE_(reg)(" Done.\n");
3403 return ERROR_SUCCESS;
3407 /******************************************************************************
3408 * RegDeleteKey32A [ADVAPI32.133]
3410 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3412 LPWSTR lpszSubKeyW;
3413 DWORD ret;
3415 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3416 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3417 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3418 if(lpszSubKeyW) free(lpszSubKeyW);
3419 return ret;
3423 /******************************************************************************
3424 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3426 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3428 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3429 return RegDeleteKeyA( hkey, lpszSubKey );
3434 * Delete registry value
3436 * Callpath:
3437 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3441 /******************************************************************************
3442 * RegDeleteValue32W [ADVAPI32.136]
3444 * PARAMS
3445 * hkey [I]
3446 * lpszValue [I]
3448 * RETURNS
3450 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3452 DWORD i;
3453 LPKEYSTRUCT lpkey;
3454 LPKEYVALUE val;
3456 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3458 lpkey = lookup_hkey( hkey );
3459 if (!lpkey)
3460 return ERROR_INVALID_HANDLE;
3462 if (lpszValue) {
3463 for (i=0;i<lpkey->nrofvalues;i++)
3464 if ( lpkey->values[i].name &&
3465 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3467 break;
3468 } else {
3469 for (i=0;i<lpkey->nrofvalues;i++)
3470 if (lpkey->values[i].name==NULL)
3471 break;
3474 if (i == lpkey->nrofvalues)
3475 return ERROR_FILE_NOT_FOUND;
3477 val = lpkey->values+i;
3478 if (val->name) free(val->name);
3479 if (val->data) free(val->data);
3480 memcpy(
3481 lpkey->values+i,
3482 lpkey->values+i+1,
3483 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3485 lpkey->values = (LPKEYVALUE)xrealloc(
3486 lpkey->values,
3487 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3489 lpkey->nrofvalues--;
3490 return ERROR_SUCCESS;
3494 /******************************************************************************
3495 * RegDeleteValue32A [ADVAPI32.135]
3497 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3499 LPWSTR lpszValueW;
3500 DWORD ret;
3502 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3503 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3504 ret = RegDeleteValueW( hkey, lpszValueW );
3505 if(lpszValueW) free(lpszValueW);
3506 return ret;
3510 /******************************************************************************
3511 * RegDeleteValue16 [KERNEL.222]
3513 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3515 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3516 return RegDeleteValueA( hkey, lpszValue );
3520 /******************************************************************************
3521 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3522 * Immediately writes key to registry.
3523 * Only returns after data has been written to disk.
3525 * FIXME: does it really wait until data is written ?
3527 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3528 * written if this function really works (and only if !).
3530 * PARAMS
3531 * hkey [I] Handle of key to write
3533 * RETURNS
3534 * Success: ERROR_SUCCESS
3535 * Failure: Error code
3537 DWORD WINAPI RegFlushKey( HKEY hkey )
3539 LPKEYSTRUCT lpkey;
3541 TRACE_(reg)("(%x)\n", hkey);
3543 lpkey = lookup_hkey( hkey );
3544 if (!lpkey)
3545 return ERROR_BADKEY;
3547 SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3548 return ERROR_SUCCESS;
3552 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3555 /******************************************************************************
3556 * RegQueryInfoKey32W [ADVAPI32.153]
3558 * PARAMS
3559 * hkey [I] Handle to key to query
3560 * lpszClass [O] Buffer for class string
3561 * lpcchClass [O] Size of class string buffer
3562 * lpdwReserved [I] Reserved
3563 * lpcSubKeys [I] Buffer for number of subkeys
3564 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3565 * lpcchMaxClass [O] Buffer for longest class string length
3566 * lpcValues [O] Buffer for number of value entries
3567 * lpcchMaxValueName [O] Buffer for longest value name length
3568 * lpccbMaxValueData [O] Buffer for longest value data length
3569 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3570 * ft
3571 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3572 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3573 * lpcchClass is NULL
3574 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3575 * (it's hard to test validity, so test !NULL instead)
3577 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3578 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3579 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3580 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3581 LPDWORD lpcchMaxValueName,
3582 LPDWORD lpccbMaxValueData,
3583 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3585 LPKEYSTRUCT lpkey,lpxkey;
3586 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3587 int i;
3589 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3590 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3591 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3592 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3594 lpkey = lookup_hkey(hkey);
3595 if (!lpkey)
3596 return ERROR_INVALID_HANDLE;
3597 if (lpszClass) {
3598 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3599 return ERROR_INVALID_PARAMETER;
3601 /* either lpcchClass is valid or this is win95 and lpcchClass
3602 could be invalid */
3603 if (lpkey->class) {
3604 DWORD classLen = lstrlenW(lpkey->class);
3606 if (lpcchClass && classLen+1>*lpcchClass) {
3607 *lpcchClass=classLen+1;
3608 return ERROR_MORE_DATA;
3610 if (lpcchClass)
3611 *lpcchClass=classLen;
3612 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3613 } else {
3614 *lpszClass = 0;
3615 if (lpcchClass)
3616 *lpcchClass = 0;
3618 } else {
3619 if (lpcchClass)
3620 *lpcchClass = lstrlenW(lpkey->class);
3622 lpxkey=lpkey->nextsub;
3623 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3624 while (lpxkey) {
3625 nrofkeys++;
3626 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3627 maxsubkey=lstrlenW(lpxkey->keyname);
3628 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3629 maxclass=lstrlenW(lpxkey->class);
3630 lpxkey=lpxkey->next;
3632 for (i=0;i<lpkey->nrofvalues;i++) {
3633 LPKEYVALUE val=lpkey->values+i;
3635 if (val->name && lstrlenW(val->name)>maxvname)
3636 maxvname=lstrlenW(val->name);
3637 if (val->len>maxvdata)
3638 maxvdata=val->len;
3640 if (!maxclass) maxclass = 1;
3641 if (!maxvname) maxvname = 1;
3642 if (lpcValues)
3643 *lpcValues = lpkey->nrofvalues;
3644 if (lpcSubKeys)
3645 *lpcSubKeys = nrofkeys;
3646 if (lpcchMaxSubkey)
3647 *lpcchMaxSubkey = maxsubkey;
3648 if (lpcchMaxClass)
3649 *lpcchMaxClass = maxclass;
3650 if (lpcchMaxValueName)
3651 *lpcchMaxValueName= maxvname;
3652 if (lpccbMaxValueData)
3653 *lpccbMaxValueData= maxvdata;
3654 return ERROR_SUCCESS;
3658 /******************************************************************************
3659 * RegQueryInfoKey32A [ADVAPI32.152]
3661 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3662 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3663 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3664 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3665 LPDWORD lpccbMaxValueData,
3666 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3668 LPWSTR lpszClassW = NULL;
3669 DWORD ret;
3671 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3672 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3673 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3674 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3676 if (lpszClass) {
3677 if (lpcchClass) {
3678 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3679 } else if (VERSION_GetVersion() == WIN95) {
3680 /* win95 allows lpcchClass to be null */
3681 /* we don't know how big lpszClass is, would
3682 MAX_PATHNAME_LEN be the correct default? */
3683 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3686 } else
3687 lpszClassW = NULL;
3688 ret=RegQueryInfoKeyW(
3689 hkey,
3690 lpszClassW,
3691 lpcchClass,
3692 lpdwReserved,
3693 lpcSubKeys,
3694 lpcchMaxSubkey,
3695 lpcchMaxClass,
3696 lpcValues,
3697 lpcchMaxValueName,
3698 lpccbMaxValueData,
3699 lpcbSecurityDescriptor,
3702 if (ret==ERROR_SUCCESS && lpszClass)
3703 lstrcpyWtoA(lpszClass,lpszClassW);
3704 if (lpszClassW)
3705 free(lpszClassW);
3706 return ret;
3710 /******************************************************************************
3711 * RegConnectRegistry32W [ADVAPI32.128]
3713 * PARAMS
3714 * lpMachineName [I] Address of name of remote computer
3715 * hHey [I] Predefined registry handle
3716 * phkResult [I] Address of buffer for remote registry handle
3718 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3719 LPHKEY phkResult )
3721 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3723 if (!lpMachineName || !*lpMachineName) {
3724 /* Use the local machine name */
3725 return RegOpenKey16( hKey, "", phkResult );
3728 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3729 return ERROR_BAD_NETPATH;
3733 /******************************************************************************
3734 * RegConnectRegistry32A [ADVAPI32.127]
3736 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3738 DWORD ret;
3739 LPWSTR machineW = strdupA2W(machine);
3740 ret = RegConnectRegistryW( machineW, hkey, reskey );
3741 free(machineW);
3742 return ret;
3746 /******************************************************************************
3747 * RegGetKeySecurity [ADVAPI32.144]
3748 * Retrieves a copy of security descriptor protecting the registry key
3750 * PARAMS
3751 * hkey [I] Open handle of key to set
3752 * SecurityInformation [I] Descriptor contents
3753 * pSecurityDescriptor [O] Address of descriptor for key
3754 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3756 * RETURNS
3757 * Success: ERROR_SUCCESS
3758 * Failure: Error code
3760 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3761 SECURITY_INFORMATION SecurityInformation,
3762 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3763 LPDWORD lpcbSecurityDescriptor )
3765 LPKEYSTRUCT lpkey;
3767 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3768 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3770 lpkey = lookup_hkey( hkey );
3771 if (!lpkey)
3772 return ERROR_INVALID_HANDLE;
3774 /* FIXME: Check for valid SecurityInformation values */
3776 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3777 return ERROR_INSUFFICIENT_BUFFER;
3779 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3780 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3782 return ERROR_SUCCESS;
3786 /******************************************************************************
3787 * RegLoadKey32W [ADVAPI32.???]
3789 * PARAMS
3790 * hkey [I] Handle of open key
3791 * lpszSubKey [I] Address of name of subkey
3792 * lpszFile [I] Address of filename for registry information
3794 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3796 LPKEYSTRUCT lpkey;
3797 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3799 /* Do this check before the hkey check */
3800 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3801 return ERROR_INVALID_PARAMETER;
3803 lpkey = lookup_hkey( hkey );
3804 if (!lpkey)
3805 return ERROR_INVALID_HANDLE;
3807 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3808 debugstr_w(lpszFile));
3810 return ERROR_SUCCESS;
3814 /******************************************************************************
3815 * RegLoadKey32A [ADVAPI32.???]
3817 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3819 LONG ret;
3820 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3821 LPWSTR lpszFileW = strdupA2W(lpszFile);
3822 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3823 if(lpszFileW) free(lpszFileW);
3824 if(lpszSubKeyW) free(lpszSubKeyW);
3825 return ret;
3829 /******************************************************************************
3830 * RegNotifyChangeKeyValue [ADVAPI32.???]
3832 * PARAMS
3833 * hkey [I] Handle of key to watch
3834 * fWatchSubTree [I] Flag for subkey notification
3835 * fdwNotifyFilter [I] Changes to be reported
3836 * hEvent [I] Handle of signaled event
3837 * fAsync [I] Flag for asynchronous reporting
3839 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3840 DWORD fdwNotifyFilter, HANDLE hEvent,
3841 BOOL fAsync )
3843 LPKEYSTRUCT lpkey;
3844 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3845 hEvent,fAsync);
3847 lpkey = lookup_hkey( hkey );
3848 if (!lpkey)
3849 return ERROR_INVALID_HANDLE;
3851 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3852 hEvent,fAsync);
3854 return ERROR_SUCCESS;
3858 /******************************************************************************
3859 * RegUnLoadKey32W [ADVAPI32.173]
3861 * PARAMS
3862 * hkey [I] Handle of open key
3863 * lpSubKey [I] Address of name of subkey to unload
3865 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3867 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3868 return ERROR_SUCCESS;
3872 /******************************************************************************
3873 * RegUnLoadKey32A [ADVAPI32.172]
3875 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3877 LONG ret;
3878 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3879 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3880 if(lpSubKeyW) free(lpSubKeyW);
3881 return ret;
3885 /******************************************************************************
3886 * RegSetKeySecurity [ADVAPI32.167]
3888 * PARAMS
3889 * hkey [I] Open handle of key to set
3890 * SecurityInfo [I] Descriptor contents
3891 * pSecurityDesc [I] Address of descriptor for key
3893 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3894 PSECURITY_DESCRIPTOR pSecurityDesc )
3896 LPKEYSTRUCT lpkey;
3898 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3900 /* It seems to perform this check before the hkey check */
3901 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3902 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3903 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3904 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3905 /* Param OK */
3906 } else
3907 return ERROR_INVALID_PARAMETER;
3909 if (!pSecurityDesc)
3910 return ERROR_INVALID_PARAMETER;
3912 lpkey = lookup_hkey( hkey );
3913 if (!lpkey)
3914 return ERROR_INVALID_HANDLE;
3916 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3918 return ERROR_SUCCESS;
3922 /******************************************************************************
3923 * RegSaveKey32W [ADVAPI32.166]
3925 * PARAMS
3926 * hkey [I] Handle of key where save begins
3927 * lpFile [I] Address of filename to save to
3928 * sa [I] Address of security structure
3930 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3931 LPSECURITY_ATTRIBUTES sa )
3933 LPKEYSTRUCT lpkey;
3935 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3937 /* It appears to do this check before the hkey check */
3938 if (!lpFile || !*lpFile)
3939 return ERROR_INVALID_PARAMETER;
3941 lpkey = lookup_hkey( hkey );
3942 if (!lpkey)
3943 return ERROR_INVALID_HANDLE;
3945 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3947 return ERROR_SUCCESS;
3951 /******************************************************************************
3952 * RegSaveKey32A [ADVAPI32.165]
3954 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3955 LPSECURITY_ATTRIBUTES sa )
3957 LONG ret;
3958 LPWSTR lpFileW = strdupA2W(lpFile);
3959 ret = RegSaveKeyW( hkey, lpFileW, sa );
3960 free(lpFileW);
3961 return ret;
3965 /******************************************************************************
3966 * RegRestoreKey32W [ADVAPI32.164]
3968 * PARAMS
3969 * hkey [I] Handle of key where restore begins
3970 * lpFile [I] Address of filename containing saved tree
3971 * dwFlags [I] Optional flags
3973 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3975 LPKEYSTRUCT lpkey;
3977 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3979 /* It seems to do this check before the hkey check */
3980 if (!lpFile || !*lpFile)
3981 return ERROR_INVALID_PARAMETER;
3983 lpkey = lookup_hkey( hkey );
3984 if (!lpkey)
3985 return ERROR_INVALID_HANDLE;
3987 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3989 /* Check for file existence */
3991 return ERROR_SUCCESS;
3995 /******************************************************************************
3996 * RegRestoreKey32A [ADVAPI32.163]
3998 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4000 LONG ret;
4001 LPWSTR lpFileW = strdupA2W(lpFile);
4002 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4003 if(lpFileW) free(lpFileW);
4004 return ret;
4008 /******************************************************************************
4009 * RegReplaceKey32W [ADVAPI32.162]
4011 * PARAMS
4012 * hkey [I] Handle of open key
4013 * lpSubKey [I] Address of name of subkey
4014 * lpNewFile [I] Address of filename for file with new data
4015 * lpOldFile [I] Address of filename for backup file
4017 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4018 LPCWSTR lpOldFile )
4020 LPKEYSTRUCT lpkey;
4022 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4023 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4025 lpkey = lookup_hkey( hkey );
4026 if (!lpkey)
4027 return ERROR_INVALID_HANDLE;
4029 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
4030 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4032 return ERROR_SUCCESS;
4036 /******************************************************************************
4037 * RegReplaceKey32A [ADVAPI32.161]
4039 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4040 LPCSTR lpOldFile )
4042 LONG ret;
4043 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4044 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4045 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4046 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4047 free(lpOldFileW);
4048 free(lpNewFileW);
4049 free(lpSubKeyW);
4050 return ret;