Implementation of custom dialog messages and notifications.
[wine.git] / misc / registry.c
blob789f3b94061af102ce4aeca0102ebb0f03b5cb55
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;
623 if (!lpkey)
624 return 0;
625 if (lpkey->flags & REG_OPTION_TAINTED)
626 tainted = 1;
627 else
628 tainted = 0;
629 while (lpkey) {
630 if (_save_check_tainted(lpkey->nextsub)) {
631 lpkey->flags |= REG_OPTION_TAINTED;
632 tainted = 1;
634 lpkey = lpkey->next;
636 return tainted;
639 /******************************************************************************
640 * _save_USTRING [Internal]
642 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
644 LPWSTR s;
645 int doescape;
647 if (wstr==NULL)
648 return;
649 s=wstr;
650 while (*s) {
651 doescape=0;
652 if (*s>0x7f)
653 doescape = 1;
654 if (*s=='\n')
655 doescape = 1;
656 if (escapeeq && *s=='=')
657 doescape = 1;
658 if (*s=='\\')
659 fputc(*s,F); /* if \\ then put it twice. */
660 if (doescape)
661 fprintf(F,"\\u%04x",*((unsigned short*)s));
662 else
663 fputc(*s,F);
664 s++;
668 /******************************************************************************
669 * _savesubkey [Internal]
671 * NOTES
672 * REG_MULTI_SZ is handled as binary (like in win95) (js)
674 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
676 LPKEYSTRUCT lpxkey;
677 int i,tabs,j;
679 lpxkey = lpkey;
680 while (lpxkey) {
681 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
682 (all || (lpxkey->flags & REG_OPTION_TAINTED))
684 for (tabs=level;tabs--;)
685 fputc('\t',F);
686 _save_USTRING(F,lpxkey->keyname,1);
687 fputs("\n",F);
688 for (i=0;i<lpxkey->nrofvalues;i++) {
689 LPKEYVALUE val=lpxkey->values+i;
691 for (tabs=level+1;tabs--;)
692 fputc('\t',F);
693 _save_USTRING(F,val->name,0);
694 fputc('=',F);
695 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
696 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
697 _save_USTRING(F,(LPWSTR)val->data,0);
698 else
699 for (j=0;j<val->len;j++)
700 fprintf(F,"%02x",*((unsigned char*)val->data+j));
701 fputs("\n",F);
703 /* descend recursively */
704 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
705 return 0;
707 lpxkey=lpxkey->next;
709 return 1;
713 /******************************************************************************
714 * _savesubreg [Internal]
716 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
718 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
719 _save_check_tainted(lpkey->nextsub);
720 return _savesubkey(F,lpkey->nextsub,0,all);
724 /******************************************************************************
725 * _savereg [Internal]
727 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
729 FILE *F;
731 F=fopen(fn,"w");
732 if (F==NULL) {
733 WARN_(reg)("Couldn't open %s for writing: %s\n",
734 fn,strerror(errno)
736 return FALSE;
738 if (!_savesubreg(F,lpkey,all)) {
739 fclose(F);
740 unlink(fn);
741 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
742 return FALSE;
744 fclose(F);
745 return TRUE;
749 /******************************************************************************
750 * SHELL_SaveRegistryBranch [Internal]
752 * Saves main registry branch specified by hkey.
754 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
756 char *fn, *home, *tmp;
758 /* Find out what to save to, get from config file */
759 BOOL writeToHome = PROFILE_GetWineIniBool("registry","WritetoHomeRegistries",1);
760 BOOL writeToAlt = PROFILE_GetWineIniBool("registry","WritetoAltRegistries",1);
762 /* FIXME: does this check apply to all keys written below ? */
763 if (!(home = getenv( "HOME" )))
764 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
766 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
767 if (hkey == HKEY_CLASSES_ROOT) hkey = HKEY_LOCAL_MACHINE;
769 switch (hkey)
771 case HKEY_CURRENT_USER:
772 fn = xmalloc( MAX_PATHNAME_LEN );
773 if (writeToAlt && PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
774 fn, MAX_PATHNAME_LEN - 1))
775 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
776 free (fn);
778 if (home && writeToHome)
780 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
781 strlen(SAVE_CURRENT_USER) + 2 );
782 strcpy(fn,home);
783 strcat(fn,WINE_PREFIX);
785 /* create the directory. don't care about errorcodes. */
786 mkdir(fn,0755); /* drwxr-xr-x */
787 strcat(fn,"/"SAVE_CURRENT_USER);
789 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
790 strcpy(tmp,fn);
791 strcat(tmp,".tmp");
793 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
794 if (-1==rename(tmp,fn)) {
795 perror("rename tmp registry");
796 unlink(tmp);
799 free(tmp);
800 free(fn);
802 break;
803 case HKEY_LOCAL_MACHINE:
804 /* Try first saving according to the defined location in .winerc */
805 fn = xmalloc ( MAX_PATHNAME_LEN);
806 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltLocalMachineFile", "",
807 fn, MAX_PATHNAME_LEN - 1))
808 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
809 free (fn);
811 if (home && writeToHome)
813 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
814 strlen(SAVE_LOCAL_MACHINE) + 2);
815 strcpy(fn,home);
816 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
818 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
819 strcpy(tmp,fn);
820 strcat(tmp,".tmp");
822 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
823 if (-1==rename(tmp,fn)) {
824 perror("rename tmp registry");
825 unlink(tmp);
828 free(tmp);
829 free(fn);
831 break;
832 case HKEY_USERS:
833 fn = xmalloc( MAX_PATHNAME_LEN );
834 if (writeToAlt && PROFILE_GetWineIniString( "Registry", "AltUserFile", "",
835 fn, MAX_PATHNAME_LEN - 1))
836 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
837 free (fn);
839 if (home && writeToHome)
841 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
842 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
843 strcpy(fn,home);
844 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
846 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
847 strcpy(tmp,fn);
848 strcat(tmp,".tmp");
849 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
850 if (-1==rename(tmp,fn)) {
851 perror("rename tmp registry");
852 unlink(tmp);
855 free(tmp);
856 free(fn);
858 break;
859 default:
860 ERR_(reg)("unknown/invalid key handle !\n");
861 break;
866 /******************************************************************************
867 * SHELL_SaveRegistry [Internal]
869 void SHELL_SaveRegistry( void )
871 char buf[4];
872 HKEY hkey;
873 int all;
875 TRACE_(reg)("(void)\n");
877 all=0;
878 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
880 strcpy(buf,"yes");
882 else
884 DWORD len,junk,type;
886 len=4;
887 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
888 VAL_SAVEUPDATED,
889 &junk,
890 &type,
891 buf,
892 &len)) || (type!=REG_SZ))
894 strcpy(buf,"yes");
896 RegCloseKey(hkey);
899 if (lstrcmpiA(buf,"yes"))
900 all = 1;
902 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
903 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
904 SHELL_SaveRegistryBranch(HKEY_USERS, all);
908 /************************ LOAD Registry Function ****************************/
912 /******************************************************************************
913 * _find_or_add_key [Internal]
915 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
917 LPKEYSTRUCT lpxkey,*lplpkey;
919 if ((!keyname) || (keyname[0]==0)) {
920 free(keyname);
921 return lpkey;
923 lplpkey= &(lpkey->nextsub);
924 lpxkey = *lplpkey;
925 while (lpxkey) {
926 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
927 !lstrcmpiW(lpxkey->keyname,keyname)
929 break;
930 lplpkey = &(lpxkey->next);
931 lpxkey = *lplpkey;
933 if (lpxkey==NULL) {
934 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
935 lpxkey = *lplpkey;
936 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
937 lpxkey->keyname = keyname;
938 } else
939 free(keyname);
940 return lpxkey;
943 /******************************************************************************
944 * _find_or_add_value [Internal]
946 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
947 LPBYTE data, DWORD len, DWORD lastmodified )
949 LPKEYVALUE val=NULL;
950 int i;
952 if (name && !*name) {/* empty string equals default (NULL) value */
953 free(name);
954 name = NULL;
957 for (i=0;i<lpkey->nrofvalues;i++) {
958 val=lpkey->values+i;
959 if (name==NULL) {
960 if (val->name==NULL)
961 break;
962 } else {
963 if ( val->name!=NULL &&
964 tolower(val->name[0])==tolower(name[0]) &&
965 !lstrcmpiW(val->name,name)
967 break;
970 if (i==lpkey->nrofvalues) {
971 lpkey->values = xrealloc(
972 lpkey->values,
973 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
975 val=lpkey->values+i;
976 memset(val,'\0',sizeof(KEYVALUE));
977 val->name = name;
978 } else {
979 if (name)
980 free(name);
982 if (val->lastmodified<lastmodified) {
983 val->lastmodified=lastmodified;
984 val->type = type;
986 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
988 data=xmalloc(sizeof(WCHAR));
989 memset(data,0,sizeof(WCHAR));
990 len =sizeof(WCHAR);
993 val->len = len;
994 if (val->data)
995 free(val->data);
996 val->data = data;
997 } else
998 free(data);
1002 /******************************************************************************
1003 * _wine_read_line [Internal]
1005 * reads a line including dynamically enlarging the readbuffer and throwing
1006 * away comments
1008 static int _wine_read_line( FILE *F, char **buf, int *len )
1010 char *s,*curread;
1011 int mylen,curoff;
1013 curread = *buf;
1014 mylen = *len;
1015 **buf = '\0';
1016 while (1) {
1017 while (1) {
1018 s=fgets(curread,mylen,F);
1019 if (s==NULL)
1020 return 0; /* EOF */
1021 if (NULL==(s=strchr(curread,'\n'))) {
1022 /* buffer wasn't large enough */
1023 curoff = strlen(*buf);
1024 *buf = xrealloc(*buf,*len*2);
1025 curread = *buf + curoff;
1026 mylen = *len; /* we filled up the buffer and
1027 * got new '*len' bytes to fill
1029 *len = *len * 2;
1030 } else {
1031 *s='\0';
1032 break;
1035 /* throw away comments */
1036 if (**buf=='#' || **buf==';') {
1037 curread = *buf;
1038 mylen = *len;
1039 continue;
1041 if (s) /* got end of line */
1042 break;
1044 return 1;
1048 /******************************************************************************
1049 * _wine_read_USTRING [Internal]
1051 * converts a char* into a UNICODE string (up to a special char)
1052 * and returns the position exactly after that string
1054 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1056 char *s;
1057 LPWSTR ws;
1059 /* read up to "=" or "\0" or "\n" */
1060 s = buf;
1061 if (*s == '=') {
1062 /* empty string is the win3.1 default value(NULL)*/
1063 *str = NULL;
1064 return s;
1066 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1067 ws = *str;
1068 while (*s && (*s!='\n') && (*s!='=')) {
1069 if (*s!='\\')
1070 *ws++=*((unsigned char*)s++);
1071 else {
1072 s++;
1073 if (!*s) {
1074 /* Dangling \ ... may only happen if a registry
1075 * write was short. FIXME: What do to?
1077 break;
1079 if (*s=='\\') {
1080 *ws++='\\';
1081 s++;
1082 continue;
1084 if (*s!='u') {
1085 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1086 *ws++='\\';
1087 *ws++=*s++;
1088 } else {
1089 char xbuf[5];
1090 int wc;
1092 s++;
1093 memcpy(xbuf,s,4);xbuf[4]='\0';
1094 if (!sscanf(xbuf,"%x",&wc))
1095 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1096 s+=4;
1097 *ws++ =(unsigned short)wc;
1101 *ws = 0;
1102 ws = *str;
1103 if (*ws)
1104 *str = strdupW(*str);
1105 else
1106 *str = NULL;
1107 free(ws);
1108 return s;
1112 /******************************************************************************
1113 * _wine_loadsubkey [Internal]
1115 * NOTES
1116 * It seems like this is returning a boolean. Should it?
1118 * RETURNS
1119 * Success: 1
1120 * Failure: 0
1122 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1123 int *buflen, DWORD optflag )
1125 LPKEYSTRUCT lpxkey;
1126 int i;
1127 char *s;
1128 LPWSTR name;
1130 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1131 *buflen, optflag);
1133 lpkey->flags |= optflag;
1135 /* Good. We already got a line here ... so parse it */
1136 lpxkey = NULL;
1137 while (1) {
1138 i=0;s=*buf;
1139 while (*s=='\t') {
1140 s++;
1141 i++;
1143 if (i>level) {
1144 if (lpxkey==NULL) {
1145 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1146 return 0;
1148 if (!_wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag))
1149 if (!_wine_read_line(F,buf,buflen))
1150 return 1;
1151 continue;
1154 /* let the caller handle this line */
1155 if (i<level || **buf=='\0')
1156 return 1;
1158 /* it can be: a value or a keyname. Parse the name first */
1159 s=_wine_read_USTRING(s,&name);
1161 /* switch() default: hack to avoid gotos */
1162 switch (0) {
1163 default:
1164 if (*s=='\0') {
1165 lpxkey=_find_or_add_key(lpkey,name);
1166 } else {
1167 LPBYTE data;
1168 int len,lastmodified,type;
1170 if (*s!='=') {
1171 WARN_(reg)("Unexpected character: %c\n",*s);
1172 break;
1174 s++;
1175 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1176 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1177 break;
1179 /* skip the 2 , */
1180 s=strchr(s,',');s++;
1181 s=strchr(s,',');
1182 if (!s++) {
1183 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1184 break;
1186 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1187 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1188 if (data)
1189 len = lstrlenW((LPWSTR)data)*2+2;
1190 else
1191 len = 0;
1192 } else {
1193 len=strlen(s)/2;
1194 data = (LPBYTE)xmalloc(len+1);
1195 for (i=0;i<len;i++) {
1196 data[i]=0;
1197 if (*s>='0' && *s<='9')
1198 data[i]=(*s-'0')<<4;
1199 if (*s>='a' && *s<='f')
1200 data[i]=(*s-'a'+'\xa')<<4;
1201 if (*s>='A' && *s<='F')
1202 data[i]=(*s-'A'+'\xa')<<4;
1203 s++;
1204 if (*s>='0' && *s<='9')
1205 data[i]|=*s-'0';
1206 if (*s>='a' && *s<='f')
1207 data[i]|=*s-'a'+'\xa';
1208 if (*s>='A' && *s<='F')
1209 data[i]|=*s-'A'+'\xa';
1210 s++;
1213 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1216 /* read the next line */
1217 if (!_wine_read_line(F,buf,buflen))
1218 return 1;
1220 return 1;
1224 /******************************************************************************
1225 * _wine_loadsubreg [Internal]
1227 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1229 int ver;
1230 char *buf;
1231 int buflen;
1233 buf=xmalloc(10);buflen=10;
1234 if (!_wine_read_line(F,&buf,&buflen)) {
1235 free(buf);
1236 return 0;
1238 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1239 free(buf);
1240 return 0;
1242 if (ver!=REGISTRY_SAVE_VERSION) {
1243 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1244 free(buf);
1245 return 0;
1247 if (!_wine_read_line(F,&buf,&buflen)) {
1248 free(buf);
1249 return 0;
1251 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1252 free(buf);
1253 return 0;
1255 free(buf);
1256 return 1;
1260 /******************************************************************************
1261 * _wine_loadreg [Internal]
1263 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1265 FILE *F;
1267 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1269 F = fopen(fn,"rb");
1270 if (F==NULL) {
1271 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1272 return;
1274 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1275 fclose(F);
1276 unlink(fn);
1277 return;
1279 fclose(F);
1282 /******************************************************************************
1283 * _flush_registry [Internal]
1285 * This function allow to flush section of the internal registry. It is mainly
1286 * implements to fix a problem with the global HKU and the local HKU.
1287 * Those two files are read to build the HKU\.Default branch to finaly copy
1288 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1289 * all the global HKU are saved onto the user's personal version of HKU hive.
1290 * which is bad...
1293 /* Forward declaration of recusive agent */
1294 static void _flush_reg(LPKEYSTRUCT from);
1296 static void _flush_registry( LPKEYSTRUCT from )
1298 /* make sure we have something... */
1299 if (from == NULL)
1300 return;
1302 /* Launch the recusive agent on sub branches */
1303 _flush_reg( from->nextsub );
1304 _flush_reg( from->next );
1306 /* Initialize pointers */
1307 from->nextsub = NULL;
1308 from->next = NULL;
1310 static void _flush_reg( LPKEYSTRUCT from )
1312 int j;
1314 /* make sure we have something... */
1315 if (from == NULL)
1316 return;
1319 * do the same for the child keys
1321 if (from->nextsub != NULL)
1322 _flush_reg(from->nextsub);
1325 * do the same for the sibling keys
1327 if (from->next != NULL)
1328 _flush_reg(from->next);
1331 * iterate through this key's values and delete them
1333 for (j=0;j<from->nrofvalues;j++)
1335 free( (from->values+j)->name);
1336 free( (from->values+j)->data);
1340 * free the structure
1342 if ( from != NULL )
1343 free(from);
1347 /******************************************************************************
1348 * _copy_registry [Internal]
1350 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1352 LPKEYSTRUCT lpxkey;
1353 int j;
1354 LPKEYVALUE valfrom;
1356 from=from->nextsub;
1357 while (from) {
1358 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1360 for (j=0;j<from->nrofvalues;j++) {
1361 LPWSTR name;
1362 LPBYTE data;
1364 valfrom = from->values+j;
1365 name=valfrom->name;
1366 if (name) name=strdupW(name);
1367 data=(LPBYTE)xmalloc(valfrom->len);
1368 memcpy(data,valfrom->data,valfrom->len);
1370 _find_or_add_value(
1371 lpxkey,
1372 name,
1373 valfrom->type,
1374 data,
1375 valfrom->len,
1376 valfrom->lastmodified
1379 _copy_registry(from,lpxkey);
1380 from = from->next;
1385 /* WINDOWS 95 REGISTRY LOADER */
1387 * Structure of a win95 registry database.
1388 * main header:
1389 * 0 : "CREG" - magic
1390 * 4 : DWORD version
1391 * 8 : DWORD offset_of_RGDB_part
1392 * 0C..0F: ? (someone fill in please)
1393 * 10: WORD number of RGDB blocks
1394 * 12: WORD ?
1395 * 14: WORD always 0000?
1396 * 16: WORD always 0001?
1397 * 18..1F: ? (someone fill in please)
1399 * 20: RGKN_section:
1400 * header:
1401 * 0 : "RGKN" - magic
1402 * 4 : DWORD offset to first RGDB section
1403 * 8 : DWORD offset to the root record
1404 * C..0x1B: ? (fill in)
1405 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1407 * Disk Key Entry Structure:
1408 * 00: DWORD - Free entry indicator(?)
1409 * 04: DWORD - Hash = sum of bytes of keyname
1410 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1411 * 0C: DWORD - disk address of PreviousLevel Key.
1412 * 10: DWORD - disk address of Next Sublevel Key.
1413 * 14: DWORD - disk address of Next Key (on same level).
1414 * DKEP>18: WORD - Nr, Low Significant part.
1415 * 1A: WORD - Nr, High Significant part.
1417 * The disk address always points to the nr part of the previous key entry
1418 * of the referenced key. Don't ask me why, or even if I got this correct
1419 * from staring at 1kg of hexdumps. (DKEP)
1421 * The High significant part of the structure seems to equal the number
1422 * of the RGDB section. The low significant part is a unique ID within
1423 * that RGDB section
1425 * There are two minor corrections to the position of that structure.
1426 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1427 * the DKE reread from there.
1428 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1429 * CPS - I have not experienced the above phenomenon in my registry files
1431 * RGDB_section:
1432 * 00: "RGDB" - magic
1433 * 04: DWORD offset to next RGDB section
1434 * 08: DWORD ?
1435 * 0C: WORD always 000d?
1436 * 0E: WORD RGDB block number
1437 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1438 * 14..1F: ?
1439 * 20.....: disk keys
1441 * disk key:
1442 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1443 * 08: WORD nrLS - low significant part of NR
1444 * 0A: WORD nrHS - high significant part of NR
1445 * 0C: DWORD bytesused - bytes used in this structure.
1446 * 10: WORD name_len - length of name in bytes. without \0
1447 * 12: WORD nr_of_values - number of values.
1448 * 14: char name[name_len] - name string. No \0.
1449 * 14+name_len: disk values
1450 * nextkeyoffset: ... next disk key
1452 * disk value:
1453 * 00: DWORD type - value type (hmm, could be WORD too)
1454 * 04: DWORD - unknown, usually 0
1455 * 08: WORD namelen - length of Name. 0 means name=NULL
1456 * 0C: WORD datalen - length of Data.
1457 * 10: char name[namelen] - name, no \0
1458 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1459 * 10+namelen+datalen: next values or disk key
1461 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1462 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1463 * structure) and reading another RGDB_section.
1464 * repeat until end of file.
1466 * An interesting relationship exists in RGDB_section. The value at offset
1467 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1468 * idea at the moment what this means. (Kevin Cozens)
1470 * FIXME: this description needs some serious help, yes.
1473 struct _w95keyvalue {
1474 unsigned long type;
1475 unsigned short datalen;
1476 char *name;
1477 unsigned char *data;
1478 unsigned long x1;
1479 int lastmodified;
1482 struct _w95key {
1483 char *name;
1484 int nrofvals;
1485 struct _w95keyvalue *values;
1486 struct _w95key *prevlvl;
1487 struct _w95key *nextsub;
1488 struct _w95key *next;
1492 struct _w95_info {
1493 char *rgknbuffer;
1494 int rgknsize;
1495 char *rgdbbuffer;
1496 int rgdbsize;
1497 int depth;
1498 int lastmodified;
1502 /******************************************************************************
1503 * _w95_processKey [Internal]
1505 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1506 int nrLS, int nrMS, struct _w95_info *info )
1509 /* Disk Key Header structure (RGDB part) */
1510 struct dkh {
1511 unsigned long nextkeyoff;
1512 unsigned short nrLS;
1513 unsigned short nrMS;
1514 unsigned long bytesused;
1515 unsigned short keynamelen;
1516 unsigned short values;
1517 unsigned long xx1;
1518 /* keyname */
1519 /* disk key values or nothing */
1521 /* Disk Key Value structure */
1522 struct dkv {
1523 unsigned long type;
1524 unsigned long x1;
1525 unsigned short valnamelen;
1526 unsigned short valdatalen;
1527 /* valname, valdata */
1531 struct dkh dkh;
1532 int bytesread = 0;
1533 char *rgdbdata = info->rgdbbuffer;
1534 int nbytes = info->rgdbsize;
1535 char *curdata = rgdbdata;
1536 char *end = rgdbdata + nbytes;
1537 int off_next_rgdb;
1538 char *next = rgdbdata;
1539 int nrgdb, i;
1540 LPKEYSTRUCT lpxkey;
1542 do {
1543 curdata = next;
1544 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1546 memcpy(&off_next_rgdb,curdata+4,4);
1547 next = curdata + off_next_rgdb;
1548 nrgdb = (int) *((short *)curdata + 7);
1550 } while (nrgdb != nrMS && (next < end));
1552 /* curdata now points to the start of the right RGDB section */
1553 curdata += 0x20;
1555 #define XREAD(whereto,len) \
1556 if ((curdata + len) <= end) {\
1557 memcpy(whereto,curdata,len);\
1558 curdata+=len;\
1559 bytesread+=len;\
1562 while (curdata < next) {
1563 struct dkh *xdkh = (struct dkh*)curdata;
1565 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1566 if (xdkh->nrLS == nrLS) {
1567 memcpy(&dkh,xdkh,sizeof(dkh));
1568 curdata += sizeof(dkh);
1569 break;
1571 curdata += xdkh->nextkeyoff;
1574 if (dkh.nrLS != nrLS) return (NULL);
1576 if (nrgdb != dkh.nrMS)
1577 return (NULL);
1579 assert((dkh.keynamelen<2) || curdata[0]);
1580 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1581 curdata += dkh.keynamelen;
1583 for (i=0;i< dkh.values; i++) {
1584 struct dkv dkv;
1585 LPBYTE data;
1586 int len;
1587 LPWSTR name;
1589 XREAD(&dkv,sizeof(dkv));
1591 name = strcvtA2W(curdata, dkv.valnamelen);
1592 curdata += dkv.valnamelen;
1594 if ((1 << dkv.type) & UNICONVMASK) {
1595 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1596 len = 2*(dkv.valdatalen + 1);
1597 } else {
1598 /* I don't think we want to NULL terminate all data */
1599 data = xmalloc(dkv.valdatalen);
1600 memcpy (data, curdata, dkv.valdatalen);
1601 len = dkv.valdatalen;
1604 curdata += dkv.valdatalen;
1606 _find_or_add_value(
1607 lpxkey,
1608 name,
1609 dkv.type,
1610 data,
1611 len,
1612 info->lastmodified
1615 return (lpxkey);
1618 /******************************************************************************
1619 * _w95_walkrgkn [Internal]
1621 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1622 struct _w95_info *info )
1625 /* Disk Key Entry structure (RGKN part) */
1626 struct dke {
1627 unsigned long x1;
1628 unsigned long x2;
1629 unsigned long x3;/*usually 0xFFFFFFFF */
1630 unsigned long prevlvl;
1631 unsigned long nextsub;
1632 unsigned long next;
1633 unsigned short nrLS;
1634 unsigned short nrMS;
1635 } *dke = (struct dke *)off;
1636 LPKEYSTRUCT lpxkey;
1638 if (dke == NULL) {
1639 dke = (struct dke *) ((char *)info->rgknbuffer);
1642 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1643 /* XXX <-- This is a hack*/
1644 if (!lpxkey) {
1645 lpxkey = prevkey;
1648 if (dke->nextsub != -1 &&
1649 ((dke->nextsub - 0x20) < info->rgknsize)
1650 && (dke->nextsub > 0x20)) {
1652 _w95_walkrgkn(lpxkey,
1653 info->rgknbuffer + dke->nextsub - 0x20,
1654 info);
1657 if (dke->next != -1 &&
1658 ((dke->next - 0x20) < info->rgknsize) &&
1659 (dke->next > 0x20)) {
1660 _w95_walkrgkn(prevkey,
1661 info->rgknbuffer + dke->next - 0x20,
1662 info);
1665 return;
1669 /******************************************************************************
1670 * _w95_loadreg [Internal]
1672 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1674 HFILE hfd;
1675 char magic[5];
1676 unsigned long where,version,rgdbsection,end;
1677 struct _w95_info info;
1678 OFSTRUCT ofs;
1679 BY_HANDLE_FILE_INFORMATION hfdinfo;
1681 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1682 hfd=OpenFile(fn,&ofs,OF_READ);
1683 if (hfd==HFILE_ERROR)
1684 return;
1685 magic[4]=0;
1686 if (4!=_lread(hfd,magic,4))
1687 return;
1688 if (strcmp(magic,"CREG")) {
1689 WARN_(reg)("%s is not a w95 registry.\n",fn);
1690 return;
1692 if (4!=_lread(hfd,&version,4))
1693 return;
1694 if (4!=_lread(hfd,&rgdbsection,4))
1695 return;
1696 if (-1==_llseek(hfd,0x20,SEEK_SET))
1697 return;
1698 if (4!=_lread(hfd,magic,4))
1699 return;
1700 if (strcmp(magic,"RGKN")) {
1701 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1702 return;
1705 /* STEP 1: Keylink structures */
1706 if (-1==_llseek(hfd,0x40,SEEK_SET))
1707 return;
1708 where = 0x40;
1709 end = rgdbsection;
1711 info.rgknsize = end - where;
1712 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1713 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1714 return;
1716 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1717 return;
1719 end = hfdinfo.nFileSizeLow;
1720 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1722 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1723 return;
1725 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1726 info.rgdbsize = end - rgdbsection;
1728 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1729 return;
1730 _lclose(hfd);
1732 _w95_walkrgkn(lpkey, NULL, &info);
1734 free (info.rgdbbuffer);
1735 free (info.rgknbuffer);
1739 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1742 reghack - windows 3.11 registry data format demo program.
1744 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1745 a combined hash table and tree description, and finally a text table.
1747 The header is obvious from the struct header. The taboff1 and taboff2
1748 fields are always 0x20, and their usage is unknown.
1750 The 8-byte entry table has various entry types.
1752 tabent[0] is a root index. The second word has the index of the root of
1753 the directory.
1754 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1755 the index of the key/value that has that hash. Data with the same
1756 hash value are on a circular list. The other three words in the
1757 hash entry are always zero.
1758 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1759 entry: dirent and keyent/valent. They are identified by context.
1760 tabent[freeidx] is the first free entry. The first word in a free entry
1761 is the index of the next free entry. The last has 0 as a link.
1762 The other three words in the free list are probably irrelevant.
1764 Entries in text table are preceeded by a word at offset-2. This word
1765 has the value (2*index)+1, where index is the referring keyent/valent
1766 entry in the table. I have no suggestion for the 2* and the +1.
1767 Following the word, there are N bytes of data, as per the keyent/valent
1768 entry length. The offset of the keyent/valent entry is from the start
1769 of the text table to the first data byte.
1771 This information is not available from Microsoft. The data format is
1772 deduced from the reg.dat file by me. Mistakes may
1773 have been made. I claim no rights and give no guarantees for this program.
1775 Tor Sjøwall, tor@sn.no
1778 /* reg.dat header format */
1779 struct _w31_header {
1780 char cookie[8]; /* 'SHCC3.10' */
1781 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1782 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1783 unsigned long tabcnt; /* number of entries in index table */
1784 unsigned long textoff; /* offset of text part */
1785 unsigned long textsize; /* byte size of text part */
1786 unsigned short hashsize; /* hash size */
1787 unsigned short freeidx; /* free index */
1790 /* generic format of table entries */
1791 struct _w31_tabent {
1792 unsigned short w0, w1, w2, w3;
1795 /* directory tabent: */
1796 struct _w31_dirent {
1797 unsigned short sibling_idx; /* table index of sibling dirent */
1798 unsigned short child_idx; /* table index of child dirent */
1799 unsigned short key_idx; /* table index of key keyent */
1800 unsigned short value_idx; /* table index of value valent */
1803 /* key tabent: */
1804 struct _w31_keyent {
1805 unsigned short hash_idx; /* hash chain index for string */
1806 unsigned short refcnt; /* reference count */
1807 unsigned short length; /* length of string */
1808 unsigned short string_off; /* offset of string in text table */
1811 /* value tabent: */
1812 struct _w31_valent {
1813 unsigned short hash_idx; /* hash chain index for string */
1814 unsigned short refcnt; /* reference count */
1815 unsigned short length; /* length of string */
1816 unsigned short string_off; /* offset of string in text table */
1819 /* recursive helper function to display a directory tree */
1820 void
1821 __w31_dumptree( unsigned short idx,
1822 unsigned char *txt,
1823 struct _w31_tabent *tab,
1824 struct _w31_header *head,
1825 LPKEYSTRUCT lpkey,
1826 time_t lastmodified,
1827 int level
1829 struct _w31_dirent *dir;
1830 struct _w31_keyent *key;
1831 struct _w31_valent *val;
1832 LPKEYSTRUCT xlpkey = NULL;
1833 LPWSTR name,value;
1834 static char tail[400];
1836 while (idx!=0) {
1837 dir=(struct _w31_dirent*)&tab[idx];
1839 if (dir->key_idx) {
1840 key = (struct _w31_keyent*)&tab[dir->key_idx];
1842 memcpy(tail,&txt[key->string_off],key->length);
1843 tail[key->length]='\0';
1844 /* all toplevel entries AND the entries in the
1845 * toplevel subdirectory belong to \SOFTWARE\Classes
1847 if (!level && !lstrcmpA(tail,".classes")) {
1848 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1849 idx=dir->sibling_idx;
1850 continue;
1852 name=strdupA2W(tail);
1854 xlpkey=_find_or_add_key(lpkey,name);
1856 /* only add if leaf node or valued node */
1857 if (dir->value_idx!=0||dir->child_idx==0) {
1858 if (dir->value_idx) {
1859 val=(struct _w31_valent*)&tab[dir->value_idx];
1860 memcpy(tail,&txt[val->string_off],val->length);
1861 tail[val->length]='\0';
1862 value=strdupA2W(tail);
1863 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1866 } else {
1867 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1869 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1870 idx=dir->sibling_idx;
1875 /******************************************************************************
1876 * _w31_loadreg [Internal]
1878 void _w31_loadreg(void) {
1879 HFILE hf;
1880 struct _w31_header head;
1881 struct _w31_tabent *tab;
1882 unsigned char *txt;
1883 int len;
1884 OFSTRUCT ofs;
1885 BY_HANDLE_FILE_INFORMATION hfinfo;
1886 time_t lastmodified;
1887 LPKEYSTRUCT lpkey;
1889 TRACE_(reg)("(void)\n");
1891 hf = OpenFile("reg.dat",&ofs,OF_READ);
1892 if (hf==HFILE_ERROR)
1893 return;
1895 /* read & dump header */
1896 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1897 ERR_(reg)("reg.dat is too short.\n");
1898 _lclose(hf);
1899 return;
1901 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1902 ERR_(reg)("reg.dat has bad signature.\n");
1903 _lclose(hf);
1904 return;
1907 len = head.tabcnt * sizeof(struct _w31_tabent);
1908 /* read and dump index table */
1909 tab = xmalloc(len);
1910 if (len!=_lread(hf,tab,len)) {
1911 ERR_(reg)("couldn't read %d bytes.\n",len);
1912 free(tab);
1913 _lclose(hf);
1914 return;
1917 /* read text */
1918 txt = xmalloc(head.textsize);
1919 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1920 ERR_(reg)("couldn't seek to textblock.\n");
1921 free(tab);
1922 free(txt);
1923 _lclose(hf);
1924 return;
1926 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1927 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1928 free(tab);
1929 free(txt);
1930 _lclose(hf);
1931 return;
1934 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1935 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1936 free(tab);
1937 free(txt);
1938 _lclose(hf);
1939 return;
1941 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1942 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1943 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1944 free(tab);
1945 free(txt);
1946 _lclose(hf);
1947 return;
1951 /**********************************************************************************
1952 * SHELL_LoadRegistry [Internal]
1954 void SHELL_LoadRegistry( void )
1956 char *fn, *home;
1957 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1958 HKEY hkey;
1960 TRACE_(reg)("(void)\n");
1962 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1963 HKU = lookup_hkey(HKEY_USERS);
1964 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1966 if (PROFILE_GetWineIniBool ("registry", "LoadWindowsRegistryFiles", 1))
1968 /* Load windows 3.1 entries */
1969 _w31_loadreg();
1970 /* Load windows 95 entries */
1971 _w95_loadreg("C:\\system.1st", HKLM);
1972 _w95_loadreg("system.dat", HKLM);
1973 _w95_loadreg("user.dat", HKU);
1976 if (PROFILE_GetWineIniBool ("registry","LoadGlobalRegistryFiles", 1))
1979 * Load the global HKU hive directly from sysconfdir
1981 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1984 * Load the global machine defaults directly form sysconfdir
1986 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1990 * Load the user saved registries
1992 if (!(home = getenv( "HOME" )))
1993 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1994 else if (PROFILE_GetWineIniBool("registry", "LoadHomeRegistryFiles", 1))
1997 * Load user's personal versions of global HKU/.Default keys
1999 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX) +
2000 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2001 strcpy(fn, home);
2002 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2003 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
2004 free(fn);
2006 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) + strlen(SAVE_CURRENT_USER)+2);
2007 strcpy(fn, home);
2008 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2009 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2010 free(fn);
2013 * Load HKLM, attempt to get the registry location from the config
2014 * file first, if exist, load and keep going.
2016 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
2017 strcpy(fn,home);
2018 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2019 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2020 free(fn);
2024 * Load HKCU, get the registry location from the config
2025 * file, if exist, load and keep going.
2027 if (PROFILE_GetWineIniBool ( "registry", "LoadAltRegistryFiles", 1))
2029 fn = xmalloc( MAX_PATHNAME_LEN );
2030 if ( PROFILE_GetWineIniString( "registry", "AltCurrentUserFile", "",
2031 fn, MAX_PATHNAME_LEN - 1))
2033 _wine_loadreg(HKCU,fn,REG_OPTION_TAINTED);
2035 free (fn);
2037 * Load HKU, get the registry location from the config
2038 * file, if exist, load and keep going.
2040 fn = xmalloc ( MAX_PATHNAME_LEN );
2041 if ( PROFILE_GetWineIniString ( "registry", "AltUserFile", "",
2042 fn, MAX_PATHNAME_LEN - 1))
2044 _wine_loadreg(HKU,fn,REG_OPTION_TAINTED);
2046 free (fn);
2048 * Load HKLM, get the registry location from the config
2049 * file, if exist, load and keep going.
2051 fn = xmalloc ( MAX_PATHNAME_LEN );
2052 if (PROFILE_GetWineIniString ( "registry", "AltLocalMachineFile", "",
2053 fn, MAX_PATHNAME_LEN - 1))
2055 _wine_loadreg(HKLM,fn,REG_OPTION_TAINTED);
2057 free (fn);
2061 * Obtain the handle of the HKU\.Default key.
2062 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2064 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2065 lpkey = lookup_hkey(hkey);
2066 if(!lpkey){
2067 WARN_(reg)("Could not create global user default key\n");
2068 } else {
2069 _copy_registry(lpkey, HKCU );
2072 RegCloseKey(hkey);
2075 * Since HKU is built from the global HKU and the local user HKU file we must
2076 * flush the HKU tree we have built at this point otherwise the part brought
2077 * in from the global HKU is saved into the local HKU. To avoid this
2078 * useless dupplication of HKU keys we reread the local HKU key.
2081 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2082 _flush_registry(HKU);
2084 /* Reload user's local HKU hive */
2085 if (home && PROFILE_GetWineIniBool ("registry","LoadHomeRegistryFiles",1))
2087 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2088 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2090 strcpy(fn,home);
2091 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2093 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2095 free(fn);
2099 * Make sure the update mode is there
2101 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2103 DWORD junk,type,len;
2104 char data[5];
2106 len=4;
2107 if (( RegQueryValueExA(
2108 hkey,
2109 VAL_SAVEUPDATED,
2110 &junk,
2111 &type,
2112 data,
2113 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2115 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2118 RegCloseKey(hkey);
2123 /********************* API FUNCTIONS ***************************************/
2125 * Open Keys.
2127 * All functions are stubs to RegOpenKeyEx32W where all the
2128 * magic happens.
2130 * Callpath:
2131 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2132 * RegOpenKey32W -> RegOpenKeyEx32W
2136 /******************************************************************************
2137 * RegOpenKeyEx32W [ADVAPI32.150]
2138 * Opens the specified key
2140 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2142 * PARAMS
2143 * hkey [I] Handle of open key
2144 * lpszSubKey [I] Name of subkey to open
2145 * dwReserved [I] Reserved - must be zero
2146 * samDesired [I] Security access mask
2147 * retkey [O] Address of handle of open key
2149 * RETURNS
2150 * Success: ERROR_SUCCESS
2151 * Failure: Error code
2153 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2154 REGSAM samDesired, LPHKEY retkey )
2156 LPKEYSTRUCT lpNextKey,lpxkey;
2157 LPWSTR *wps;
2158 int wpc,i;
2160 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2161 samDesired,retkey);
2163 lpNextKey = lookup_hkey( hkey );
2164 if (!lpNextKey)
2165 return ERROR_INVALID_HANDLE;
2167 if (!lpszSubKey || !*lpszSubKey) {
2168 /* Either NULL or pointer to empty string, so return a new handle
2169 to the original hkey */
2170 currenthandle += 2;
2171 add_handle(currenthandle,lpNextKey,samDesired);
2172 *retkey=currenthandle;
2173 return ERROR_SUCCESS;
2176 if (lpszSubKey[0] == '\\') {
2177 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2178 return ERROR_BAD_PATHNAME;
2181 split_keypath(lpszSubKey,&wps,&wpc);
2182 i = 0;
2183 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2184 lpxkey = lpNextKey;
2186 while (wps[i]) {
2187 lpxkey=lpNextKey->nextsub;
2188 while (lpxkey) {
2189 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2190 break;
2192 lpxkey=lpxkey->next;
2195 if (!lpxkey) {
2196 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2197 FREE_KEY_PATH;
2198 return ERROR_FILE_NOT_FOUND;
2200 i++;
2201 lpNextKey = lpxkey;
2204 currenthandle += 2;
2205 add_handle(currenthandle,lpxkey,samDesired);
2206 *retkey = currenthandle;
2207 TRACE_(reg)(" Returning %x\n", currenthandle);
2208 FREE_KEY_PATH;
2209 return ERROR_SUCCESS;
2213 /******************************************************************************
2214 * RegOpenKeyEx32A [ADVAPI32.149]
2216 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2217 REGSAM samDesired, LPHKEY retkey )
2219 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2220 DWORD ret;
2222 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2223 samDesired,retkey);
2224 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2225 free(lpszSubKeyW);
2226 return ret;
2230 /******************************************************************************
2231 * RegOpenKey32W [ADVAPI32.151]
2233 * PARAMS
2234 * hkey [I] Handle of open key
2235 * lpszSubKey [I] Address of name of subkey to open
2236 * retkey [O] Address of handle of open key
2238 * RETURNS
2239 * Success: ERROR_SUCCESS
2240 * Failure: Error code
2242 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2244 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2245 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2249 /******************************************************************************
2250 * RegOpenKey32A [ADVAPI32.148]
2252 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2254 DWORD ret;
2255 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2256 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2257 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2258 free(lpszSubKeyW);
2259 return ret;
2263 /******************************************************************************
2264 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2266 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2268 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2269 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2274 * Create keys
2276 * All those functions convert their respective
2277 * arguments and call RegCreateKeyExW at the end.
2279 * We stay away from the Ex functions as long as possible because there are
2280 * differences in the return values
2282 * Callpath:
2283 * RegCreateKeyEx32A \
2284 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2288 /******************************************************************************
2289 * RegCreateKeyEx32W [ADVAPI32.131]
2291 * PARAMS
2292 * hkey [I] Handle of an open key
2293 * lpszSubKey [I] Address of subkey name
2294 * dwReserved [I] Reserved - must be 0
2295 * lpszClass [I] Address of class string
2296 * fdwOptions [I] Special options flag
2297 * samDesired [I] Desired security access
2298 * lpSecAttribs [I] Address of key security structure
2299 * retkey [O] Address of buffer for opened handle
2300 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2302 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2303 DWORD dwReserved, LPWSTR lpszClass,
2304 DWORD fdwOptions, REGSAM samDesired,
2305 LPSECURITY_ATTRIBUTES lpSecAttribs,
2306 LPHKEY retkey, LPDWORD lpDispos )
2308 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2309 LPWSTR *wps;
2310 int wpc,i;
2312 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2313 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2314 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2316 lpNextKey = lookup_hkey(hkey);
2317 if (!lpNextKey)
2318 return ERROR_INVALID_HANDLE;
2320 /* Check for valid options */
2321 switch(fdwOptions) {
2322 case REG_OPTION_NON_VOLATILE:
2323 case REG_OPTION_VOLATILE:
2324 case REG_OPTION_BACKUP_RESTORE:
2325 break;
2326 default:
2327 return ERROR_INVALID_PARAMETER;
2330 /* Sam has to be a combination of the following */
2331 if (!(samDesired &
2332 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2333 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2334 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2335 return ERROR_INVALID_PARAMETER;
2337 if (!lpszSubKey || !*lpszSubKey) {
2338 currenthandle += 2;
2339 add_handle(currenthandle,lpNextKey,samDesired);
2340 *retkey=currenthandle;
2341 TRACE_(reg)("Returning %x\n", currenthandle);
2342 lpNextKey->flags|=REG_OPTION_TAINTED;
2343 return ERROR_SUCCESS;
2346 if (lpszSubKey[0] == '\\') {
2347 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2348 return ERROR_BAD_PATHNAME;
2351 split_keypath(lpszSubKey,&wps,&wpc);
2352 i = 0;
2353 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2354 lpxkey = lpNextKey;
2355 while (wps[i]) {
2356 lpxkey=lpNextKey->nextsub;
2357 while (lpxkey) {
2358 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2359 break;
2360 lpxkey=lpxkey->next;
2362 if (!lpxkey)
2363 break;
2364 i++;
2365 lpNextKey = lpxkey;
2367 if (lpxkey) {
2368 currenthandle += 2;
2369 add_handle(currenthandle,lpxkey,samDesired);
2370 lpxkey->flags |= REG_OPTION_TAINTED;
2371 *retkey = currenthandle;
2372 TRACE_(reg)("Returning %x\n", currenthandle);
2373 if (lpDispos)
2374 *lpDispos = REG_OPENED_EXISTING_KEY;
2375 FREE_KEY_PATH;
2376 return ERROR_SUCCESS;
2379 /* Good. Now the hard part */
2380 while (wps[i]) {
2381 lplpPrevKey = &(lpNextKey->nextsub);
2382 lpxkey = *lplpPrevKey;
2383 while (lpxkey) {
2384 lplpPrevKey = &(lpxkey->next);
2385 lpxkey = *lplpPrevKey;
2387 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2388 if (!*lplpPrevKey) {
2389 FREE_KEY_PATH;
2390 TRACE_(reg)("Returning OUTOFMEMORY\n");
2391 return ERROR_OUTOFMEMORY;
2393 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2394 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2395 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2396 (*lplpPrevKey)->next = NULL;
2397 (*lplpPrevKey)->nextsub = NULL;
2398 (*lplpPrevKey)->values = NULL;
2399 (*lplpPrevKey)->nrofvalues = 0;
2400 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2401 if (lpszClass)
2402 (*lplpPrevKey)->class = strdupW(lpszClass);
2403 else
2404 (*lplpPrevKey)->class = NULL;
2405 lpNextKey = *lplpPrevKey;
2406 i++;
2408 currenthandle += 2;
2409 add_handle(currenthandle,lpNextKey,samDesired);
2411 /*FIXME: flag handling correct? */
2412 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2413 if (lpszClass)
2414 lpNextKey->class = strdupW(lpszClass);
2415 else
2416 lpNextKey->class = NULL;
2417 *retkey = currenthandle;
2418 TRACE_(reg)("Returning %x\n", currenthandle);
2419 if (lpDispos)
2420 *lpDispos = REG_CREATED_NEW_KEY;
2421 FREE_KEY_PATH;
2422 return ERROR_SUCCESS;
2426 /******************************************************************************
2427 * RegCreateKeyEx32A [ADVAPI32.130]
2429 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2430 LPSTR lpszClass, DWORD fdwOptions,
2431 REGSAM samDesired,
2432 LPSECURITY_ATTRIBUTES lpSecAttribs,
2433 LPHKEY retkey, LPDWORD lpDispos )
2435 LPWSTR lpszSubKeyW, lpszClassW;
2436 DWORD ret;
2438 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2439 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2440 retkey,lpDispos);
2442 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2443 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2445 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2446 fdwOptions, samDesired, lpSecAttribs, retkey,
2447 lpDispos );
2449 if(lpszSubKeyW) free(lpszSubKeyW);
2450 if(lpszClassW) free(lpszClassW);
2452 return ret;
2456 /******************************************************************************
2457 * RegCreateKey32W [ADVAPI32.132]
2459 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2461 DWORD junk;
2462 LPKEYSTRUCT lpNextKey;
2464 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2466 /* This check is here because the return value is different than the
2467 one from the Ex functions */
2468 lpNextKey = lookup_hkey(hkey);
2469 if (!lpNextKey)
2470 return ERROR_BADKEY;
2472 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2473 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2474 retkey, &junk);
2478 /******************************************************************************
2479 * RegCreateKey32A [ADVAPI32.129]
2481 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2483 DWORD ret;
2484 LPWSTR lpszSubKeyW;
2486 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2487 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2488 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2489 if(lpszSubKeyW) free(lpszSubKeyW);
2490 return ret;
2494 /******************************************************************************
2495 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2497 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2499 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2500 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2505 * Query Value Functions
2506 * Win32 differs between keynames and valuenames.
2507 * multiple values may belong to one key, the special value
2508 * with name NULL is the default value used by the win31
2509 * compat functions.
2511 * Callpath:
2512 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2513 * RegQueryValue32W -> RegQueryValueEx32W
2517 /******************************************************************************
2518 * RegQueryValueEx32W [ADVAPI32.158]
2519 * Retrieves type and data for a specified name associated with an open key
2521 * PARAMS
2522 * hkey [I] Handle of key to query
2523 * lpValueName [I] Name of value to query
2524 * lpdwReserved [I] Reserved - must be NULL
2525 * lpdwType [O] Address of buffer for value type. If NULL, the type
2526 * is not required.
2527 * lpbData [O] Address of data buffer. If NULL, the actual data is
2528 * not required.
2529 * lpcbData [I/O] Address of data buffer size
2531 * RETURNS
2532 * ERROR_SUCCESS: Success
2533 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2534 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2536 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2537 LPDWORD lpdwReserved, LPDWORD lpdwType,
2538 LPBYTE lpbData, LPDWORD lpcbData )
2540 LPKEYSTRUCT lpkey;
2541 int i;
2542 DWORD ret;
2544 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2545 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2547 lpkey = lookup_hkey(hkey);
2549 if (!lpkey)
2550 return ERROR_INVALID_HANDLE;
2552 if ((lpbData && ! lpcbData) || lpdwReserved)
2553 return ERROR_INVALID_PARAMETER;
2555 /* An empty name string is equivalent to NULL */
2556 if (lpValueName && !*lpValueName)
2557 lpValueName = NULL;
2559 if (lpValueName==NULL)
2560 { /* Use key's unnamed or default value, if any */
2561 for (i=0;i<lpkey->nrofvalues;i++)
2562 if (lpkey->values[i].name==NULL)
2563 break;
2565 else
2566 { /* Search for the key name */
2567 for (i=0;i<lpkey->nrofvalues;i++)
2568 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2569 break;
2572 if (i==lpkey->nrofvalues)
2573 { TRACE_(reg)(" Key not found\n");
2574 if (lpValueName==NULL)
2575 { /* Empty keyname not found */
2576 if (lpbData)
2577 { *(WCHAR*)lpbData = 0;
2578 *lpcbData = 2;
2580 if (lpdwType)
2581 *lpdwType = REG_SZ;
2582 TRACE_(reg)(" Returning an empty string\n");
2583 return ERROR_SUCCESS;
2585 return ERROR_FILE_NOT_FOUND;
2588 ret = ERROR_SUCCESS;
2590 if (lpdwType) /* type required ?*/
2591 *lpdwType = lpkey->values[i].type;
2593 if (lpbData) /* data required ?*/
2594 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2595 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2596 else {
2597 *lpcbData = lpkey->values[i].len;
2598 ret = ERROR_MORE_DATA;
2602 if (lpcbData) /* size required ?*/
2603 { *lpcbData = lpkey->values[i].len;
2606 debug_print_value ( lpbData, &lpkey->values[i]);
2608 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2610 return ret;
2614 /******************************************************************************
2615 * RegQueryValue32W [ADVAPI32.159]
2617 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2618 LPLONG lpcbData )
2620 HKEY xhkey;
2621 DWORD ret,lpdwType;
2623 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2624 lpcbData?*lpcbData:0);
2626 /* Only open subkey, if we really do descend */
2627 if (lpszSubKey && *lpszSubKey) {
2628 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2629 if (ret != ERROR_SUCCESS) {
2630 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2631 return ret;
2633 } else
2634 xhkey = hkey;
2636 lpdwType = REG_SZ;
2637 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2638 lpcbData );
2639 if (xhkey != hkey)
2640 RegCloseKey(xhkey);
2641 return ret;
2645 /******************************************************************************
2646 * RegQueryValueEx32A [ADVAPI32.157]
2648 * NOTES:
2649 * the documantation is wrong: if the buffer is to small it remains untouched
2651 * FIXME: check returnvalue (len) for an empty key
2653 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2654 LPDWORD lpdwReserved, LPDWORD lpdwType,
2655 LPBYTE lpbData, LPDWORD lpcbData )
2657 LPWSTR lpszValueNameW;
2658 LPBYTE mybuf = NULL;
2659 DWORD ret, mytype, mylen = 0;
2661 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2662 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2664 if (!lpcbData && lpbData) /* buffer without size is illegal */
2665 { return ERROR_INVALID_PARAMETER;
2668 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2670 /* get just the type first */
2671 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2673 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2674 { if(lpszValueNameW) free(lpszValueNameW);
2675 return ret;
2678 if (lpcbData) /* at least length requested? */
2679 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2680 { if (lpbData ) /* value requested? */
2681 { mylen = 2*( *lpcbData );
2682 mybuf = (LPBYTE)xmalloc( mylen );
2685 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2687 if (ret == ERROR_SUCCESS )
2688 { if ( lpbData )
2689 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2693 *lpcbData = mylen/2; /* size is in byte! */
2695 else /* no strings, call it straight */
2696 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2700 if (lpdwType) /* type when requested */
2701 { *lpdwType = mytype;
2704 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2706 if(mybuf) free(mybuf);
2707 if(lpszValueNameW) free(lpszValueNameW);
2708 return ret;
2712 /******************************************************************************
2713 * RegQueryValueEx16 [KERNEL.225]
2715 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2716 LPDWORD lpdwReserved, LPDWORD lpdwType,
2717 LPBYTE lpbData, LPDWORD lpcbData )
2719 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2720 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2721 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2722 lpbData, lpcbData );
2726 /******************************************************************************
2727 * RegQueryValue32A [ADVAPI32.156]
2729 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2730 LPLONG lpcbData )
2732 HKEY xhkey;
2733 DWORD ret, dwType;
2735 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2736 lpcbData?*lpcbData:0);
2738 if (lpszSubKey && *lpszSubKey) {
2739 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2740 if( ret != ERROR_SUCCESS )
2741 return ret;
2742 } else
2743 xhkey = hkey;
2745 dwType = REG_SZ;
2746 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2747 lpcbData );
2748 if( xhkey != hkey )
2749 RegCloseKey( xhkey );
2750 return ret;
2754 /******************************************************************************
2755 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2757 * NOTES
2758 * Is this HACK still applicable?
2760 * HACK
2761 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2762 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2763 * Aldus FH4)
2765 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2766 LPDWORD lpcbData )
2768 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2769 lpcbData?*lpcbData:0);
2771 if (lpcbData)
2772 *lpcbData &= 0xFFFF;
2773 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2778 * Setting values of Registry keys
2780 * Callpath:
2781 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2782 * RegSetValue32W -> RegSetValueEx32W
2786 /******************************************************************************
2787 * RegSetValueEx32W [ADVAPI32.170]
2788 * Sets the data and type of a value under a register key
2790 * PARAMS
2791 * hkey [I] Handle of key to set value for
2792 * lpszValueName [I] Name of value to set
2793 * dwReserved [I] Reserved - must be zero
2794 * dwType [I] Flag for value type
2795 * lpbData [I] Address of value data
2796 * cbData [I] Size of value data
2798 * RETURNS
2799 * Success: ERROR_SUCCESS
2800 * Failure: Error code
2802 * NOTES
2803 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2805 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2806 DWORD dwReserved, DWORD dwType,
2807 CONST BYTE *lpbData, DWORD cbData)
2809 LPKEYSTRUCT lpkey;
2810 int i;
2812 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2813 dwReserved, dwType, lpbData, cbData);
2815 lpkey = lookup_hkey( hkey );
2817 if (!lpkey)
2818 return ERROR_INVALID_HANDLE;
2820 lpkey->flags |= REG_OPTION_TAINTED;
2822 if (lpszValueName==NULL) {
2823 /* Sets type and name for key's unnamed or default value */
2824 for (i=0;i<lpkey->nrofvalues;i++)
2825 if (lpkey->values[i].name==NULL)
2826 break;
2827 } else {
2828 for (i=0;i<lpkey->nrofvalues;i++)
2829 if ( lpkey->values[i].name &&
2830 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2832 break;
2834 if (i==lpkey->nrofvalues) {
2835 lpkey->values = (LPKEYVALUE)xrealloc(
2836 lpkey->values,
2837 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2839 lpkey->nrofvalues++;
2840 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2842 if (lpkey->values[i].name==NULL) {
2843 if (lpszValueName)
2844 lpkey->values[i].name = strdupW(lpszValueName);
2845 else
2846 lpkey->values[i].name = NULL;
2849 if (dwType == REG_SZ)
2850 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2852 lpkey->values[i].len = cbData;
2853 lpkey->values[i].type = dwType;
2854 if (lpkey->values[i].data !=NULL)
2855 free(lpkey->values[i].data);
2856 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2857 lpkey->values[i].lastmodified = time(NULL);
2858 memcpy(lpkey->values[i].data,lpbData,cbData);
2859 return ERROR_SUCCESS;
2863 /******************************************************************************
2864 * RegSetValueEx32A [ADVAPI32.169]
2866 * NOTES
2867 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2869 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2870 DWORD dwReserved, DWORD dwType,
2871 CONST BYTE *lpbData, DWORD cbData )
2873 LPBYTE buf;
2874 LPWSTR lpszValueNameW;
2875 DWORD ret;
2877 if (!lpbData)
2878 return (ERROR_INVALID_PARAMETER);
2880 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2881 dwReserved,dwType,lpbData,cbData);
2883 if ((1<<dwType) & UNICONVMASK)
2884 { if (dwType == REG_SZ)
2885 cbData = strlen ((LPCSTR)lpbData)+1;
2887 buf = (LPBYTE)xmalloc( cbData *2 );
2888 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2889 cbData=2*cbData;
2891 else
2892 buf=(LPBYTE)lpbData;
2894 if (lpszValueName)
2895 lpszValueNameW = strdupA2W(lpszValueName);
2896 else
2897 lpszValueNameW = NULL;
2899 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2901 if (lpszValueNameW)
2902 free(lpszValueNameW);
2904 if (buf!=lpbData)
2905 free(buf);
2907 return ret;
2911 /******************************************************************************
2912 * RegSetValueEx16 [KERNEL.226]
2914 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2915 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2917 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2918 dwReserved,dwType,lpbData,cbData);
2919 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2920 cbData );
2924 /******************************************************************************
2925 * RegSetValue32W [ADVAPI32.171]
2927 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2928 LPCWSTR lpszData, DWORD cbData )
2930 HKEY xhkey;
2931 DWORD ret;
2933 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2934 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2936 if (lpszSubKey && *lpszSubKey) {
2937 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2938 if (ret!=ERROR_SUCCESS)
2939 return ret;
2940 } else
2941 xhkey=hkey;
2942 if (dwType!=REG_SZ) {
2943 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2944 dwType=REG_SZ;
2946 if (cbData!=2*lstrlenW(lpszData)+2) {
2947 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2948 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2950 cbData=2*lstrlenW(lpszData)+2;
2952 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2953 if (hkey!=xhkey)
2954 RegCloseKey(xhkey);
2955 return ret;
2959 /******************************************************************************
2960 * RegSetValue32A [ADVAPI32.168]
2963 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2964 LPCSTR lpszData, DWORD cbData )
2966 DWORD ret;
2967 HKEY xhkey;
2969 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2970 if (lpszSubKey && *lpszSubKey) {
2971 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2972 if (ret!=ERROR_SUCCESS)
2973 return ret;
2974 } else
2975 xhkey=hkey;
2977 if (dwType!=REG_SZ) {
2978 TRACE_(reg)("dwType=%ld!\n",dwType);
2979 dwType=REG_SZ;
2981 if (cbData!=strlen(lpszData)+1)
2982 cbData=strlen(lpszData)+1;
2983 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2984 if (xhkey!=hkey)
2985 RegCloseKey(xhkey);
2986 return ret;
2990 /******************************************************************************
2991 * RegSetValue16 [KERNEL.221] [SHELL.5]
2993 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2994 LPCSTR lpszData, DWORD cbData )
2996 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2997 debugstr_a(lpszData),cbData);
2998 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
3003 * Key Enumeration
3005 * Callpath:
3006 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
3007 * RegEnumKey32W -> RegEnumKeyEx32W
3011 /******************************************************************************
3012 * RegEnumKeyEx32W [ADVAPI32.139]
3014 * PARAMS
3015 * hkey [I] Handle to key to enumerate
3016 * iSubKey [I] Index of subkey to enumerate
3017 * lpszName [O] Buffer for subkey name
3018 * lpcchName [O] Size of subkey buffer
3019 * lpdwReserved [I] Reserved
3020 * lpszClass [O] Buffer for class string
3021 * lpcchClass [O] Size of class buffer
3022 * ft [O] Time key last written to
3024 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3025 LPDWORD lpcchName, LPDWORD lpdwReserved,
3026 LPWSTR lpszClass, LPDWORD lpcchClass,
3027 FILETIME *ft )
3029 LPKEYSTRUCT lpkey,lpxkey;
3031 TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3032 lpcchName,lpcchName? *lpcchName : -1,lpdwReserved,lpszClass,
3033 lpcchClass,ft);
3035 lpkey = lookup_hkey( hkey );
3036 if (!lpkey)
3037 return ERROR_INVALID_HANDLE;
3039 if (!lpcchName)
3040 return ERROR_INVALID_PARAMETER;
3042 if (!lpkey->nextsub)
3043 return ERROR_NO_MORE_ITEMS;
3044 lpxkey=lpkey->nextsub;
3046 /* Traverse the subkeys */
3047 while (iSubkey && lpxkey) {
3048 iSubkey--;
3049 lpxkey=lpxkey->next;
3052 if (iSubkey || !lpxkey)
3053 return ERROR_NO_MORE_ITEMS;
3054 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3055 *lpcchName = lstrlenW(lpxkey->keyname);
3056 return ERROR_MORE_DATA;
3058 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3059 *lpcchName = lstrlenW(lpszName);
3061 if (lpszClass) {
3062 /* FIXME: what should we write into it? */
3063 *lpszClass = 0;
3064 *lpcchClass = 2;
3066 return ERROR_SUCCESS;
3070 /******************************************************************************
3071 * RegEnumKeyW [ADVAPI32.140]
3073 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3074 DWORD lpcchName )
3076 DWORD ret;
3077 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3078 ret = RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,NULL);
3080 /* If lpszName is NULL then we have a slightly different behaviour than
3081 RegEnumKeyExW */
3082 if(lpszName == NULL && ret == ERROR_MORE_DATA)
3083 ret = ERROR_SUCCESS;
3085 return ret;
3089 /******************************************************************************
3090 * RegEnumKeyEx32A [ADVAPI32.138]
3092 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3093 LPDWORD lpcchName, LPDWORD lpdwReserved,
3094 LPSTR lpszClass, LPDWORD lpcchClass,
3095 FILETIME *ft )
3097 DWORD ret;
3098 LPWSTR lpszNameW, lpszClassW;
3100 TRACE_(reg)("(%x,%ld,%p,%p(%ld),%p,%p,%p,%p)\n",
3101 hkey,iSubkey,lpszName,lpcchName,lpcchName? *lpcchName : -1,
3102 lpdwReserved,lpszClass,lpcchClass,ft);
3104 lpszNameW = lpszName ? (LPWSTR)xmalloc(*lpcchName * 2) : NULL;
3105 lpszClassW = lpszClass ? (LPWSTR)xmalloc(*lpcchClass * 2) : NULL;
3107 ret = RegEnumKeyExW(hkey, iSubkey, lpszNameW, lpcchName, lpdwReserved,
3108 lpszClassW, lpcchClass, ft);
3110 if (ret == ERROR_SUCCESS) {
3111 lstrcpyWtoA(lpszName,lpszNameW);
3112 if (lpszClassW)
3113 lstrcpyWtoA(lpszClass,lpszClassW);
3115 if (lpszNameW)
3116 free(lpszNameW);
3117 if (lpszClassW)
3118 free(lpszClassW);
3119 return ret;
3123 /******************************************************************************
3124 * RegEnumKeyA [ADVAPI32.137]
3126 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3127 DWORD lpcchName )
3129 DWORD ret;
3130 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3131 ret = RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3132 NULL, NULL );
3134 /* If lpszName is NULL then we have a slightly different behaviour than
3135 RegEnumKeyExA */
3136 if(lpszName == NULL && ret == ERROR_MORE_DATA)
3137 ret = ERROR_SUCCESS;
3139 return ret;
3143 /******************************************************************************
3144 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3146 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3147 DWORD lpcchName )
3149 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3150 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3155 * Enumerate Registry Values
3157 * Callpath:
3158 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3162 /******************************************************************************
3163 * RegEnumValue32W [ADVAPI32.142]
3165 * PARAMS
3166 * hkey [I] Handle to key to query
3167 * iValue [I] Index of value to query
3168 * lpszValue [O] Value string
3169 * lpcchValue [I/O] Size of value buffer (in wchars)
3170 * lpdReserved [I] Reserved
3171 * lpdwType [O] Type code
3172 * lpbData [O] Value data
3173 * lpcbData [I/O] Size of data buffer (in bytes)
3175 * Note: wide character functions that take and/or return "character counts"
3176 * use TCHAR (that is unsigned short or char) not byte counts.
3178 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3179 LPDWORD lpcchValue, LPDWORD lpdReserved,
3180 LPDWORD lpdwType, LPBYTE lpbData,
3181 LPDWORD lpcbData )
3183 LPKEYSTRUCT lpkey;
3184 LPKEYVALUE val;
3186 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3187 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3189 lpkey = lookup_hkey( hkey );
3191 if (!lpcbData && lpbData)
3192 return ERROR_INVALID_PARAMETER;
3194 if (!lpkey)
3195 return ERROR_INVALID_HANDLE;
3197 if (lpkey->nrofvalues <= iValue)
3198 return ERROR_NO_MORE_ITEMS;
3200 val = &(lpkey->values[iValue]);
3202 if (val->name) {
3203 if (lstrlenW(val->name)+1>*lpcchValue) {
3204 *lpcchValue = lstrlenW(val->name)+1;
3205 return ERROR_MORE_DATA;
3207 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3208 *lpcchValue=lstrlenW(val->name);
3209 } else {
3210 *lpszValue = 0;
3211 *lpcchValue = 0;
3214 /* Can be NULL if the type code is not required */
3215 if (lpdwType)
3216 *lpdwType = val->type;
3218 if (lpbData) {
3219 if (val->len>*lpcbData) {
3220 *lpcbData = val->len;
3221 return ERROR_MORE_DATA;
3223 memcpy(lpbData,val->data,val->len);
3224 *lpcbData = val->len;
3227 debug_print_value ( val->data, val );
3228 return ERROR_SUCCESS;
3232 /******************************************************************************
3233 * RegEnumValue32A [ADVAPI32.141]
3235 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3236 LPDWORD lpcchValue, LPDWORD lpdReserved,
3237 LPDWORD lpdwType, LPBYTE lpbData,
3238 LPDWORD lpcbData )
3240 LPWSTR lpszValueW;
3241 LPBYTE lpbDataW;
3242 DWORD ret,lpcbDataW;
3243 DWORD dwType;
3245 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3246 lpdReserved,lpdwType,lpbData,lpcbData);
3248 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3249 if (lpbData) {
3250 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3251 lpcbDataW = *lpcbData;
3252 } else
3253 lpbDataW = NULL;
3255 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3256 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3258 if (lpdwType)
3259 *lpdwType = dwType;
3261 if (ret==ERROR_SUCCESS) {
3262 lstrcpyWtoA(lpszValue,lpszValueW);
3263 if (lpbData) {
3264 if ((1<<dwType) & UNICONVMASK) {
3265 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3266 } else {
3267 if (lpcbDataW > *lpcbData) {
3268 *lpcbData = lpcbDataW;
3269 ret = ERROR_MORE_DATA;
3270 } else
3271 memcpy(lpbData,lpbDataW,lpcbDataW);
3273 *lpcbData = lpcbDataW;
3276 if (lpbDataW) free(lpbDataW);
3277 if (lpszValueW) free(lpszValueW);
3278 return ret;
3282 /******************************************************************************
3283 * RegEnumValue16 [KERNEL.223]
3285 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3286 LPDWORD lpcchValue, LPDWORD lpdReserved,
3287 LPDWORD lpdwType, LPBYTE lpbData,
3288 LPDWORD lpcbData )
3290 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3291 lpdReserved,lpdwType,lpbData,lpcbData);
3292 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3293 lpdwType, lpbData, lpcbData );
3297 /******************************************************************************
3298 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3299 * Releases the handle of the specified key
3301 * PARAMS
3302 * hkey [I] Handle of key to close
3304 * RETURNS
3305 * Success: ERROR_SUCCESS
3306 * Failure: Error code
3308 DWORD WINAPI RegCloseKey( HKEY hkey )
3310 TRACE_(reg)("(%x)\n",hkey);
3312 /* The standard handles are allowed to succeed, even though they are not
3313 closed */
3314 if (is_standard_hkey(hkey))
3315 return ERROR_SUCCESS;
3317 return remove_handle(hkey);
3322 * Delete registry key
3324 * Callpath:
3325 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3329 /******************************************************************************
3330 * RegDeleteKey32W [ADVAPI32.134]
3332 * PARAMS
3333 * hkey [I] Handle to open key
3334 * lpszSubKey [I] Name of subkey to delete
3336 * RETURNS
3337 * Success: ERROR_SUCCESS
3338 * Failure: Error code
3340 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3342 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3343 LPWSTR *wps;
3344 int wpc,i;
3346 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3348 lpNextKey = lookup_hkey(hkey);
3349 if (!lpNextKey)
3350 return ERROR_INVALID_HANDLE;
3352 /* Subkey param cannot be NULL */
3353 if (!lpszSubKey || !*lpszSubKey)
3354 return ERROR_BADKEY;
3356 /* We need to know the previous key in the hier. */
3357 split_keypath(lpszSubKey,&wps,&wpc);
3358 i = 0;
3359 lpxkey = lpNextKey;
3360 while (i<wpc-1) {
3361 lpxkey=lpNextKey->nextsub;
3362 while (lpxkey) {
3363 TRACE_(reg)(" Scanning [%s]\n",
3364 debugstr_w(lpxkey->keyname));
3365 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3366 break;
3367 lpxkey=lpxkey->next;
3369 if (!lpxkey) {
3370 FREE_KEY_PATH;
3371 TRACE_(reg)(" Not found.\n");
3372 /* not found is success */
3373 return ERROR_SUCCESS;
3375 i++;
3376 lpNextKey = lpxkey;
3378 lpxkey = lpNextKey->nextsub;
3379 lplpPrevKey = &(lpNextKey->nextsub);
3380 while (lpxkey) {
3381 TRACE_(reg)(" Scanning [%s]\n",
3382 debugstr_w(lpxkey->keyname));
3383 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3384 break;
3385 lplpPrevKey = &(lpxkey->next);
3386 lpxkey = lpxkey->next;
3389 if (!lpxkey) {
3390 FREE_KEY_PATH;
3391 WARN_(reg)(" Not found.\n");
3392 return ERROR_FILE_NOT_FOUND;
3395 if (lpxkey->nextsub) {
3396 FREE_KEY_PATH;
3397 WARN_(reg)(" Not empty.\n");
3398 return ERROR_CANTWRITE;
3400 *lplpPrevKey = lpxkey->next;
3401 free(lpxkey->keyname);
3402 if (lpxkey->class)
3403 free(lpxkey->class);
3404 if (lpxkey->values)
3405 free(lpxkey->values);
3406 free(lpxkey);
3407 FREE_KEY_PATH;
3408 TRACE_(reg)(" Done.\n");
3409 return ERROR_SUCCESS;
3413 /******************************************************************************
3414 * RegDeleteKey32A [ADVAPI32.133]
3416 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3418 LPWSTR lpszSubKeyW;
3419 DWORD ret;
3421 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3422 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3423 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3424 if(lpszSubKeyW) free(lpszSubKeyW);
3425 return ret;
3429 /******************************************************************************
3430 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3432 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3434 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3435 return RegDeleteKeyA( hkey, lpszSubKey );
3440 * Delete registry value
3442 * Callpath:
3443 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3447 /******************************************************************************
3448 * RegDeleteValue32W [ADVAPI32.136]
3450 * PARAMS
3451 * hkey [I]
3452 * lpszValue [I]
3454 * RETURNS
3456 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3458 DWORD i;
3459 LPKEYSTRUCT lpkey;
3460 LPKEYVALUE val;
3462 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3464 lpkey = lookup_hkey( hkey );
3465 if (!lpkey)
3466 return ERROR_INVALID_HANDLE;
3468 if (lpszValue) {
3469 for (i=0;i<lpkey->nrofvalues;i++)
3470 if ( lpkey->values[i].name &&
3471 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3473 break;
3474 } else {
3475 for (i=0;i<lpkey->nrofvalues;i++)
3476 if (lpkey->values[i].name==NULL)
3477 break;
3480 if (i == lpkey->nrofvalues)
3481 return ERROR_FILE_NOT_FOUND;
3483 val = lpkey->values+i;
3484 if (val->name) free(val->name);
3485 if (val->data) free(val->data);
3486 memcpy(
3487 lpkey->values+i,
3488 lpkey->values+i+1,
3489 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3491 lpkey->values = (LPKEYVALUE)xrealloc(
3492 lpkey->values,
3493 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3495 lpkey->nrofvalues--;
3496 return ERROR_SUCCESS;
3500 /******************************************************************************
3501 * RegDeleteValue32A [ADVAPI32.135]
3503 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3505 LPWSTR lpszValueW;
3506 DWORD ret;
3508 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3509 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3510 ret = RegDeleteValueW( hkey, lpszValueW );
3511 if(lpszValueW) free(lpszValueW);
3512 return ret;
3516 /******************************************************************************
3517 * RegDeleteValue16 [KERNEL.222]
3519 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3521 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3522 return RegDeleteValueA( hkey, lpszValue );
3526 /******************************************************************************
3527 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3528 * Immediately writes key to registry.
3529 * Only returns after data has been written to disk.
3531 * FIXME: does it really wait until data is written ?
3533 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3534 * written if this function really works (and only if !).
3536 * PARAMS
3537 * hkey [I] Handle of key to write
3539 * RETURNS
3540 * Success: ERROR_SUCCESS
3541 * Failure: Error code
3543 DWORD WINAPI RegFlushKey( HKEY hkey )
3545 LPKEYSTRUCT lpkey;
3547 TRACE_(reg)("(%x)\n", hkey);
3549 lpkey = lookup_hkey( hkey );
3550 if (!lpkey)
3551 return ERROR_BADKEY;
3553 SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3554 return ERROR_SUCCESS;
3558 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3561 /******************************************************************************
3562 * RegQueryInfoKey32W [ADVAPI32.153]
3564 * PARAMS
3565 * hkey [I] Handle to key to query
3566 * lpszClass [O] Buffer for class string
3567 * lpcchClass [O] Size of class string buffer
3568 * lpdwReserved [I] Reserved
3569 * lpcSubKeys [I] Buffer for number of subkeys
3570 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3571 * lpcchMaxClass [O] Buffer for longest class string length
3572 * lpcValues [O] Buffer for number of value entries
3573 * lpcchMaxValueName [O] Buffer for longest value name length
3574 * lpccbMaxValueData [O] Buffer for longest value data length
3575 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3576 * ft
3577 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3578 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3579 * lpcchClass is NULL
3580 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3581 * (it's hard to test validity, so test !NULL instead)
3583 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3584 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3585 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3586 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3587 LPDWORD lpcchMaxValueName,
3588 LPDWORD lpccbMaxValueData,
3589 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3591 LPKEYSTRUCT lpkey,lpxkey;
3592 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3593 int i;
3595 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3596 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3597 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3598 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3600 lpkey = lookup_hkey(hkey);
3601 if (!lpkey)
3602 return ERROR_INVALID_HANDLE;
3603 if (lpszClass) {
3604 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3605 return ERROR_INVALID_PARAMETER;
3607 /* either lpcchClass is valid or this is win95 and lpcchClass
3608 could be invalid */
3609 if (lpkey->class) {
3610 DWORD classLen = lstrlenW(lpkey->class);
3612 if (lpcchClass && classLen+1>*lpcchClass) {
3613 *lpcchClass=classLen+1;
3614 return ERROR_MORE_DATA;
3616 if (lpcchClass)
3617 *lpcchClass=classLen;
3618 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3619 } else {
3620 *lpszClass = 0;
3621 if (lpcchClass)
3622 *lpcchClass = 0;
3624 } else {
3625 if (lpcchClass)
3626 *lpcchClass = lstrlenW(lpkey->class);
3628 lpxkey=lpkey->nextsub;
3629 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3630 while (lpxkey) {
3631 nrofkeys++;
3632 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3633 maxsubkey=lstrlenW(lpxkey->keyname);
3634 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3635 maxclass=lstrlenW(lpxkey->class);
3636 lpxkey=lpxkey->next;
3638 for (i=0;i<lpkey->nrofvalues;i++) {
3639 LPKEYVALUE val=lpkey->values+i;
3641 if (val->name && lstrlenW(val->name)>maxvname)
3642 maxvname=lstrlenW(val->name);
3643 if (val->len>maxvdata)
3644 maxvdata=val->len;
3646 if (!maxclass) maxclass = 1;
3647 if (!maxvname) maxvname = 1;
3648 if (lpcValues)
3649 *lpcValues = lpkey->nrofvalues;
3650 if (lpcSubKeys)
3651 *lpcSubKeys = nrofkeys;
3652 if (lpcchMaxSubkey)
3653 *lpcchMaxSubkey = maxsubkey;
3654 if (lpcchMaxClass)
3655 *lpcchMaxClass = maxclass;
3656 if (lpcchMaxValueName)
3657 *lpcchMaxValueName= maxvname;
3658 if (lpccbMaxValueData)
3659 *lpccbMaxValueData= maxvdata;
3660 return ERROR_SUCCESS;
3664 /******************************************************************************
3665 * RegQueryInfoKey32A [ADVAPI32.152]
3667 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3668 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3669 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3670 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3671 LPDWORD lpccbMaxValueData,
3672 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3674 LPWSTR lpszClassW = NULL;
3675 DWORD ret;
3677 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3678 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3679 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3680 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3682 if (lpszClass) {
3683 if (lpcchClass) {
3684 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3685 } else if (VERSION_GetVersion() == WIN95) {
3686 /* win95 allows lpcchClass to be null */
3687 /* we don't know how big lpszClass is, would
3688 MAX_PATHNAME_LEN be the correct default? */
3689 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3692 } else
3693 lpszClassW = NULL;
3694 ret=RegQueryInfoKeyW(
3695 hkey,
3696 lpszClassW,
3697 lpcchClass,
3698 lpdwReserved,
3699 lpcSubKeys,
3700 lpcchMaxSubkey,
3701 lpcchMaxClass,
3702 lpcValues,
3703 lpcchMaxValueName,
3704 lpccbMaxValueData,
3705 lpcbSecurityDescriptor,
3708 if (ret==ERROR_SUCCESS && lpszClass)
3709 lstrcpyWtoA(lpszClass,lpszClassW);
3710 if (lpszClassW)
3711 free(lpszClassW);
3712 return ret;
3716 /******************************************************************************
3717 * RegConnectRegistry32W [ADVAPI32.128]
3719 * PARAMS
3720 * lpMachineName [I] Address of name of remote computer
3721 * hHey [I] Predefined registry handle
3722 * phkResult [I] Address of buffer for remote registry handle
3724 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3725 LPHKEY phkResult )
3727 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3729 if (!lpMachineName || !*lpMachineName) {
3730 /* Use the local machine name */
3731 return RegOpenKey16( hKey, "", phkResult );
3734 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3735 return ERROR_BAD_NETPATH;
3739 /******************************************************************************
3740 * RegConnectRegistry32A [ADVAPI32.127]
3742 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3744 DWORD ret;
3745 LPWSTR machineW = strdupA2W(machine);
3746 ret = RegConnectRegistryW( machineW, hkey, reskey );
3747 free(machineW);
3748 return ret;
3752 /******************************************************************************
3753 * RegGetKeySecurity [ADVAPI32.144]
3754 * Retrieves a copy of security descriptor protecting the registry key
3756 * PARAMS
3757 * hkey [I] Open handle of key to set
3758 * SecurityInformation [I] Descriptor contents
3759 * pSecurityDescriptor [O] Address of descriptor for key
3760 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3762 * RETURNS
3763 * Success: ERROR_SUCCESS
3764 * Failure: Error code
3766 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3767 SECURITY_INFORMATION SecurityInformation,
3768 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3769 LPDWORD lpcbSecurityDescriptor )
3771 LPKEYSTRUCT lpkey;
3773 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3774 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3776 lpkey = lookup_hkey( hkey );
3777 if (!lpkey)
3778 return ERROR_INVALID_HANDLE;
3780 /* FIXME: Check for valid SecurityInformation values */
3782 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3783 return ERROR_INSUFFICIENT_BUFFER;
3785 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3786 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3788 return ERROR_SUCCESS;
3792 /******************************************************************************
3793 * RegLoadKey32W [ADVAPI32.???]
3795 * PARAMS
3796 * hkey [I] Handle of open key
3797 * lpszSubKey [I] Address of name of subkey
3798 * lpszFile [I] Address of filename for registry information
3800 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3802 LPKEYSTRUCT lpkey;
3803 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3805 /* Do this check before the hkey check */
3806 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3807 return ERROR_INVALID_PARAMETER;
3809 lpkey = lookup_hkey( hkey );
3810 if (!lpkey)
3811 return ERROR_INVALID_HANDLE;
3813 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3814 debugstr_w(lpszFile));
3816 return ERROR_SUCCESS;
3820 /******************************************************************************
3821 * RegLoadKey32A [ADVAPI32.???]
3823 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3825 LONG ret;
3826 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3827 LPWSTR lpszFileW = strdupA2W(lpszFile);
3828 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3829 if(lpszFileW) free(lpszFileW);
3830 if(lpszSubKeyW) free(lpszSubKeyW);
3831 return ret;
3835 /******************************************************************************
3836 * RegNotifyChangeKeyValue [ADVAPI32.???]
3838 * PARAMS
3839 * hkey [I] Handle of key to watch
3840 * fWatchSubTree [I] Flag for subkey notification
3841 * fdwNotifyFilter [I] Changes to be reported
3842 * hEvent [I] Handle of signaled event
3843 * fAsync [I] Flag for asynchronous reporting
3845 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3846 DWORD fdwNotifyFilter, HANDLE hEvent,
3847 BOOL fAsync )
3849 LPKEYSTRUCT lpkey;
3850 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3851 hEvent,fAsync);
3853 lpkey = lookup_hkey( hkey );
3854 if (!lpkey)
3855 return ERROR_INVALID_HANDLE;
3857 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3858 hEvent,fAsync);
3860 return ERROR_SUCCESS;
3864 /******************************************************************************
3865 * RegUnLoadKey32W [ADVAPI32.173]
3867 * PARAMS
3868 * hkey [I] Handle of open key
3869 * lpSubKey [I] Address of name of subkey to unload
3871 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3873 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3874 return ERROR_SUCCESS;
3878 /******************************************************************************
3879 * RegUnLoadKey32A [ADVAPI32.172]
3881 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3883 LONG ret;
3884 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3885 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3886 if(lpSubKeyW) free(lpSubKeyW);
3887 return ret;
3891 /******************************************************************************
3892 * RegSetKeySecurity [ADVAPI32.167]
3894 * PARAMS
3895 * hkey [I] Open handle of key to set
3896 * SecurityInfo [I] Descriptor contents
3897 * pSecurityDesc [I] Address of descriptor for key
3899 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3900 PSECURITY_DESCRIPTOR pSecurityDesc )
3902 LPKEYSTRUCT lpkey;
3904 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3906 /* It seems to perform this check before the hkey check */
3907 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3908 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3909 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3910 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3911 /* Param OK */
3912 } else
3913 return ERROR_INVALID_PARAMETER;
3915 if (!pSecurityDesc)
3916 return ERROR_INVALID_PARAMETER;
3918 lpkey = lookup_hkey( hkey );
3919 if (!lpkey)
3920 return ERROR_INVALID_HANDLE;
3922 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3924 return ERROR_SUCCESS;
3928 /******************************************************************************
3929 * RegSaveKey32W [ADVAPI32.166]
3931 * PARAMS
3932 * hkey [I] Handle of key where save begins
3933 * lpFile [I] Address of filename to save to
3934 * sa [I] Address of security structure
3936 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3937 LPSECURITY_ATTRIBUTES sa )
3939 LPKEYSTRUCT lpkey;
3941 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3943 /* It appears to do this check before the hkey check */
3944 if (!lpFile || !*lpFile)
3945 return ERROR_INVALID_PARAMETER;
3947 lpkey = lookup_hkey( hkey );
3948 if (!lpkey)
3949 return ERROR_INVALID_HANDLE;
3951 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3953 return ERROR_SUCCESS;
3957 /******************************************************************************
3958 * RegSaveKey32A [ADVAPI32.165]
3960 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3961 LPSECURITY_ATTRIBUTES sa )
3963 LONG ret;
3964 LPWSTR lpFileW = strdupA2W(lpFile);
3965 ret = RegSaveKeyW( hkey, lpFileW, sa );
3966 free(lpFileW);
3967 return ret;
3971 /******************************************************************************
3972 * RegRestoreKey32W [ADVAPI32.164]
3974 * PARAMS
3975 * hkey [I] Handle of key where restore begins
3976 * lpFile [I] Address of filename containing saved tree
3977 * dwFlags [I] Optional flags
3979 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3981 LPKEYSTRUCT lpkey;
3983 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3985 /* It seems to do this check before the hkey check */
3986 if (!lpFile || !*lpFile)
3987 return ERROR_INVALID_PARAMETER;
3989 lpkey = lookup_hkey( hkey );
3990 if (!lpkey)
3991 return ERROR_INVALID_HANDLE;
3993 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3995 /* Check for file existence */
3997 return ERROR_SUCCESS;
4001 /******************************************************************************
4002 * RegRestoreKey32A [ADVAPI32.163]
4004 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4006 LONG ret;
4007 LPWSTR lpFileW = strdupA2W(lpFile);
4008 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4009 if(lpFileW) free(lpFileW);
4010 return ret;
4014 /******************************************************************************
4015 * RegReplaceKey32W [ADVAPI32.162]
4017 * PARAMS
4018 * hkey [I] Handle of open key
4019 * lpSubKey [I] Address of name of subkey
4020 * lpNewFile [I] Address of filename for file with new data
4021 * lpOldFile [I] Address of filename for backup file
4023 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4024 LPCWSTR lpOldFile )
4026 LPKEYSTRUCT lpkey;
4028 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4029 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4031 lpkey = lookup_hkey( hkey );
4032 if (!lpkey)
4033 return ERROR_INVALID_HANDLE;
4035 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
4036 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4038 return ERROR_SUCCESS;
4042 /******************************************************************************
4043 * RegReplaceKey32A [ADVAPI32.161]
4045 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4046 LPCSTR lpOldFile )
4048 LONG ret;
4049 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4050 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4051 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4052 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4053 free(lpOldFileW);
4054 free(lpNewFileW);
4055 free(lpSubKeyW);
4056 return ret;