Added support for icons in property sheet tabs.
[wine/testsucceed.git] / misc / registry.c
blobf163ae0913957a58392ba10346117f3872c43fe4
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_ERRNO_H
28 #include <sys/errno.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
32 #include <sys/stat.h>
33 #include <assert.h>
34 #include <time.h>
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/winbase16.h"
38 #include "wine/winestring.h"
39 #include "winerror.h"
40 #include "file.h"
41 #include "heap.h"
42 #include "debugtools.h"
43 #include "xmalloc.h"
44 #include "options.h"
45 #include "winreg.h"
46 #include "winversion.h"
48 DECLARE_DEBUG_CHANNEL(reg)
49 DECLARE_DEBUG_CHANNEL(string)
51 static void REGISTRY_Init(void);
52 /* FIXME: following defines should be configured global ... */
54 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
55 #define WINE_PREFIX "/.wine"
56 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
57 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
59 /* relative in ~user/.wine/ : */
60 #define SAVE_CURRENT_USER "user.reg"
61 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
62 #define SAVE_LOCAL_MACHINE "system.reg"
64 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
65 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
67 /* one value of a key */
68 typedef struct tagKEYVALUE
70 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
71 DWORD type; /* type of value */
72 DWORD len; /* length of data in BYTEs */
73 DWORD lastmodified; /* time of seconds since 1.1.1970 */
74 LPBYTE data; /* content, may be strings, binaries, etc. */
75 } KEYVALUE,*LPKEYVALUE;
77 /* a registry key */
78 typedef struct tagKEYSTRUCT
80 LPWSTR keyname; /* name of THIS key (UNICODE) */
81 DWORD flags; /* flags. */
82 LPWSTR class;
83 /* values */
84 DWORD nrofvalues; /* nr of values in THIS key */
85 LPKEYVALUE values; /* values in THIS key */
86 /* key management pointers */
87 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
88 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
89 } KEYSTRUCT, *LPKEYSTRUCT;
92 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
93 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
94 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
95 static KEYSTRUCT *key_users=NULL; /* all users? */
97 /* dynamic, not saved */
98 static KEYSTRUCT *key_performance_data=NULL;
99 static KEYSTRUCT *key_current_config=NULL;
100 static KEYSTRUCT *key_dyn_data=NULL;
102 /* what valuetypes do we need to convert? */
103 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
106 static struct openhandle {
107 LPKEYSTRUCT lpkey;
108 HKEY hkey;
109 REGSAM accessmask;
110 } *openhandles=NULL;
111 static int nrofopenhandles=0;
112 /* Starts after 1 because 0,1 are reserved for Win16 */
113 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
114 HKEYs for remote registry access */
115 static int currenthandle=2;
119 * QUESTION
120 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
121 * If so, can we remove them?
122 * ANSWER
123 * No, the memory handling functions are called very often in here,
124 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
125 * loading 100 times slower. -MM
127 static LPWSTR strdupA2W(LPCSTR src)
129 if(src) {
130 LPWSTR dest=xmalloc(2*strlen(src)+2);
131 lstrcpyAtoW(dest,src);
132 return dest;
134 return NULL;
137 static LPWSTR strdupW(LPCWSTR a) {
138 LPWSTR b;
139 int len;
141 if(a) {
142 len=sizeof(WCHAR)*(lstrlenW(a)+1);
143 b=(LPWSTR)xmalloc(len);
144 memcpy(b,a,len);
145 return b;
147 return NULL;
150 LPWSTR strcvtA2W(LPCSTR src, int nchars)
153 LPWSTR dest = xmalloc (2 * nchars + 2);
155 lstrcpynAtoW(dest,src,nchars+1);
156 dest[nchars] = 0;
157 return dest;
160 * we need to convert A to W with '\0' in strings (MULTI_SZ)
163 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
164 { LPWSTR p = dst;
166 TRACE_(reg)("\"%s\" %i\n",src, n);
168 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
170 return dst;
172 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
173 { LPSTR p = dst;
175 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
177 while (n-- > 0) *p++ = (CHAR)*src++;
179 return dst;
182 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
184 if (TRACE_ON(reg) && lpbData)
186 switch(key->type)
188 case REG_EXPAND_SZ:
189 case REG_SZ:
190 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
193 break;
195 case REG_DWORD:
196 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key->name),
198 (DWORD)*lpbData);
199 break;
201 case REG_MULTI_SZ:
203 int i;
204 LPCWSTR ptr = (LPCWSTR)lpbData;
205 for (i=0;ptr[0];i++)
207 TRACE_(reg)(" Value %s, MULTI_SZ(%i=%s)\n",
208 debugstr_w(key->name),
210 debugstr_w(ptr));
212 ptr += lstrlenW(ptr)+1;
215 break;
217 default:
219 char szTemp[100]; /* 3*32 + 3 + 1 */
220 int i;
221 for ( i = 0; i < key->len ; i++)
223 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
224 if (i>=31)
226 sprintf (&(szTemp[i*3+3]),"...");
227 break;
230 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
231 debugstr_w(key->name),
232 szTemp);
234 } /* switch */
235 } /* if */
239 /******************************************************************************
240 * is_standard_hkey [Internal]
241 * Determines if a hkey is a standard key
243 static BOOL is_standard_hkey( HKEY hkey )
245 switch(hkey) {
246 case 0x00000000:
247 case 0x00000001:
248 case HKEY_CLASSES_ROOT:
249 case HKEY_CURRENT_CONFIG:
250 case HKEY_CURRENT_USER:
251 case HKEY_LOCAL_MACHINE:
252 case HKEY_USERS:
253 case HKEY_PERFORMANCE_DATA:
254 case HKEY_DYN_DATA:
255 return TRUE;
256 default:
257 return FALSE;
261 /******************************************************************************
262 * add_handle [Internal]
264 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
266 int i;
268 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
269 /* Check for duplicates */
270 for (i=0;i<nrofopenhandles;i++) {
271 if (openhandles[i].lpkey==lpkey) {
272 /* This is not really an error - the user is allowed to create
273 two (or more) handles to the same key */
274 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
276 if (openhandles[i].hkey==hkey) {
277 WARN_(reg)("Adding handle %x twice\n",hkey);
280 openhandles=xrealloc( openhandles,
281 sizeof(struct openhandle)*(nrofopenhandles+1));
283 openhandles[i].lpkey = lpkey;
284 openhandles[i].hkey = hkey;
285 openhandles[i].accessmask = accessmask;
286 nrofopenhandles++;
290 /******************************************************************************
291 * get_handle [Internal]
293 * RETURNS
294 * Success: Pointer to key
295 * Failure: NULL
297 static LPKEYSTRUCT get_handle( HKEY hkey )
299 int i;
301 for (i=0; i<nrofopenhandles; i++)
302 if (openhandles[i].hkey == hkey)
303 return openhandles[i].lpkey;
304 WARN_(reg)("Could not find handle 0x%x\n",hkey);
305 return NULL;
309 /******************************************************************************
310 * remove_handle [Internal]
312 * PARAMS
313 * hkey [I] Handle of key to remove
315 * RETURNS
316 * Success: ERROR_SUCCESS
317 * Failure: ERROR_INVALID_HANDLE
319 static DWORD remove_handle( HKEY hkey )
321 int i;
323 for (i=0;i<nrofopenhandles;i++)
324 if (openhandles[i].hkey==hkey)
325 break;
327 if (i == nrofopenhandles) {
328 WARN_(reg)("Could not find handle 0x%x\n",hkey);
329 return ERROR_INVALID_HANDLE;
332 memcpy( openhandles+i,
333 openhandles+i+1,
334 sizeof(struct openhandle)*(nrofopenhandles-i-1)
336 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
337 nrofopenhandles--;
338 return ERROR_SUCCESS;
341 /******************************************************************************
342 * lookup_hkey [Internal]
344 * Just as the name says. Creates the root keys on demand, so we can call the
345 * Reg* functions at any time.
347 * RETURNS
348 * Success: Pointer to key structure
349 * Failure: NULL
351 #define ADD_ROOT_KEY(xx) \
352 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
353 memset(xx,'\0',sizeof(KEYSTRUCT));\
354 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
356 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
358 switch (hkey) {
359 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
360 * some programs. Do not remove those cases. -MM
362 case 0x00000000:
363 case 0x00000001:
364 case HKEY_CLASSES_ROOT:
366 if (!key_classes_root)
368 HKEY cl_r_hkey;
370 /* calls lookup_hkey recursively, TWICE */
371 if ( RegCreateKey16(
372 HKEY_LOCAL_MACHINE,
373 "SOFTWARE\\Classes",
374 &cl_r_hkey) != ERROR_SUCCESS)
376 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
377 exit(1);
380 key_classes_root = lookup_hkey(cl_r_hkey);
382 return key_classes_root;
385 case HKEY_CURRENT_USER:
386 if (!key_current_user) {
387 ADD_ROOT_KEY(key_current_user);
389 return key_current_user;
391 case HKEY_LOCAL_MACHINE:
392 if (!key_local_machine) {
393 ADD_ROOT_KEY(key_local_machine);
394 REGISTRY_Init();
396 return key_local_machine;
398 case HKEY_USERS:
399 if (!key_users) {
400 ADD_ROOT_KEY(key_users);
402 return key_users;
404 case HKEY_PERFORMANCE_DATA:
405 if (!key_performance_data) {
406 ADD_ROOT_KEY(key_performance_data);
408 return key_performance_data;
410 case HKEY_DYN_DATA:
411 if (!key_dyn_data) {
412 ADD_ROOT_KEY(key_dyn_data);
414 return key_dyn_data;
416 case HKEY_CURRENT_CONFIG:
417 if (!key_current_config) {
418 ADD_ROOT_KEY(key_current_config);
420 return key_current_config;
422 default:
423 return get_handle(hkey);
426 /*NOTREACHED*/
431 * recursively searches for lpkey_to_find in the root key branch
432 * given in lpcurrkey.
434 static int subkey_found(LPKEYSTRUCT lpcurrkey, LPKEYSTRUCT lpkey_to_find)
436 if (lpcurrkey == lpkey_to_find)
437 return 1;
439 while (lpcurrkey)
441 if (subkey_found(lpcurrkey->nextsub, lpkey_to_find))
442 return 1;
444 lpcurrkey = lpcurrkey->next;
447 TRACE_(reg)("No key found in this root key branch\n");
448 return 0;
453 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
455 static HKEY find_root_key(LPKEYSTRUCT lpkey)
457 typedef struct tagROOT_KEYS {
458 KEYSTRUCT *lpkey;
459 HKEY hkey;
460 } ROOT_KEYS;
461 ROOT_KEYS root_keys[] = { { key_classes_root, HKEY_CLASSES_ROOT },
462 { key_current_user, HKEY_CURRENT_USER },
463 { key_local_machine, HKEY_LOCAL_MACHINE },
464 { key_users, HKEY_USERS } };
465 int i;
467 for (i=0; i<4;i++)
469 if (subkey_found(root_keys[i].lpkey, lpkey))
470 return root_keys[i].hkey;
472 ERR_(reg)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
473 return 0;
474 #undef ROOT_KEYS
476 #undef ADD_ROOT_KEY
477 /* so we don't accidently access them ... */
478 #define key_current_config NULL NULL
479 #define key_current_user NULL NULL
480 #define key_users NULL NULL
481 #define key_local_machine NULL NULL
482 #define key_classes_root NULL NULL
483 #define key_dyn_data NULL NULL
484 #define key_performance_data NULL NULL
486 /******************************************************************************
487 * split_keypath [Internal]
488 * splits the unicode string 'wp' into an array of strings.
489 * the array is allocated by this function.
490 * Free the array using FREE_KEY_PATH
492 * PARAMS
493 * wp [I] String to split up
494 * wpv [O] Array of pointers to strings
495 * wpc [O] Number of components
497 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
499 int i,j,len;
500 LPWSTR ws;
502 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
504 ws = HEAP_strdupW( SystemHeap, 0, wp );
506 /* We know we have at least one substring */
507 *wpc = 1;
509 /* Replace each backslash with NULL, and increment the count */
510 for (i=0;ws[i];i++) {
511 if (ws[i]=='\\') {
512 ws[i]=0;
513 (*wpc)++;
517 len = i;
519 /* Allocate the space for the array of pointers, leaving room for the
520 NULL at the end */
521 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
522 (*wpv)[0]= ws;
524 /* Assign each pointer to the appropriate character in the string */
525 j = 1;
526 for (i=1;i<len;i++)
527 if (ws[i-1]==0) {
528 (*wpv)[j++]=ws+i;
529 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
532 (*wpv)[j]=NULL;
534 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
539 /******************************************************************************
540 * REGISTRY_Init [Internal]
541 * Registry initialisation, allocates some default keys.
543 static void REGISTRY_Init(void) {
544 HKEY hkey;
545 char buf[200];
547 TRACE_(reg)("(void)\n");
549 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
550 RegCloseKey(hkey);
552 /* This was an Open, but since it is called before the real registries
553 are loaded, it was changed to a Create - MTB 980507*/
554 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
555 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
556 RegCloseKey(hkey);
558 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
559 * CurrentVersion
560 * CurrentBuildNumber
561 * CurrentType
562 * string RegisteredOwner
563 * string RegisteredOrganization
566 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
567 * string SysContact
568 * string SysLocation
569 * SysServices
571 if (-1!=gethostname(buf,200)) {
572 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
573 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
574 RegCloseKey(hkey);
579 /************************ SAVE Registry Function ****************************/
581 #define REGISTRY_SAVE_VERSION 0x00000001
583 /* Registry saveformat:
584 * If you change it, increase above number by 1, which will flush
585 * old registry database files.
587 * Global:
588 * "WINE REGISTRY Version %d"
589 * subkeys....
590 * Subkeys:
591 * keyname
592 * valuename=lastmodified,type,data
593 * ...
594 * subkeys
595 * ...
596 * keyname,valuename,stringdata:
597 * the usual ascii characters from 0x00-0xff (well, not 0x00)
598 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
599 * ( "=\\\t" escaped in \uXXXX form.)
600 * type,lastmodified:
601 * int
603 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
605 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
606 * SaveOnlyUpdatedKeys=yes
609 /******************************************************************************
610 * _save_check_tainted [Internal]
612 static int _save_check_tainted( LPKEYSTRUCT lpkey )
614 int tainted;
616 if (!lpkey)
617 return 0;
618 if (lpkey->flags & REG_OPTION_TAINTED)
619 tainted = 1;
620 else
621 tainted = 0;
622 while (lpkey) {
623 if (_save_check_tainted(lpkey->nextsub)) {
624 lpkey->flags |= REG_OPTION_TAINTED;
625 tainted = 1;
627 lpkey = lpkey->next;
629 return tainted;
632 /******************************************************************************
633 * _save_USTRING [Internal]
635 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
637 LPWSTR s;
638 int doescape;
640 if (wstr==NULL)
641 return;
642 s=wstr;
643 while (*s) {
644 doescape=0;
645 if (*s>0xff)
646 doescape = 1;
647 if (*s=='\n')
648 doescape = 1;
649 if (escapeeq && *s=='=')
650 doescape = 1;
651 if (*s=='\\')
652 fputc(*s,F); /* if \\ then put it twice. */
653 if (doescape)
654 fprintf(F,"\\u%04x",*((unsigned short*)s));
655 else
656 fputc(*s,F);
657 s++;
661 /******************************************************************************
662 * _savesubkey [Internal]
664 * NOTES
665 * REG_MULTI_SZ is handled as binary (like in win95) (js)
667 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
669 LPKEYSTRUCT lpxkey;
670 int i,tabs,j;
672 lpxkey = lpkey;
673 while (lpxkey) {
674 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
675 (all || (lpxkey->flags & REG_OPTION_TAINTED))
677 for (tabs=level;tabs--;)
678 fputc('\t',F);
679 _save_USTRING(F,lpxkey->keyname,1);
680 fputs("\n",F);
681 for (i=0;i<lpxkey->nrofvalues;i++) {
682 LPKEYVALUE val=lpxkey->values+i;
684 for (tabs=level+1;tabs--;)
685 fputc('\t',F);
686 _save_USTRING(F,val->name,0);
687 fputc('=',F);
688 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
689 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
690 _save_USTRING(F,(LPWSTR)val->data,0);
691 else
692 for (j=0;j<val->len;j++)
693 fprintf(F,"%02x",*((unsigned char*)val->data+j));
694 fputs("\n",F);
696 /* descend recursively */
697 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
698 return 0;
700 lpxkey=lpxkey->next;
702 return 1;
706 /******************************************************************************
707 * _savesubreg [Internal]
709 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
711 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
712 _save_check_tainted(lpkey->nextsub);
713 return _savesubkey(F,lpkey->nextsub,0,all);
717 /******************************************************************************
718 * _savereg [Internal]
720 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
722 FILE *F;
724 F=fopen(fn,"w");
725 if (F==NULL) {
726 WARN_(reg)("Couldn't open %s for writing: %s\n",
727 fn,strerror(errno)
729 return FALSE;
731 if (!_savesubreg(F,lpkey,all)) {
732 fclose(F);
733 unlink(fn);
734 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
735 return FALSE;
737 fclose(F);
738 return TRUE;
742 /******************************************************************************
743 * SHELL_SaveRegistryBranch [Internal]
745 * Saves main registry branch specified by hkey.
747 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
749 char *fn, *home, *tmp;
751 /* FIXME: does this check apply to all keys written below ? */
752 if (!(home = getenv( "HOME" )))
754 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
755 return;
758 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
759 if (hkey == HKEY_CLASSES_ROOT)
760 hkey = HKEY_LOCAL_MACHINE;
762 switch (hkey)
764 case HKEY_CURRENT_USER:
766 int usedCfgUser = 0;
768 fn = xmalloc( MAX_PATHNAME_LEN );
769 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "",
770 fn, MAX_PATHNAME_LEN - 1))
772 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
773 usedCfgUser = 1;
775 free (fn);
777 if (usedCfgUser != 1)
779 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
780 strlen(SAVE_CURRENT_USER) + 2 );
781 strcpy(fn,home);
782 strcat(fn,WINE_PREFIX);
784 /* create the directory. don't care about errorcodes. */
785 mkdir(fn,0755); /* drwxr-xr-x */
786 strcat(fn,"/"SAVE_CURRENT_USER);
788 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
789 strcpy(tmp,fn);
790 strcat(tmp,".tmp");
792 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
793 if (-1==rename(tmp,fn)) {
794 perror("rename tmp registry");
795 unlink(tmp);
798 free(tmp);
799 free(fn);
802 break;
803 case HKEY_LOCAL_MACHINE:
805 int usedCfgLM = 0;
806 /* Try first saving according to the defined location in .winerc */
807 fn = xmalloc ( MAX_PATHNAME_LEN);
808 if (PROFILE_GetWineIniString ( "Registry",
809 "LocalMachineFileName", "", fn, MAX_PATHNAME_LEN - 1))
811 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
812 usedCfgLM = 1;
814 free (fn);
816 if ( usedCfgLM != 1)
818 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
819 strlen(SAVE_LOCAL_MACHINE) + 2);
820 strcpy(fn,home);
821 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
823 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
824 strcpy(tmp,fn);
825 strcat(tmp,".tmp");
827 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
828 if (-1==rename(tmp,fn)) {
829 perror("rename tmp registry");
830 unlink(tmp);
833 free(tmp);
834 free(fn);
837 break;
838 case HKEY_USERS:
839 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
840 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
842 strcpy(fn,home);
843 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
845 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
846 strcpy(tmp,fn);strcat(tmp,".tmp");
847 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
848 if (-1==rename(tmp,fn)) {
849 perror("rename tmp registry");
850 unlink(tmp);
853 free(tmp);
854 free(fn);
855 break;
856 default:
857 ERR_(reg)("unknown/invalid key handle !\n");
862 /******************************************************************************
863 * SHELL_SaveRegistry [Internal]
865 void SHELL_SaveRegistry( void )
867 char buf[4];
868 HKEY hkey;
869 int all;
871 TRACE_(reg)("(void)\n");
873 all=0;
874 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
876 strcpy(buf,"yes");
878 else
880 DWORD len,junk,type;
882 len=4;
883 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
884 VAL_SAVEUPDATED,
885 &junk,
886 &type,
887 buf,
888 &len)) || (type!=REG_SZ))
890 strcpy(buf,"yes");
892 RegCloseKey(hkey);
895 if (lstrcmpiA(buf,"yes"))
896 all = 1;
898 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
899 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
900 SHELL_SaveRegistryBranch(HKEY_USERS, all);
904 /************************ LOAD Registry Function ****************************/
908 /******************************************************************************
909 * _find_or_add_key [Internal]
911 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
913 LPKEYSTRUCT lpxkey,*lplpkey;
915 if ((!keyname) || (keyname[0]==0)) {
916 free(keyname);
917 return lpkey;
919 lplpkey= &(lpkey->nextsub);
920 lpxkey = *lplpkey;
921 while (lpxkey) {
922 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
923 !lstrcmpiW(lpxkey->keyname,keyname)
925 break;
926 lplpkey = &(lpxkey->next);
927 lpxkey = *lplpkey;
929 if (lpxkey==NULL) {
930 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
931 lpxkey = *lplpkey;
932 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
933 lpxkey->keyname = keyname;
934 } else
935 free(keyname);
936 return lpxkey;
939 /******************************************************************************
940 * _find_or_add_value [Internal]
942 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
943 LPBYTE data, DWORD len, DWORD lastmodified )
945 LPKEYVALUE val=NULL;
946 int i;
948 if (name && !*name) {/* empty string equals default (NULL) value */
949 free(name);
950 name = NULL;
953 for (i=0;i<lpkey->nrofvalues;i++) {
954 val=lpkey->values+i;
955 if (name==NULL) {
956 if (val->name==NULL)
957 break;
958 } else {
959 if ( val->name!=NULL &&
960 tolower(val->name[0])==tolower(name[0]) &&
961 !lstrcmpiW(val->name,name)
963 break;
966 if (i==lpkey->nrofvalues) {
967 lpkey->values = xrealloc(
968 lpkey->values,
969 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
971 val=lpkey->values+i;
972 memset(val,'\0',sizeof(KEYVALUE));
973 val->name = name;
974 } else {
975 if (name)
976 free(name);
978 if (val->lastmodified<lastmodified) {
979 val->lastmodified=lastmodified;
980 val->type = type;
982 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
984 data=xmalloc(sizeof(WCHAR));
985 memset(data,0,sizeof(WCHAR));
986 len =sizeof(WCHAR);
989 val->len = len;
990 if (val->data)
991 free(val->data);
992 val->data = data;
993 } else
994 free(data);
998 /******************************************************************************
999 * _wine_read_line [Internal]
1001 * reads a line including dynamically enlarging the readbuffer and throwing
1002 * away comments
1004 static int _wine_read_line( FILE *F, char **buf, int *len )
1006 char *s,*curread;
1007 int mylen,curoff;
1009 curread = *buf;
1010 mylen = *len;
1011 **buf = '\0';
1012 while (1) {
1013 while (1) {
1014 s=fgets(curread,mylen,F);
1015 if (s==NULL)
1016 return 0; /* EOF */
1017 if (NULL==(s=strchr(curread,'\n'))) {
1018 /* buffer wasn't large enough */
1019 curoff = strlen(*buf);
1020 *buf = xrealloc(*buf,*len*2);
1021 curread = *buf + curoff;
1022 mylen = *len; /* we filled up the buffer and
1023 * got new '*len' bytes to fill
1025 *len = *len * 2;
1026 } else {
1027 *s='\0';
1028 break;
1031 /* throw away comments */
1032 if (**buf=='#' || **buf==';') {
1033 curread = *buf;
1034 mylen = *len;
1035 continue;
1037 if (s) /* got end of line */
1038 break;
1040 return 1;
1044 /******************************************************************************
1045 * _wine_read_USTRING [Internal]
1047 * converts a char* into a UNICODE string (up to a special char)
1048 * and returns the position exactly after that string
1050 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1052 char *s;
1053 LPWSTR ws;
1055 /* read up to "=" or "\0" or "\n" */
1056 s = buf;
1057 if (*s == '=') {
1058 /* empty string is the win3.1 default value(NULL)*/
1059 *str = NULL;
1060 return s;
1062 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1063 ws = *str;
1064 while (*s && (*s!='\n') && (*s!='=')) {
1065 if (*s!='\\')
1066 *ws++=*((unsigned char*)s++);
1067 else {
1068 s++;
1069 if (!*s) {
1070 /* Dangling \ ... may only happen if a registry
1071 * write was short. FIXME: What do to?
1073 break;
1075 if (*s=='\\') {
1076 *ws++='\\';
1077 s++;
1078 continue;
1080 if (*s!='u') {
1081 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1082 *ws++='\\';
1083 *ws++=*s++;
1084 } else {
1085 char xbuf[5];
1086 int wc;
1088 s++;
1089 memcpy(xbuf,s,4);xbuf[4]='\0';
1090 if (!sscanf(xbuf,"%x",&wc))
1091 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1092 s+=4;
1093 *ws++ =(unsigned short)wc;
1097 *ws = 0;
1098 ws = *str;
1099 if (*ws)
1100 *str = strdupW(*str);
1101 else
1102 *str = NULL;
1103 free(ws);
1104 return s;
1108 /******************************************************************************
1109 * _wine_loadsubkey [Internal]
1111 * NOTES
1112 * It seems like this is returning a boolean. Should it?
1114 * RETURNS
1115 * Success: 1
1116 * Failure: 0
1118 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1119 int *buflen, DWORD optflag )
1121 LPKEYSTRUCT lpxkey;
1122 int i;
1123 char *s;
1124 LPWSTR name;
1126 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1127 *buflen, optflag);
1129 lpkey->flags |= optflag;
1131 /* Good. We already got a line here ... so parse it */
1132 lpxkey = NULL;
1133 while (1) {
1134 i=0;s=*buf;
1135 while (*s=='\t') {
1136 s++;
1137 i++;
1139 if (i>level) {
1140 if (lpxkey==NULL) {
1141 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1142 return 0;
1144 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1145 continue;
1148 /* let the caller handle this line */
1149 if (i<level || **buf=='\0')
1150 return 1;
1152 /* it can be: a value or a keyname. Parse the name first */
1153 s=_wine_read_USTRING(s,&name);
1155 /* switch() default: hack to avoid gotos */
1156 switch (0) {
1157 default:
1158 if (*s=='\0') {
1159 lpxkey=_find_or_add_key(lpkey,name);
1160 } else {
1161 LPBYTE data;
1162 int len,lastmodified,type;
1164 if (*s!='=') {
1165 WARN_(reg)("Unexpected character: %c\n",*s);
1166 break;
1168 s++;
1169 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1170 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1171 break;
1173 /* skip the 2 , */
1174 s=strchr(s,',');s++;
1175 s=strchr(s,',');s++;
1176 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1177 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1178 if (data)
1179 len = lstrlenW((LPWSTR)data)*2+2;
1180 else
1181 len = 0;
1182 } else {
1183 len=strlen(s)/2;
1184 data = (LPBYTE)xmalloc(len+1);
1185 for (i=0;i<len;i++) {
1186 data[i]=0;
1187 if (*s>='0' && *s<='9')
1188 data[i]=(*s-'0')<<4;
1189 if (*s>='a' && *s<='f')
1190 data[i]=(*s-'a'+'\xa')<<4;
1191 if (*s>='A' && *s<='F')
1192 data[i]=(*s-'A'+'\xa')<<4;
1193 s++;
1194 if (*s>='0' && *s<='9')
1195 data[i]|=*s-'0';
1196 if (*s>='a' && *s<='f')
1197 data[i]|=*s-'a'+'\xa';
1198 if (*s>='A' && *s<='F')
1199 data[i]|=*s-'A'+'\xa';
1200 s++;
1203 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1206 /* read the next line */
1207 if (!_wine_read_line(F,buf,buflen))
1208 return 1;
1210 return 1;
1214 /******************************************************************************
1215 * _wine_loadsubreg [Internal]
1217 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1219 int ver;
1220 char *buf;
1221 int buflen;
1223 buf=xmalloc(10);buflen=10;
1224 if (!_wine_read_line(F,&buf,&buflen)) {
1225 free(buf);
1226 return 0;
1228 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1229 free(buf);
1230 return 0;
1232 if (ver!=REGISTRY_SAVE_VERSION) {
1233 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1234 free(buf);
1235 return 0;
1237 if (!_wine_read_line(F,&buf,&buflen)) {
1238 free(buf);
1239 return 0;
1241 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1242 free(buf);
1243 return 0;
1245 free(buf);
1246 return 1;
1250 /******************************************************************************
1251 * _wine_loadreg [Internal]
1253 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1255 FILE *F;
1257 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1259 F = fopen(fn,"rb");
1260 if (F==NULL) {
1261 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1262 return;
1264 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1265 fclose(F);
1266 unlink(fn);
1267 return;
1269 fclose(F);
1272 /******************************************************************************
1273 * _flush_registry [Internal]
1275 * This function allow to flush section of the internal registry. It is mainly
1276 * implements to fix a problem with the global HKU and the local HKU.
1277 * Those two files are read to build the HKU\.Default branch to finaly copy
1278 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1279 * all the global HKU are saved onto the user's personal version of HKU hive.
1280 * which is bad...
1283 /* Forward declaration of recusive agent */
1284 static void _flush_reg(LPKEYSTRUCT from);
1286 static void _flush_registry( LPKEYSTRUCT from )
1288 /* make sure we have something... */
1289 if (from == NULL)
1290 return;
1292 /* Launch the recusive agent on sub branches */
1293 _flush_reg( from->nextsub );
1294 _flush_reg( from->next );
1296 /* Initialize pointers */
1297 from->nextsub = NULL;
1298 from->next = NULL;
1300 static void _flush_reg( LPKEYSTRUCT from )
1302 int j;
1304 /* make sure we have something... */
1305 if (from == NULL)
1306 return;
1309 * do the same for the child keys
1311 if (from->nextsub != NULL)
1312 _flush_reg(from->nextsub);
1315 * do the same for the sibling keys
1317 if (from->next != NULL)
1318 _flush_reg(from->next);
1321 * iterate through this key's values and delete them
1323 for (j=0;j<from->nrofvalues;j++)
1325 free( (from->values+j)->name);
1326 free( (from->values+j)->data);
1330 * free the structure
1332 if ( from != NULL )
1333 free(from);
1337 /******************************************************************************
1338 * _copy_registry [Internal]
1340 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1342 LPKEYSTRUCT lpxkey;
1343 int j;
1344 LPKEYVALUE valfrom;
1346 from=from->nextsub;
1347 while (from) {
1348 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1350 for (j=0;j<from->nrofvalues;j++) {
1351 LPWSTR name;
1352 LPBYTE data;
1354 valfrom = from->values+j;
1355 name=valfrom->name;
1356 if (name) name=strdupW(name);
1357 data=(LPBYTE)xmalloc(valfrom->len);
1358 memcpy(data,valfrom->data,valfrom->len);
1360 _find_or_add_value(
1361 lpxkey,
1362 name,
1363 valfrom->type,
1364 data,
1365 valfrom->len,
1366 valfrom->lastmodified
1369 _copy_registry(from,lpxkey);
1370 from = from->next;
1375 /* WINDOWS 95 REGISTRY LOADER */
1377 * Structure of a win95 registry database.
1378 * main header:
1379 * 0 : "CREG" - magic
1380 * 4 : DWORD version
1381 * 8 : DWORD offset_of_RGDB_part
1382 * 0C..0F: ? (someone fill in please)
1383 * 10: WORD number of RGDB blocks
1384 * 12: WORD ?
1385 * 14: WORD always 0000?
1386 * 16: WORD always 0001?
1387 * 18..1F: ? (someone fill in please)
1389 * 20: RGKN_section:
1390 * header:
1391 * 0 : "RGKN" - magic
1392 * 4 : DWORD offset to first RGDB section
1393 * 8 : DWORD offset to the root record
1394 * C..0x1B: ? (fill in)
1395 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1397 * Disk Key Entry Structure:
1398 * 00: DWORD - Free entry indicator(?)
1399 * 04: DWORD - Hash = sum of bytes of keyname
1400 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1401 * 0C: DWORD - disk address of PreviousLevel Key.
1402 * 10: DWORD - disk address of Next Sublevel Key.
1403 * 14: DWORD - disk address of Next Key (on same level).
1404 * DKEP>18: WORD - Nr, Low Significant part.
1405 * 1A: WORD - Nr, High Significant part.
1407 * The disk address always points to the nr part of the previous key entry
1408 * of the referenced key. Don't ask me why, or even if I got this correct
1409 * from staring at 1kg of hexdumps. (DKEP)
1411 * The High significant part of the structure seems to equal the number
1412 * of the RGDB section. The low significant part is a unique ID within
1413 * that RGDB section
1415 * There are two minor corrections to the position of that structure.
1416 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1417 * the DKE reread from there.
1418 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1419 * CPS - I have not experienced the above phenomenon in my registry files
1421 * RGDB_section:
1422 * 00: "RGDB" - magic
1423 * 04: DWORD offset to next RGDB section
1424 * 08: DWORD ?
1425 * 0C: WORD always 000d?
1426 * 0E: WORD RGDB block number
1427 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1428 * 14..1F: ?
1429 * 20.....: disk keys
1431 * disk key:
1432 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1433 * 08: WORD nrLS - low significant part of NR
1434 * 0A: WORD nrHS - high significant part of NR
1435 * 0C: DWORD bytesused - bytes used in this structure.
1436 * 10: WORD name_len - length of name in bytes. without \0
1437 * 12: WORD nr_of_values - number of values.
1438 * 14: char name[name_len] - name string. No \0.
1439 * 14+name_len: disk values
1440 * nextkeyoffset: ... next disk key
1442 * disk value:
1443 * 00: DWORD type - value type (hmm, could be WORD too)
1444 * 04: DWORD - unknown, usually 0
1445 * 08: WORD namelen - length of Name. 0 means name=NULL
1446 * 0C: WORD datalen - length of Data.
1447 * 10: char name[namelen] - name, no \0
1448 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1449 * 10+namelen+datalen: next values or disk key
1451 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1452 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1453 * structure) and reading another RGDB_section.
1454 * repeat until end of file.
1456 * An interesting relationship exists in RGDB_section. The value at offset
1457 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1458 * idea at the moment what this means. (Kevin Cozens)
1460 * FIXME: this description needs some serious help, yes.
1463 struct _w95keyvalue {
1464 unsigned long type;
1465 unsigned short datalen;
1466 char *name;
1467 unsigned char *data;
1468 unsigned long x1;
1469 int lastmodified;
1472 struct _w95key {
1473 char *name;
1474 int nrofvals;
1475 struct _w95keyvalue *values;
1476 struct _w95key *prevlvl;
1477 struct _w95key *nextsub;
1478 struct _w95key *next;
1482 struct _w95_info {
1483 char *rgknbuffer;
1484 int rgknsize;
1485 char *rgdbbuffer;
1486 int rgdbsize;
1487 int depth;
1488 int lastmodified;
1492 /******************************************************************************
1493 * _w95_processKey [Internal]
1495 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1496 int nrLS, int nrMS, struct _w95_info *info )
1499 /* Disk Key Header structure (RGDB part) */
1500 struct dkh {
1501 unsigned long nextkeyoff;
1502 unsigned short nrLS;
1503 unsigned short nrMS;
1504 unsigned long bytesused;
1505 unsigned short keynamelen;
1506 unsigned short values;
1507 unsigned long xx1;
1508 /* keyname */
1509 /* disk key values or nothing */
1511 /* Disk Key Value structure */
1512 struct dkv {
1513 unsigned long type;
1514 unsigned long x1;
1515 unsigned short valnamelen;
1516 unsigned short valdatalen;
1517 /* valname, valdata */
1521 struct dkh dkh;
1522 int bytesread = 0;
1523 char *rgdbdata = info->rgdbbuffer;
1524 int nbytes = info->rgdbsize;
1525 char *curdata = rgdbdata;
1526 char *end = rgdbdata + nbytes;
1527 int off_next_rgdb;
1528 char *next = rgdbdata;
1529 int nrgdb, i;
1530 LPKEYSTRUCT lpxkey;
1532 do {
1533 curdata = next;
1534 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1536 memcpy(&off_next_rgdb,curdata+4,4);
1537 next = curdata + off_next_rgdb;
1538 nrgdb = (int) *((short *)curdata + 7);
1540 } while (nrgdb != nrMS && (next < end));
1542 /* curdata now points to the start of the right RGDB section */
1543 curdata += 0x20;
1545 #define XREAD(whereto,len) \
1546 if ((curdata + len) <= end) {\
1547 memcpy(whereto,curdata,len);\
1548 curdata+=len;\
1549 bytesread+=len;\
1552 while (curdata < next) {
1553 struct dkh *xdkh = (struct dkh*)curdata;
1555 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1556 if (xdkh->nrLS == nrLS) {
1557 memcpy(&dkh,xdkh,sizeof(dkh));
1558 curdata += sizeof(dkh);
1559 break;
1561 curdata += xdkh->nextkeyoff;
1564 if (dkh.nrLS != nrLS) return (NULL);
1566 if (nrgdb != dkh.nrMS)
1567 return (NULL);
1569 assert((dkh.keynamelen<2) || curdata[0]);
1570 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1571 curdata += dkh.keynamelen;
1573 for (i=0;i< dkh.values; i++) {
1574 struct dkv dkv;
1575 LPBYTE data;
1576 int len;
1577 LPWSTR name;
1579 XREAD(&dkv,sizeof(dkv));
1581 name = strcvtA2W(curdata, dkv.valnamelen);
1582 curdata += dkv.valnamelen;
1584 if ((1 << dkv.type) & UNICONVMASK) {
1585 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1586 len = 2*(dkv.valdatalen + 1);
1587 } else {
1588 /* I don't think we want to NULL terminate all data */
1589 data = xmalloc(dkv.valdatalen);
1590 memcpy (data, curdata, dkv.valdatalen);
1591 len = dkv.valdatalen;
1594 curdata += dkv.valdatalen;
1596 _find_or_add_value(
1597 lpxkey,
1598 name,
1599 dkv.type,
1600 data,
1601 len,
1602 info->lastmodified
1605 return (lpxkey);
1608 /******************************************************************************
1609 * _w95_walkrgkn [Internal]
1611 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1612 struct _w95_info *info )
1615 /* Disk Key Entry structure (RGKN part) */
1616 struct dke {
1617 unsigned long x1;
1618 unsigned long x2;
1619 unsigned long x3;/*usually 0xFFFFFFFF */
1620 unsigned long prevlvl;
1621 unsigned long nextsub;
1622 unsigned long next;
1623 unsigned short nrLS;
1624 unsigned short nrMS;
1625 } *dke = (struct dke *)off;
1626 LPKEYSTRUCT lpxkey;
1628 if (dke == NULL) {
1629 dke = (struct dke *) ((char *)info->rgknbuffer);
1632 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1633 /* XXX <-- This is a hack*/
1634 if (!lpxkey) {
1635 lpxkey = prevkey;
1638 if (dke->nextsub != -1 &&
1639 ((dke->nextsub - 0x20) < info->rgknsize)
1640 && (dke->nextsub > 0x20)) {
1642 _w95_walkrgkn(lpxkey,
1643 info->rgknbuffer + dke->nextsub - 0x20,
1644 info);
1647 if (dke->next != -1 &&
1648 ((dke->next - 0x20) < info->rgknsize) &&
1649 (dke->next > 0x20)) {
1650 _w95_walkrgkn(prevkey,
1651 info->rgknbuffer + dke->next - 0x20,
1652 info);
1655 return;
1659 /******************************************************************************
1660 * _w95_loadreg [Internal]
1662 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1664 HFILE hfd;
1665 char magic[5];
1666 unsigned long where,version,rgdbsection,end;
1667 struct _w95_info info;
1668 OFSTRUCT ofs;
1669 BY_HANDLE_FILE_INFORMATION hfdinfo;
1671 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1672 hfd=OpenFile(fn,&ofs,OF_READ);
1673 if (hfd==HFILE_ERROR)
1674 return;
1675 magic[4]=0;
1676 if (4!=_lread(hfd,magic,4))
1677 return;
1678 if (strcmp(magic,"CREG")) {
1679 WARN_(reg)("%s is not a w95 registry.\n",fn);
1680 return;
1682 if (4!=_lread(hfd,&version,4))
1683 return;
1684 if (4!=_lread(hfd,&rgdbsection,4))
1685 return;
1686 if (-1==_llseek(hfd,0x20,SEEK_SET))
1687 return;
1688 if (4!=_lread(hfd,magic,4))
1689 return;
1690 if (strcmp(magic,"RGKN")) {
1691 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1692 return;
1695 /* STEP 1: Keylink structures */
1696 if (-1==_llseek(hfd,0x40,SEEK_SET))
1697 return;
1698 where = 0x40;
1699 end = rgdbsection;
1701 info.rgknsize = end - where;
1702 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1703 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1704 return;
1706 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1707 return;
1709 end = hfdinfo.nFileSizeLow;
1710 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1712 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1713 return;
1715 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1716 info.rgdbsize = end - rgdbsection;
1718 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1719 return;
1720 _lclose(hfd);
1722 _w95_walkrgkn(lpkey, NULL, &info);
1724 free (info.rgdbbuffer);
1725 free (info.rgknbuffer);
1729 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1732 reghack - windows 3.11 registry data format demo program.
1734 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1735 a combined hash table and tree description, and finally a text table.
1737 The header is obvious from the struct header. The taboff1 and taboff2
1738 fields are always 0x20, and their usage is unknown.
1740 The 8-byte entry table has various entry types.
1742 tabent[0] is a root index. The second word has the index of the root of
1743 the directory.
1744 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1745 the index of the key/value that has that hash. Data with the same
1746 hash value are on a circular list. The other three words in the
1747 hash entry are always zero.
1748 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1749 entry: dirent and keyent/valent. They are identified by context.
1750 tabent[freeidx] is the first free entry. The first word in a free entry
1751 is the index of the next free entry. The last has 0 as a link.
1752 The other three words in the free list are probably irrelevant.
1754 Entries in text table are preceeded by a word at offset-2. This word
1755 has the value (2*index)+1, where index is the referring keyent/valent
1756 entry in the table. I have no suggestion for the 2* and the +1.
1757 Following the word, there are N bytes of data, as per the keyent/valent
1758 entry length. The offset of the keyent/valent entry is from the start
1759 of the text table to the first data byte.
1761 This information is not available from Microsoft. The data format is
1762 deduced from the reg.dat file by me. Mistakes may
1763 have been made. I claim no rights and give no guarantees for this program.
1765 Tor Sjøwall, tor@sn.no
1768 /* reg.dat header format */
1769 struct _w31_header {
1770 char cookie[8]; /* 'SHCC3.10' */
1771 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1772 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1773 unsigned long tabcnt; /* number of entries in index table */
1774 unsigned long textoff; /* offset of text part */
1775 unsigned long textsize; /* byte size of text part */
1776 unsigned short hashsize; /* hash size */
1777 unsigned short freeidx; /* free index */
1780 /* generic format of table entries */
1781 struct _w31_tabent {
1782 unsigned short w0, w1, w2, w3;
1785 /* directory tabent: */
1786 struct _w31_dirent {
1787 unsigned short sibling_idx; /* table index of sibling dirent */
1788 unsigned short child_idx; /* table index of child dirent */
1789 unsigned short key_idx; /* table index of key keyent */
1790 unsigned short value_idx; /* table index of value valent */
1793 /* key tabent: */
1794 struct _w31_keyent {
1795 unsigned short hash_idx; /* hash chain index for string */
1796 unsigned short refcnt; /* reference count */
1797 unsigned short length; /* length of string */
1798 unsigned short string_off; /* offset of string in text table */
1801 /* value tabent: */
1802 struct _w31_valent {
1803 unsigned short hash_idx; /* hash chain index for string */
1804 unsigned short refcnt; /* reference count */
1805 unsigned short length; /* length of string */
1806 unsigned short string_off; /* offset of string in text table */
1809 /* recursive helper function to display a directory tree */
1810 void
1811 __w31_dumptree( unsigned short idx,
1812 unsigned char *txt,
1813 struct _w31_tabent *tab,
1814 struct _w31_header *head,
1815 LPKEYSTRUCT lpkey,
1816 time_t lastmodified,
1817 int level
1819 struct _w31_dirent *dir;
1820 struct _w31_keyent *key;
1821 struct _w31_valent *val;
1822 LPKEYSTRUCT xlpkey = NULL;
1823 LPWSTR name,value;
1824 static char tail[400];
1826 while (idx!=0) {
1827 dir=(struct _w31_dirent*)&tab[idx];
1829 if (dir->key_idx) {
1830 key = (struct _w31_keyent*)&tab[dir->key_idx];
1832 memcpy(tail,&txt[key->string_off],key->length);
1833 tail[key->length]='\0';
1834 /* all toplevel entries AND the entries in the
1835 * toplevel subdirectory belong to \SOFTWARE\Classes
1837 if (!level && !lstrcmpA(tail,".classes")) {
1838 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1839 idx=dir->sibling_idx;
1840 continue;
1842 name=strdupA2W(tail);
1844 xlpkey=_find_or_add_key(lpkey,name);
1846 /* only add if leaf node or valued node */
1847 if (dir->value_idx!=0||dir->child_idx==0) {
1848 if (dir->value_idx) {
1849 val=(struct _w31_valent*)&tab[dir->value_idx];
1850 memcpy(tail,&txt[val->string_off],val->length);
1851 tail[val->length]='\0';
1852 value=strdupA2W(tail);
1853 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1856 } else {
1857 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1859 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1860 idx=dir->sibling_idx;
1865 /******************************************************************************
1866 * _w31_loadreg [Internal]
1868 void _w31_loadreg(void) {
1869 HFILE hf;
1870 struct _w31_header head;
1871 struct _w31_tabent *tab;
1872 unsigned char *txt;
1873 int len;
1874 OFSTRUCT ofs;
1875 BY_HANDLE_FILE_INFORMATION hfinfo;
1876 time_t lastmodified;
1877 LPKEYSTRUCT lpkey;
1879 TRACE_(reg)("(void)\n");
1881 hf = OpenFile("reg.dat",&ofs,OF_READ);
1882 if (hf==HFILE_ERROR)
1883 return;
1885 /* read & dump header */
1886 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1887 ERR_(reg)("reg.dat is too short.\n");
1888 _lclose(hf);
1889 return;
1891 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1892 ERR_(reg)("reg.dat has bad signature.\n");
1893 _lclose(hf);
1894 return;
1897 len = head.tabcnt * sizeof(struct _w31_tabent);
1898 /* read and dump index table */
1899 tab = xmalloc(len);
1900 if (len!=_lread(hf,tab,len)) {
1901 ERR_(reg)("couldn't read %d bytes.\n",len);
1902 free(tab);
1903 _lclose(hf);
1904 return;
1907 /* read text */
1908 txt = xmalloc(head.textsize);
1909 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1910 ERR_(reg)("couldn't seek to textblock.\n");
1911 free(tab);
1912 free(txt);
1913 _lclose(hf);
1914 return;
1916 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1917 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1918 free(tab);
1919 free(txt);
1920 _lclose(hf);
1921 return;
1924 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1925 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1926 free(tab);
1927 free(txt);
1928 _lclose(hf);
1929 return;
1931 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1932 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1933 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1934 free(tab);
1935 free(txt);
1936 _lclose(hf);
1937 return;
1941 /**********************************************************************************
1942 * SHELL_LoadRegistry [Internal]
1944 void SHELL_LoadRegistry( void )
1946 char *fn, *home;
1947 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1948 HKEY hkey;
1950 TRACE_(reg)("(void)\n");
1952 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1953 HKU = lookup_hkey(HKEY_USERS);
1954 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1956 /* Load windows 3.1 entries */
1957 _w31_loadreg();
1958 /* Load windows 95 entries */
1959 _w95_loadreg("C:\\system.1st", HKLM);
1960 _w95_loadreg("system.dat", HKLM);
1961 _w95_loadreg("user.dat", HKU);
1964 * Load the global HKU hive directly from sysconfdir
1966 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1969 * Load the global machine defaults directly form sysconfdir
1971 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1974 * Load the user saved registries
1976 if ((home = getenv( "HOME" )))
1979 * Load user's personal versions of global HKU/.Default keys
1981 fn=(char*)xmalloc(
1982 strlen(home)+
1983 strlen(WINE_PREFIX)+
1984 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1986 strcpy(fn, home);
1987 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1988 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1989 free(fn);
1992 * Load HKCU, attempt to get the registry location from the config
1993 * file first, if exist, load and keep going.
1995 fn = xmalloc( MAX_PATHNAME_LEN );
1996 if ( PROFILE_GetWineIniString(
1997 "Registry",
1998 "UserFileName",
1999 "",
2000 fn,
2001 MAX_PATHNAME_LEN - 1))
2003 _wine_loadreg(HKCU,fn,0);
2005 free (fn);
2007 fn=(char*)xmalloc(
2008 strlen(home)+
2009 strlen(WINE_PREFIX)+
2010 strlen(SAVE_CURRENT_USER)+2);
2012 strcpy(fn, home);
2013 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2014 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2015 free(fn);
2018 * Load HKLM, attempt to get the registry location from the config
2019 * file first, if exist, load and keep going.
2021 fn = xmalloc ( MAX_PATHNAME_LEN);
2022 if ( PROFILE_GetWineIniString(
2023 "Registry",
2024 "LocalMachineFileName",
2025 "",
2026 fn,
2027 MAX_PATHNAME_LEN - 1))
2029 _wine_loadreg(HKLM, fn, 0);
2031 free(fn);
2033 fn=(char*)xmalloc(
2034 strlen(home)+
2035 strlen(WINE_PREFIX)+
2036 strlen(SAVE_LOCAL_MACHINE)+2);
2038 strcpy(fn,home);
2039 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2040 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2041 free(fn);
2043 else
2045 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
2049 * Obtain the handle of the HKU\.Default key.
2050 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2052 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2053 lpkey = lookup_hkey(hkey);
2054 if(!lpkey)
2055 WARN_(reg)("Could not create global user default key\n");
2056 else
2057 _copy_registry(lpkey, HKCU );
2059 RegCloseKey(hkey);
2062 * Since HKU is built from the global HKU and the local user HKU file we must
2063 * flush the HKU tree we have built at this point otherwise the part brought
2064 * in from the global HKU is saved into the local HKU. To avoid this
2065 * useless dupplication of HKU keys we reread the local HKU key.
2068 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2069 _flush_registry(HKU);
2071 /* Reload user's local HKU hive */
2072 if (home)
2074 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2075 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2077 strcpy(fn,home);
2078 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2080 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2082 free(fn);
2086 * Make sure the update mode is there
2088 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2090 DWORD junk,type,len;
2091 char data[5];
2093 len=4;
2094 if (( RegQueryValueExA(
2095 hkey,
2096 VAL_SAVEUPDATED,
2097 &junk,
2098 &type,
2099 data,
2100 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2102 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2105 RegCloseKey(hkey);
2110 /********************* API FUNCTIONS ***************************************/
2112 * Open Keys.
2114 * All functions are stubs to RegOpenKeyEx32W where all the
2115 * magic happens.
2117 * Callpath:
2118 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2119 * RegOpenKey32W -> RegOpenKeyEx32W
2123 /******************************************************************************
2124 * RegOpenKeyEx32W [ADVAPI32.150]
2125 * Opens the specified key
2127 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2129 * PARAMS
2130 * hkey [I] Handle of open key
2131 * lpszSubKey [I] Name of subkey to open
2132 * dwReserved [I] Reserved - must be zero
2133 * samDesired [I] Security access mask
2134 * retkey [O] Address of handle of open key
2136 * RETURNS
2137 * Success: ERROR_SUCCESS
2138 * Failure: Error code
2140 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2141 REGSAM samDesired, LPHKEY retkey )
2143 LPKEYSTRUCT lpNextKey,lpxkey;
2144 LPWSTR *wps;
2145 int wpc,i;
2147 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2148 samDesired,retkey);
2150 lpNextKey = lookup_hkey( hkey );
2151 if (!lpNextKey)
2152 return ERROR_INVALID_HANDLE;
2154 if (!lpszSubKey || !*lpszSubKey) {
2155 /* Either NULL or pointer to empty string, so return a new handle
2156 to the original hkey */
2157 currenthandle += 2;
2158 add_handle(currenthandle,lpNextKey,samDesired);
2159 *retkey=currenthandle;
2160 return ERROR_SUCCESS;
2163 if (lpszSubKey[0] == '\\') {
2164 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2165 return ERROR_BAD_PATHNAME;
2168 split_keypath(lpszSubKey,&wps,&wpc);
2169 i = 0;
2170 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2171 lpxkey = lpNextKey;
2173 while (wps[i]) {
2174 lpxkey=lpNextKey->nextsub;
2175 while (lpxkey) {
2176 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2177 break;
2179 lpxkey=lpxkey->next;
2182 if (!lpxkey) {
2183 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2184 FREE_KEY_PATH;
2185 return ERROR_FILE_NOT_FOUND;
2187 i++;
2188 lpNextKey = lpxkey;
2191 currenthandle += 2;
2192 add_handle(currenthandle,lpxkey,samDesired);
2193 *retkey = currenthandle;
2194 TRACE_(reg)(" Returning %x\n", currenthandle);
2195 FREE_KEY_PATH;
2196 return ERROR_SUCCESS;
2200 /******************************************************************************
2201 * RegOpenKeyEx32A [ADVAPI32.149]
2203 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2204 REGSAM samDesired, LPHKEY retkey )
2206 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2207 DWORD ret;
2209 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2210 samDesired,retkey);
2211 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2212 free(lpszSubKeyW);
2213 return ret;
2217 /******************************************************************************
2218 * RegOpenKey32W [ADVAPI32.151]
2220 * PARAMS
2221 * hkey [I] Handle of open key
2222 * lpszSubKey [I] Address of name of subkey to open
2223 * retkey [O] Address of handle of open key
2225 * RETURNS
2226 * Success: ERROR_SUCCESS
2227 * Failure: Error code
2229 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2231 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2232 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2236 /******************************************************************************
2237 * RegOpenKey32A [ADVAPI32.148]
2239 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2241 DWORD ret;
2242 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2243 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2244 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2245 free(lpszSubKeyW);
2246 return ret;
2250 /******************************************************************************
2251 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2253 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2255 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2256 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2261 * Create keys
2263 * All those functions convert their respective
2264 * arguments and call RegCreateKeyExW at the end.
2266 * We stay away from the Ex functions as long as possible because there are
2267 * differences in the return values
2269 * Callpath:
2270 * RegCreateKeyEx32A \
2271 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2275 /******************************************************************************
2276 * RegCreateKeyEx32W [ADVAPI32.131]
2278 * PARAMS
2279 * hkey [I] Handle of an open key
2280 * lpszSubKey [I] Address of subkey name
2281 * dwReserved [I] Reserved - must be 0
2282 * lpszClass [I] Address of class string
2283 * fdwOptions [I] Special options flag
2284 * samDesired [I] Desired security access
2285 * lpSecAttribs [I] Address of key security structure
2286 * retkey [O] Address of buffer for opened handle
2287 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2289 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2290 DWORD dwReserved, LPWSTR lpszClass,
2291 DWORD fdwOptions, REGSAM samDesired,
2292 LPSECURITY_ATTRIBUTES lpSecAttribs,
2293 LPHKEY retkey, LPDWORD lpDispos )
2295 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2296 LPWSTR *wps;
2297 int wpc,i;
2299 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2300 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2301 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2303 lpNextKey = lookup_hkey(hkey);
2304 if (!lpNextKey)
2305 return ERROR_INVALID_HANDLE;
2307 /* Check for valid options */
2308 switch(fdwOptions) {
2309 case REG_OPTION_NON_VOLATILE:
2310 case REG_OPTION_VOLATILE:
2311 case REG_OPTION_BACKUP_RESTORE:
2312 break;
2313 default:
2314 return ERROR_INVALID_PARAMETER;
2317 /* Sam has to be a combination of the following */
2318 if (!(samDesired &
2319 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2320 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2321 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2322 return ERROR_INVALID_PARAMETER;
2324 if (!lpszSubKey || !*lpszSubKey) {
2325 currenthandle += 2;
2326 add_handle(currenthandle,lpNextKey,samDesired);
2327 *retkey=currenthandle;
2328 TRACE_(reg)("Returning %x\n", currenthandle);
2329 lpNextKey->flags|=REG_OPTION_TAINTED;
2330 return ERROR_SUCCESS;
2333 if (lpszSubKey[0] == '\\') {
2334 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2335 return ERROR_BAD_PATHNAME;
2338 split_keypath(lpszSubKey,&wps,&wpc);
2339 i = 0;
2340 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2341 lpxkey = lpNextKey;
2342 while (wps[i]) {
2343 lpxkey=lpNextKey->nextsub;
2344 while (lpxkey) {
2345 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2346 break;
2347 lpxkey=lpxkey->next;
2349 if (!lpxkey)
2350 break;
2351 i++;
2352 lpNextKey = lpxkey;
2354 if (lpxkey) {
2355 currenthandle += 2;
2356 add_handle(currenthandle,lpxkey,samDesired);
2357 lpxkey->flags |= REG_OPTION_TAINTED;
2358 *retkey = currenthandle;
2359 TRACE_(reg)("Returning %x\n", currenthandle);
2360 if (lpDispos)
2361 *lpDispos = REG_OPENED_EXISTING_KEY;
2362 FREE_KEY_PATH;
2363 return ERROR_SUCCESS;
2366 /* Good. Now the hard part */
2367 while (wps[i]) {
2368 lplpPrevKey = &(lpNextKey->nextsub);
2369 lpxkey = *lplpPrevKey;
2370 while (lpxkey) {
2371 lplpPrevKey = &(lpxkey->next);
2372 lpxkey = *lplpPrevKey;
2374 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2375 if (!*lplpPrevKey) {
2376 FREE_KEY_PATH;
2377 TRACE_(reg)("Returning OUTOFMEMORY\n");
2378 return ERROR_OUTOFMEMORY;
2380 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2381 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2382 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2383 (*lplpPrevKey)->next = NULL;
2384 (*lplpPrevKey)->nextsub = NULL;
2385 (*lplpPrevKey)->values = NULL;
2386 (*lplpPrevKey)->nrofvalues = 0;
2387 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2388 if (lpszClass)
2389 (*lplpPrevKey)->class = strdupW(lpszClass);
2390 else
2391 (*lplpPrevKey)->class = NULL;
2392 lpNextKey = *lplpPrevKey;
2393 i++;
2395 currenthandle += 2;
2396 add_handle(currenthandle,lpNextKey,samDesired);
2398 /*FIXME: flag handling correct? */
2399 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2400 if (lpszClass)
2401 lpNextKey->class = strdupW(lpszClass);
2402 else
2403 lpNextKey->class = NULL;
2404 *retkey = currenthandle;
2405 TRACE_(reg)("Returning %x\n", currenthandle);
2406 if (lpDispos)
2407 *lpDispos = REG_CREATED_NEW_KEY;
2408 FREE_KEY_PATH;
2409 return ERROR_SUCCESS;
2413 /******************************************************************************
2414 * RegCreateKeyEx32A [ADVAPI32.130]
2416 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2417 LPSTR lpszClass, DWORD fdwOptions,
2418 REGSAM samDesired,
2419 LPSECURITY_ATTRIBUTES lpSecAttribs,
2420 LPHKEY retkey, LPDWORD lpDispos )
2422 LPWSTR lpszSubKeyW, lpszClassW;
2423 DWORD ret;
2425 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2426 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2427 retkey,lpDispos);
2429 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2430 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2432 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2433 fdwOptions, samDesired, lpSecAttribs, retkey,
2434 lpDispos );
2436 if(lpszSubKeyW) free(lpszSubKeyW);
2437 if(lpszClassW) free(lpszClassW);
2439 return ret;
2443 /******************************************************************************
2444 * RegCreateKey32W [ADVAPI32.132]
2446 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2448 DWORD junk;
2449 LPKEYSTRUCT lpNextKey;
2451 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2453 /* This check is here because the return value is different than the
2454 one from the Ex functions */
2455 lpNextKey = lookup_hkey(hkey);
2456 if (!lpNextKey)
2457 return ERROR_BADKEY;
2459 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2460 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2461 retkey, &junk);
2465 /******************************************************************************
2466 * RegCreateKey32A [ADVAPI32.129]
2468 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2470 DWORD ret;
2471 LPWSTR lpszSubKeyW;
2473 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2474 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2475 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2476 if(lpszSubKeyW) free(lpszSubKeyW);
2477 return ret;
2481 /******************************************************************************
2482 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2484 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2486 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2487 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2492 * Query Value Functions
2493 * Win32 differs between keynames and valuenames.
2494 * multiple values may belong to one key, the special value
2495 * with name NULL is the default value used by the win31
2496 * compat functions.
2498 * Callpath:
2499 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2500 * RegQueryValue32W -> RegQueryValueEx32W
2504 /******************************************************************************
2505 * RegQueryValueEx32W [ADVAPI32.158]
2506 * Retrieves type and data for a specified name associated with an open key
2508 * PARAMS
2509 * hkey [I] Handle of key to query
2510 * lpValueName [I] Name of value to query
2511 * lpdwReserved [I] Reserved - must be NULL
2512 * lpdwType [O] Address of buffer for value type. If NULL, the type
2513 * is not required.
2514 * lpbData [O] Address of data buffer. If NULL, the actual data is
2515 * not required.
2516 * lpcbData [I/O] Address of data buffer size
2518 * RETURNS
2519 * ERROR_SUCCESS: Success
2520 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2521 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2523 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2524 LPDWORD lpdwReserved, LPDWORD lpdwType,
2525 LPBYTE lpbData, LPDWORD lpcbData )
2527 LPKEYSTRUCT lpkey;
2528 int i;
2529 DWORD ret;
2531 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2532 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2534 lpkey = lookup_hkey(hkey);
2536 if (!lpkey)
2537 return ERROR_INVALID_HANDLE;
2539 if ((lpbData && ! lpcbData) || lpdwReserved)
2540 return ERROR_INVALID_PARAMETER;
2542 /* An empty name string is equivalent to NULL */
2543 if (lpValueName && !*lpValueName)
2544 lpValueName = NULL;
2546 if (lpValueName==NULL)
2547 { /* Use key's unnamed or default value, if any */
2548 for (i=0;i<lpkey->nrofvalues;i++)
2549 if (lpkey->values[i].name==NULL)
2550 break;
2552 else
2553 { /* Search for the key name */
2554 for (i=0;i<lpkey->nrofvalues;i++)
2555 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2556 break;
2559 if (i==lpkey->nrofvalues)
2560 { TRACE_(reg)(" Key not found\n");
2561 if (lpValueName==NULL)
2562 { /* Empty keyname not found */
2563 if (lpbData)
2564 { *(WCHAR*)lpbData = 0;
2565 *lpcbData = 2;
2567 if (lpdwType)
2568 *lpdwType = REG_SZ;
2569 TRACE_(reg)(" Returning an empty string\n");
2570 return ERROR_SUCCESS;
2572 return ERROR_FILE_NOT_FOUND;
2575 ret = ERROR_SUCCESS;
2577 if (lpdwType) /* type required ?*/
2578 *lpdwType = lpkey->values[i].type;
2580 if (lpbData) /* data required ?*/
2581 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2582 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2583 else {
2584 *lpcbData = lpkey->values[i].len;
2585 ret = ERROR_MORE_DATA;
2589 if (lpcbData) /* size required ?*/
2590 { *lpcbData = lpkey->values[i].len;
2593 debug_print_value ( lpbData, &lpkey->values[i]);
2595 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2597 return ret;
2601 /******************************************************************************
2602 * RegQueryValue32W [ADVAPI32.159]
2604 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2605 LPLONG lpcbData )
2607 HKEY xhkey;
2608 DWORD ret,lpdwType;
2610 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2611 lpcbData?*lpcbData:0);
2613 /* Only open subkey, if we really do descend */
2614 if (lpszSubKey && *lpszSubKey) {
2615 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2616 if (ret != ERROR_SUCCESS) {
2617 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2618 return ret;
2620 } else
2621 xhkey = hkey;
2623 lpdwType = REG_SZ;
2624 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2625 lpcbData );
2626 if (xhkey != hkey)
2627 RegCloseKey(xhkey);
2628 return ret;
2632 /******************************************************************************
2633 * RegQueryValueEx32A [ADVAPI32.157]
2635 * NOTES:
2636 * the documantation is wrong: if the buffer is to small it remains untouched
2638 * FIXME: check returnvalue (len) for an empty key
2640 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2641 LPDWORD lpdwReserved, LPDWORD lpdwType,
2642 LPBYTE lpbData, LPDWORD lpcbData )
2644 LPWSTR lpszValueNameW;
2645 LPBYTE mybuf = NULL;
2646 DWORD ret, mytype, mylen = 0;
2648 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2649 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2651 if (!lpcbData && lpbData) /* buffer without size is illegal */
2652 { return ERROR_INVALID_PARAMETER;
2655 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2657 /* get just the type first */
2658 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2660 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2661 { if(lpszValueNameW) free(lpszValueNameW);
2662 return ret;
2665 if (lpcbData) /* at least length requested? */
2666 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2667 { if (lpbData ) /* value requested? */
2668 { mylen = 2*( *lpcbData );
2669 mybuf = (LPBYTE)xmalloc( mylen );
2672 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2674 if (ret == ERROR_SUCCESS )
2675 { if ( lpbData )
2676 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2680 *lpcbData = mylen/2; /* size is in byte! */
2682 else /* no strings, call it straight */
2683 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2687 if (lpdwType) /* type when requested */
2688 { *lpdwType = mytype;
2691 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2693 if(mybuf) free(mybuf);
2694 if(lpszValueNameW) free(lpszValueNameW);
2695 return ret;
2699 /******************************************************************************
2700 * RegQueryValueEx16 [KERNEL.225]
2702 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2703 LPDWORD lpdwReserved, LPDWORD lpdwType,
2704 LPBYTE lpbData, LPDWORD lpcbData )
2706 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2707 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2708 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2709 lpbData, lpcbData );
2713 /******************************************************************************
2714 * RegQueryValue32A [ADVAPI32.156]
2716 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2717 LPLONG lpcbData )
2719 HKEY xhkey;
2720 DWORD ret, dwType;
2722 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2723 lpcbData?*lpcbData:0);
2725 if (lpszSubKey && *lpszSubKey) {
2726 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2727 if( ret != ERROR_SUCCESS )
2728 return ret;
2729 } else
2730 xhkey = hkey;
2732 dwType = REG_SZ;
2733 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2734 lpcbData );
2735 if( xhkey != hkey )
2736 RegCloseKey( xhkey );
2737 return ret;
2741 /******************************************************************************
2742 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2744 * NOTES
2745 * Is this HACK still applicable?
2747 * HACK
2748 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2749 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2750 * Aldus FH4)
2752 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2753 LPDWORD lpcbData )
2755 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2756 lpcbData?*lpcbData:0);
2758 if (lpcbData)
2759 *lpcbData &= 0xFFFF;
2760 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2765 * Setting values of Registry keys
2767 * Callpath:
2768 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2769 * RegSetValue32W -> RegSetValueEx32W
2773 /******************************************************************************
2774 * RegSetValueEx32W [ADVAPI32.170]
2775 * Sets the data and type of a value under a register key
2777 * PARAMS
2778 * hkey [I] Handle of key to set value for
2779 * lpszValueName [I] Name of value to set
2780 * dwReserved [I] Reserved - must be zero
2781 * dwType [I] Flag for value type
2782 * lpbData [I] Address of value data
2783 * cbData [I] Size of value data
2785 * RETURNS
2786 * Success: ERROR_SUCCESS
2787 * Failure: Error code
2789 * NOTES
2790 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2792 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2793 DWORD dwReserved, DWORD dwType,
2794 CONST BYTE *lpbData, DWORD cbData)
2796 LPKEYSTRUCT lpkey;
2797 int i;
2799 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2800 dwReserved, dwType, lpbData, cbData);
2802 lpkey = lookup_hkey( hkey );
2804 if (!lpkey)
2805 return ERROR_INVALID_HANDLE;
2807 lpkey->flags |= REG_OPTION_TAINTED;
2809 if (lpszValueName==NULL) {
2810 /* Sets type and name for key's unnamed or default value */
2811 for (i=0;i<lpkey->nrofvalues;i++)
2812 if (lpkey->values[i].name==NULL)
2813 break;
2814 } else {
2815 for (i=0;i<lpkey->nrofvalues;i++)
2816 if ( lpkey->values[i].name &&
2817 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2819 break;
2821 if (i==lpkey->nrofvalues) {
2822 lpkey->values = (LPKEYVALUE)xrealloc(
2823 lpkey->values,
2824 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2826 lpkey->nrofvalues++;
2827 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2829 if (lpkey->values[i].name==NULL) {
2830 if (lpszValueName)
2831 lpkey->values[i].name = strdupW(lpszValueName);
2832 else
2833 lpkey->values[i].name = NULL;
2836 if (dwType == REG_SZ)
2837 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2839 lpkey->values[i].len = cbData;
2840 lpkey->values[i].type = dwType;
2841 if (lpkey->values[i].data !=NULL)
2842 free(lpkey->values[i].data);
2843 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2844 lpkey->values[i].lastmodified = time(NULL);
2845 memcpy(lpkey->values[i].data,lpbData,cbData);
2846 return ERROR_SUCCESS;
2850 /******************************************************************************
2851 * RegSetValueEx32A [ADVAPI32.169]
2853 * NOTES
2854 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2856 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2857 DWORD dwReserved, DWORD dwType,
2858 CONST BYTE *lpbData, DWORD cbData )
2860 LPBYTE buf;
2861 LPWSTR lpszValueNameW;
2862 DWORD ret;
2864 if (!lpbData)
2865 return (ERROR_INVALID_PARAMETER);
2867 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2868 dwReserved,dwType,lpbData,cbData);
2870 if ((1<<dwType) & UNICONVMASK)
2871 { if (dwType == REG_SZ)
2872 cbData = strlen ((LPCSTR)lpbData)+1;
2874 buf = (LPBYTE)xmalloc( cbData *2 );
2875 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2876 cbData=2*cbData;
2878 else
2879 buf=(LPBYTE)lpbData;
2881 if (lpszValueName)
2882 lpszValueNameW = strdupA2W(lpszValueName);
2883 else
2884 lpszValueNameW = NULL;
2886 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2888 if (lpszValueNameW)
2889 free(lpszValueNameW);
2891 if (buf!=lpbData)
2892 free(buf);
2894 return ret;
2898 /******************************************************************************
2899 * RegSetValueEx16 [KERNEL.226]
2901 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2902 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2904 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2905 dwReserved,dwType,lpbData,cbData);
2906 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2907 cbData );
2911 /******************************************************************************
2912 * RegSetValue32W [ADVAPI32.171]
2914 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2915 LPCWSTR lpszData, DWORD cbData )
2917 HKEY xhkey;
2918 DWORD ret;
2920 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2921 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2923 if (lpszSubKey && *lpszSubKey) {
2924 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2925 if (ret!=ERROR_SUCCESS)
2926 return ret;
2927 } else
2928 xhkey=hkey;
2929 if (dwType!=REG_SZ) {
2930 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2931 dwType=REG_SZ;
2933 if (cbData!=2*lstrlenW(lpszData)+2) {
2934 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2935 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2937 cbData=2*lstrlenW(lpszData)+2;
2939 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2940 if (hkey!=xhkey)
2941 RegCloseKey(xhkey);
2942 return ret;
2946 /******************************************************************************
2947 * RegSetValue32A [ADVAPI32.168]
2950 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2951 LPCSTR lpszData, DWORD cbData )
2953 DWORD ret;
2954 HKEY xhkey;
2956 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2957 if (lpszSubKey && *lpszSubKey) {
2958 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2959 if (ret!=ERROR_SUCCESS)
2960 return ret;
2961 } else
2962 xhkey=hkey;
2964 if (dwType!=REG_SZ) {
2965 TRACE_(reg)("dwType=%ld!\n",dwType);
2966 dwType=REG_SZ;
2968 if (cbData!=strlen(lpszData)+1)
2969 cbData=strlen(lpszData)+1;
2970 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2971 if (xhkey!=hkey)
2972 RegCloseKey(xhkey);
2973 return ret;
2977 /******************************************************************************
2978 * RegSetValue16 [KERNEL.221] [SHELL.5]
2980 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2981 LPCSTR lpszData, DWORD cbData )
2983 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2984 debugstr_a(lpszData),cbData);
2985 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2990 * Key Enumeration
2992 * Callpath:
2993 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2994 * RegEnumKey32W -> RegEnumKeyEx32W
2998 /******************************************************************************
2999 * RegEnumKeyEx32W [ADVAPI32.139]
3001 * PARAMS
3002 * hkey [I] Handle to key to enumerate
3003 * iSubKey [I] Index of subkey to enumerate
3004 * lpszName [O] Buffer for subkey name
3005 * lpcchName [O] Size of subkey buffer
3006 * lpdwReserved [I] Reserved
3007 * lpszClass [O] Buffer for class string
3008 * lpcchClass [O] Size of class buffer
3009 * ft [O] Time key last written to
3011 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3012 LPDWORD lpcchName, LPDWORD lpdwReserved,
3013 LPWSTR lpszClass, LPDWORD lpcchClass,
3014 FILETIME *ft )
3016 LPKEYSTRUCT lpkey,lpxkey;
3018 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3019 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
3021 lpkey = lookup_hkey( hkey );
3022 if (!lpkey)
3023 return ERROR_INVALID_HANDLE;
3025 if (!lpkey->nextsub)
3026 return ERROR_NO_MORE_ITEMS;
3027 lpxkey=lpkey->nextsub;
3029 /* Traverse the subkeys */
3030 while (iSubkey && lpxkey) {
3031 iSubkey--;
3032 lpxkey=lpxkey->next;
3035 if (iSubkey || !lpxkey)
3036 return ERROR_NO_MORE_ITEMS;
3037 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3038 *lpcchName = lstrlenW(lpxkey->keyname)+1;
3039 return ERROR_MORE_DATA;
3041 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3043 if (*lpcchName)
3044 *lpcchName = lstrlenW(lpszName);
3046 if (lpszClass) {
3047 /* FIXME: what should we write into it? */
3048 *lpszClass = 0;
3049 *lpcchClass = 2;
3051 return ERROR_SUCCESS;
3055 /******************************************************************************
3056 * RegEnumKey32W [ADVAPI32.140]
3058 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3059 DWORD lpcchName )
3061 FILETIME ft;
3063 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3064 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3068 /******************************************************************************
3069 * RegEnumKeyEx32A [ADVAPI32.138]
3071 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3072 LPDWORD lpcchName, LPDWORD lpdwReserved,
3073 LPSTR lpszClass, LPDWORD lpcchClass,
3074 FILETIME *ft )
3076 DWORD ret,lpcchNameW,lpcchClassW;
3077 LPWSTR lpszNameW,lpszClassW;
3080 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3081 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3083 if (lpszName) {
3084 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3085 lpcchNameW = *lpcchName;
3086 } else {
3087 lpszNameW = NULL;
3088 lpcchNameW = 0;
3090 if (lpszClass) {
3091 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3092 lpcchClassW = *lpcchClass;
3093 } else {
3094 lpszClassW =0;
3095 lpcchClassW=0;
3097 ret=RegEnumKeyExW(
3098 hkey,
3099 iSubkey,
3100 lpszNameW,
3101 &lpcchNameW,
3102 lpdwReserved,
3103 lpszClassW,
3104 &lpcchClassW,
3107 if (ret==ERROR_SUCCESS) {
3108 lstrcpyWtoA(lpszName,lpszNameW);
3109 *lpcchName=strlen(lpszName);
3110 if (lpszClassW) {
3111 lstrcpyWtoA(lpszClass,lpszClassW);
3112 *lpcchClass=strlen(lpszClass);
3115 if (lpszNameW)
3116 free(lpszNameW);
3117 if (lpszClassW)
3118 free(lpszClassW);
3119 return ret;
3123 /******************************************************************************
3124 * RegEnumKey32A [ADVAPI32.137]
3126 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3127 DWORD lpcchName )
3129 FILETIME ft;
3131 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3132 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3133 NULL, &ft );
3137 /******************************************************************************
3138 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3140 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3141 DWORD lpcchName )
3143 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3144 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3149 * Enumerate Registry Values
3151 * Callpath:
3152 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3156 /******************************************************************************
3157 * RegEnumValue32W [ADVAPI32.142]
3159 * PARAMS
3160 * hkey [I] Handle to key to query
3161 * iValue [I] Index of value to query
3162 * lpszValue [O] Value string
3163 * lpcchValue [I/O] Size of value buffer (in wchars)
3164 * lpdReserved [I] Reserved
3165 * lpdwType [O] Type code
3166 * lpbData [O] Value data
3167 * lpcbData [I/O] Size of data buffer (in bytes)
3169 * Note: wide character functions that take and/or return "character counts"
3170 * use TCHAR (that is unsigned short or char) not byte counts.
3172 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3173 LPDWORD lpcchValue, LPDWORD lpdReserved,
3174 LPDWORD lpdwType, LPBYTE lpbData,
3175 LPDWORD lpcbData )
3177 LPKEYSTRUCT lpkey;
3178 LPKEYVALUE val;
3180 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3181 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3183 lpkey = lookup_hkey( hkey );
3185 if (!lpcbData && lpbData)
3186 return ERROR_INVALID_PARAMETER;
3188 if (!lpkey)
3189 return ERROR_INVALID_HANDLE;
3191 if (lpkey->nrofvalues <= iValue)
3192 return ERROR_NO_MORE_ITEMS;
3194 val = &(lpkey->values[iValue]);
3196 if (val->name) {
3197 if (lstrlenW(val->name)+1>*lpcchValue) {
3198 *lpcchValue = lstrlenW(val->name)+1;
3199 return ERROR_MORE_DATA;
3201 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3202 *lpcchValue=lstrlenW(val->name);
3203 } else {
3204 *lpszValue = 0;
3205 *lpcchValue = 0;
3208 /* Can be NULL if the type code is not required */
3209 if (lpdwType)
3210 *lpdwType = val->type;
3212 if (lpbData) {
3213 if (val->len>*lpcbData) {
3214 *lpcbData = val->len;
3215 return ERROR_MORE_DATA;
3217 memcpy(lpbData,val->data,val->len);
3218 *lpcbData = val->len;
3221 debug_print_value ( val->data, val );
3222 return ERROR_SUCCESS;
3226 /******************************************************************************
3227 * RegEnumValue32A [ADVAPI32.141]
3229 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3230 LPDWORD lpcchValue, LPDWORD lpdReserved,
3231 LPDWORD lpdwType, LPBYTE lpbData,
3232 LPDWORD lpcbData )
3234 LPWSTR lpszValueW;
3235 LPBYTE lpbDataW;
3236 DWORD ret,lpcbDataW;
3237 DWORD dwType;
3239 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3240 lpdReserved,lpdwType,lpbData,lpcbData);
3242 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3243 if (lpbData) {
3244 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3245 lpcbDataW = *lpcbData;
3246 } else
3247 lpbDataW = NULL;
3249 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3250 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3252 if (lpdwType)
3253 *lpdwType = dwType;
3255 if (ret==ERROR_SUCCESS) {
3256 lstrcpyWtoA(lpszValue,lpszValueW);
3257 if (lpbData) {
3258 if ((1<<dwType) & UNICONVMASK) {
3259 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3260 } else {
3261 if (lpcbDataW > *lpcbData) {
3262 *lpcbData = lpcbDataW;
3263 ret = ERROR_MORE_DATA;
3264 } else
3265 memcpy(lpbData,lpbDataW,lpcbDataW);
3267 *lpcbData = lpcbDataW;
3270 if (lpbDataW) free(lpbDataW);
3271 if (lpszValueW) free(lpszValueW);
3272 return ret;
3276 /******************************************************************************
3277 * RegEnumValue16 [KERNEL.223]
3279 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3280 LPDWORD lpcchValue, LPDWORD lpdReserved,
3281 LPDWORD lpdwType, LPBYTE lpbData,
3282 LPDWORD lpcbData )
3284 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3285 lpdReserved,lpdwType,lpbData,lpcbData);
3286 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3287 lpdwType, lpbData, lpcbData );
3291 /******************************************************************************
3292 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3293 * Releases the handle of the specified key
3295 * PARAMS
3296 * hkey [I] Handle of key to close
3298 * RETURNS
3299 * Success: ERROR_SUCCESS
3300 * Failure: Error code
3302 DWORD WINAPI RegCloseKey( HKEY hkey )
3304 TRACE_(reg)("(%x)\n",hkey);
3306 /* The standard handles are allowed to succeed, even though they are not
3307 closed */
3308 if (is_standard_hkey(hkey))
3309 return ERROR_SUCCESS;
3311 return remove_handle(hkey);
3316 * Delete registry key
3318 * Callpath:
3319 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3323 /******************************************************************************
3324 * RegDeleteKey32W [ADVAPI32.134]
3326 * PARAMS
3327 * hkey [I] Handle to open key
3328 * lpszSubKey [I] Name of subkey to delete
3330 * RETURNS
3331 * Success: ERROR_SUCCESS
3332 * Failure: Error code
3334 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3336 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3337 LPWSTR *wps;
3338 int wpc,i;
3340 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3342 lpNextKey = lookup_hkey(hkey);
3343 if (!lpNextKey)
3344 return ERROR_INVALID_HANDLE;
3346 /* Subkey param cannot be NULL */
3347 if (!lpszSubKey || !*lpszSubKey)
3348 return ERROR_BADKEY;
3350 /* We need to know the previous key in the hier. */
3351 split_keypath(lpszSubKey,&wps,&wpc);
3352 i = 0;
3353 lpxkey = lpNextKey;
3354 while (i<wpc-1) {
3355 lpxkey=lpNextKey->nextsub;
3356 while (lpxkey) {
3357 TRACE_(reg)(" Scanning [%s]\n",
3358 debugstr_w(lpxkey->keyname));
3359 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3360 break;
3361 lpxkey=lpxkey->next;
3363 if (!lpxkey) {
3364 FREE_KEY_PATH;
3365 TRACE_(reg)(" Not found.\n");
3366 /* not found is success */
3367 return ERROR_SUCCESS;
3369 i++;
3370 lpNextKey = lpxkey;
3372 lpxkey = lpNextKey->nextsub;
3373 lplpPrevKey = &(lpNextKey->nextsub);
3374 while (lpxkey) {
3375 TRACE_(reg)(" Scanning [%s]\n",
3376 debugstr_w(lpxkey->keyname));
3377 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3378 break;
3379 lplpPrevKey = &(lpxkey->next);
3380 lpxkey = lpxkey->next;
3383 if (!lpxkey) {
3384 FREE_KEY_PATH;
3385 WARN_(reg)(" Not found.\n");
3386 return ERROR_FILE_NOT_FOUND;
3389 if (lpxkey->nextsub) {
3390 FREE_KEY_PATH;
3391 WARN_(reg)(" Not empty.\n");
3392 return ERROR_CANTWRITE;
3394 *lplpPrevKey = lpxkey->next;
3395 free(lpxkey->keyname);
3396 if (lpxkey->class)
3397 free(lpxkey->class);
3398 if (lpxkey->values)
3399 free(lpxkey->values);
3400 free(lpxkey);
3401 FREE_KEY_PATH;
3402 TRACE_(reg)(" Done.\n");
3403 return ERROR_SUCCESS;
3407 /******************************************************************************
3408 * RegDeleteKey32A [ADVAPI32.133]
3410 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3412 LPWSTR lpszSubKeyW;
3413 DWORD ret;
3415 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3416 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3417 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3418 if(lpszSubKeyW) free(lpszSubKeyW);
3419 return ret;
3423 /******************************************************************************
3424 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3426 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3428 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3429 return RegDeleteKeyA( hkey, lpszSubKey );
3434 * Delete registry value
3436 * Callpath:
3437 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3441 /******************************************************************************
3442 * RegDeleteValue32W [ADVAPI32.136]
3444 * PARAMS
3445 * hkey [I]
3446 * lpszValue [I]
3448 * RETURNS
3450 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3452 DWORD i;
3453 LPKEYSTRUCT lpkey;
3454 LPKEYVALUE val;
3456 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3458 lpkey = lookup_hkey( hkey );
3459 if (!lpkey)
3460 return ERROR_INVALID_HANDLE;
3462 if (lpszValue) {
3463 for (i=0;i<lpkey->nrofvalues;i++)
3464 if ( lpkey->values[i].name &&
3465 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3467 break;
3468 } else {
3469 for (i=0;i<lpkey->nrofvalues;i++)
3470 if (lpkey->values[i].name==NULL)
3471 break;
3474 if (i == lpkey->nrofvalues)
3475 return ERROR_FILE_NOT_FOUND;
3477 val = lpkey->values+i;
3478 if (val->name) free(val->name);
3479 if (val->data) free(val->data);
3480 memcpy(
3481 lpkey->values+i,
3482 lpkey->values+i+1,
3483 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3485 lpkey->values = (LPKEYVALUE)xrealloc(
3486 lpkey->values,
3487 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3489 lpkey->nrofvalues--;
3490 return ERROR_SUCCESS;
3494 /******************************************************************************
3495 * RegDeleteValue32A [ADVAPI32.135]
3497 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3499 LPWSTR lpszValueW;
3500 DWORD ret;
3502 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3503 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3504 ret = RegDeleteValueW( hkey, lpszValueW );
3505 if(lpszValueW) free(lpszValueW);
3506 return ret;
3510 /******************************************************************************
3511 * RegDeleteValue16 [KERNEL.222]
3513 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3515 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3516 return RegDeleteValueA( hkey, lpszValue );
3520 /******************************************************************************
3521 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3522 * Immediately writes key to registry.
3523 * Only returns after data has been written to disk.
3525 * FIXME: does it really wait until data is written ?
3527 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3528 * written if this function really works (and only if !).
3530 * PARAMS
3531 * hkey [I] Handle of key to write
3533 * RETURNS
3534 * Success: ERROR_SUCCESS
3535 * Failure: Error code
3537 DWORD WINAPI RegFlushKey( HKEY hkey )
3539 LPKEYSTRUCT lpkey;
3541 TRACE_(reg)("(%x)\n", hkey);
3543 lpkey = lookup_hkey( hkey );
3544 if (!lpkey)
3545 return ERROR_BADKEY;
3547 SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3548 return ERROR_SUCCESS;
3552 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3555 /******************************************************************************
3556 * RegQueryInfoKey32W [ADVAPI32.153]
3558 * PARAMS
3559 * hkey [I] Handle to key to query
3560 * lpszClass [O] Buffer for class string
3561 * lpcchClass [O] Size of class string buffer
3562 * lpdwReserved [I] Reserved
3563 * lpcSubKeys [I] Buffer for number of subkeys
3564 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3565 * lpcchMaxClass [O] Buffer for longest class string length
3566 * lpcValues [O] Buffer for number of value entries
3567 * lpcchMaxValueName [O] Buffer for longest value name length
3568 * lpccbMaxValueData [O] Buffer for longest value data length
3569 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3570 * ft
3571 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3572 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3573 * lpcchClass is NULL
3574 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3575 * (it's hard to test validity, so test !NULL instead)
3577 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3578 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3579 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3580 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3581 LPDWORD lpcchMaxValueName,
3582 LPDWORD lpccbMaxValueData,
3583 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3585 LPKEYSTRUCT lpkey,lpxkey;
3586 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3587 int i;
3589 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3590 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3591 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3592 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3594 lpkey = lookup_hkey(hkey);
3595 if (!lpkey)
3596 return ERROR_INVALID_HANDLE;
3597 if (lpszClass) {
3598 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3599 return ERROR_INVALID_PARAMETER;
3601 /* either lpcchClass is valid or this is win95 and lpcchClass
3602 could be invalid */
3603 if (lpkey->class) {
3604 DWORD classLen = lstrlenW(lpkey->class);
3606 if (lpcchClass && classLen+1>*lpcchClass) {
3607 *lpcchClass=classLen+1;
3608 return ERROR_MORE_DATA;
3610 if (lpcchClass)
3611 *lpcchClass=classLen;
3612 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3613 } else {
3614 *lpszClass = 0;
3615 if (lpcchClass)
3616 *lpcchClass = 0;
3618 } else {
3619 if (lpcchClass)
3620 *lpcchClass = lstrlenW(lpkey->class);
3622 lpxkey=lpkey->nextsub;
3623 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3624 while (lpxkey) {
3625 nrofkeys++;
3626 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3627 maxsubkey=lstrlenW(lpxkey->keyname);
3628 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3629 maxclass=lstrlenW(lpxkey->class);
3630 lpxkey=lpxkey->next;
3632 for (i=0;i<lpkey->nrofvalues;i++) {
3633 LPKEYVALUE val=lpkey->values+i;
3635 if (val->name && lstrlenW(val->name)>maxvname)
3636 maxvname=lstrlenW(val->name);
3637 if (val->len>maxvdata)
3638 maxvdata=val->len;
3640 if (!maxclass) maxclass = 1;
3641 if (!maxvname) maxvname = 1;
3642 if (lpcValues)
3643 *lpcValues = lpkey->nrofvalues;
3644 if (lpcSubKeys)
3645 *lpcSubKeys = nrofkeys;
3646 if (lpcchMaxSubkey)
3647 *lpcchMaxSubkey = maxsubkey;
3648 if (lpcchMaxClass)
3649 *lpcchMaxClass = maxclass;
3650 if (lpcchMaxValueName)
3651 *lpcchMaxValueName= maxvname;
3652 if (lpccbMaxValueData)
3653 *lpccbMaxValueData= maxvdata;
3654 return ERROR_SUCCESS;
3658 /******************************************************************************
3659 * RegQueryInfoKey32A [ADVAPI32.152]
3661 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3662 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3663 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3664 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3665 LPDWORD lpccbMaxValueData,
3666 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3668 LPWSTR lpszClassW = NULL;
3669 DWORD ret;
3671 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3672 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3673 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3674 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3676 if (lpszClass) {
3677 if (lpcchClass) {
3678 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3679 } else if (VERSION_GetVersion() == WIN95) {
3680 /* win95 allows lpcchClass to be null */
3681 /* we don't know how big lpszClass is, would
3682 MAX_PATHNAME_LEN be the correct default? */
3683 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3686 } else
3687 lpszClassW = NULL;
3688 ret=RegQueryInfoKeyW(
3689 hkey,
3690 lpszClassW,
3691 lpcchClass,
3692 lpdwReserved,
3693 lpcSubKeys,
3694 lpcchMaxSubkey,
3695 lpcchMaxClass,
3696 lpcValues,
3697 lpcchMaxValueName,
3698 lpccbMaxValueData,
3699 lpcbSecurityDescriptor,
3702 if (ret==ERROR_SUCCESS && lpszClass)
3703 lstrcpyWtoA(lpszClass,lpszClassW);
3704 if (lpszClassW)
3705 free(lpszClassW);
3706 return ret;
3710 /******************************************************************************
3711 * RegConnectRegistry32W [ADVAPI32.128]
3713 * PARAMS
3714 * lpMachineName [I] Address of name of remote computer
3715 * hHey [I] Predefined registry handle
3716 * phkResult [I] Address of buffer for remote registry handle
3718 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3719 LPHKEY phkResult )
3721 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3723 if (!lpMachineName || !*lpMachineName) {
3724 /* Use the local machine name */
3725 return RegOpenKey16( hKey, "", phkResult );
3728 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3729 return ERROR_BAD_NETPATH;
3733 /******************************************************************************
3734 * RegConnectRegistry32A [ADVAPI32.127]
3736 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3738 DWORD ret;
3739 LPWSTR machineW = strdupA2W(machine);
3740 ret = RegConnectRegistryW( machineW, hkey, reskey );
3741 free(machineW);
3742 return ret;
3746 /******************************************************************************
3747 * RegGetKeySecurity [ADVAPI32.144]
3748 * Retrieves a copy of security descriptor protecting the registry key
3750 * PARAMS
3751 * hkey [I] Open handle of key to set
3752 * SecurityInformation [I] Descriptor contents
3753 * pSecurityDescriptor [O] Address of descriptor for key
3754 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3756 * RETURNS
3757 * Success: ERROR_SUCCESS
3758 * Failure: Error code
3760 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3761 SECURITY_INFORMATION SecurityInformation,
3762 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3763 LPDWORD lpcbSecurityDescriptor )
3765 LPKEYSTRUCT lpkey;
3767 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3768 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3770 lpkey = lookup_hkey( hkey );
3771 if (!lpkey)
3772 return ERROR_INVALID_HANDLE;
3774 /* FIXME: Check for valid SecurityInformation values */
3776 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3777 return ERROR_INSUFFICIENT_BUFFER;
3779 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3780 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3782 return ERROR_SUCCESS;
3786 /******************************************************************************
3787 * RegLoadKey32W [ADVAPI32.???]
3789 * PARAMS
3790 * hkey [I] Handle of open key
3791 * lpszSubKey [I] Address of name of subkey
3792 * lpszFile [I] Address of filename for registry information
3794 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3796 LPKEYSTRUCT lpkey;
3797 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3799 /* Do this check before the hkey check */
3800 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3801 return ERROR_INVALID_PARAMETER;
3803 lpkey = lookup_hkey( hkey );
3804 if (!lpkey)
3805 return ERROR_INVALID_HANDLE;
3807 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3808 debugstr_w(lpszFile));
3810 return ERROR_SUCCESS;
3814 /******************************************************************************
3815 * RegLoadKey32A [ADVAPI32.???]
3817 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3819 LONG ret;
3820 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3821 LPWSTR lpszFileW = strdupA2W(lpszFile);
3822 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3823 if(lpszFileW) free(lpszFileW);
3824 if(lpszSubKeyW) free(lpszSubKeyW);
3825 return ret;
3829 /******************************************************************************
3830 * RegNotifyChangeKeyValue [ADVAPI32.???]
3832 * PARAMS
3833 * hkey [I] Handle of key to watch
3834 * fWatchSubTree [I] Flag for subkey notification
3835 * fdwNotifyFilter [I] Changes to be reported
3836 * hEvent [I] Handle of signaled event
3837 * fAsync [I] Flag for asynchronous reporting
3839 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3840 DWORD fdwNotifyFilter, HANDLE hEvent,
3841 BOOL fAsync )
3843 LPKEYSTRUCT lpkey;
3844 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3845 hEvent,fAsync);
3847 lpkey = lookup_hkey( hkey );
3848 if (!lpkey)
3849 return ERROR_INVALID_HANDLE;
3851 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3852 hEvent,fAsync);
3854 return ERROR_SUCCESS;
3858 /******************************************************************************
3859 * RegUnLoadKey32W [ADVAPI32.173]
3861 * PARAMS
3862 * hkey [I] Handle of open key
3863 * lpSubKey [I] Address of name of subkey to unload
3865 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3867 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3868 return ERROR_SUCCESS;
3872 /******************************************************************************
3873 * RegUnLoadKey32A [ADVAPI32.172]
3875 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3877 LONG ret;
3878 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3879 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3880 if(lpSubKeyW) free(lpSubKeyW);
3881 return ret;
3885 /******************************************************************************
3886 * RegSetKeySecurity [ADVAPI32.167]
3888 * PARAMS
3889 * hkey [I] Open handle of key to set
3890 * SecurityInfo [I] Descriptor contents
3891 * pSecurityDesc [I] Address of descriptor for key
3893 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3894 PSECURITY_DESCRIPTOR pSecurityDesc )
3896 LPKEYSTRUCT lpkey;
3898 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3900 /* It seems to perform this check before the hkey check */
3901 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3902 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3903 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3904 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3905 /* Param OK */
3906 } else
3907 return ERROR_INVALID_PARAMETER;
3909 if (!pSecurityDesc)
3910 return ERROR_INVALID_PARAMETER;
3912 lpkey = lookup_hkey( hkey );
3913 if (!lpkey)
3914 return ERROR_INVALID_HANDLE;
3916 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3918 return ERROR_SUCCESS;
3922 /******************************************************************************
3923 * RegSaveKey32W [ADVAPI32.166]
3925 * PARAMS
3926 * hkey [I] Handle of key where save begins
3927 * lpFile [I] Address of filename to save to
3928 * sa [I] Address of security structure
3930 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3931 LPSECURITY_ATTRIBUTES sa )
3933 LPKEYSTRUCT lpkey;
3935 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3937 /* It appears to do this check before the hkey check */
3938 if (!lpFile || !*lpFile)
3939 return ERROR_INVALID_PARAMETER;
3941 lpkey = lookup_hkey( hkey );
3942 if (!lpkey)
3943 return ERROR_INVALID_HANDLE;
3945 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3947 return ERROR_SUCCESS;
3951 /******************************************************************************
3952 * RegSaveKey32A [ADVAPI32.165]
3954 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3955 LPSECURITY_ATTRIBUTES sa )
3957 LONG ret;
3958 LPWSTR lpFileW = strdupA2W(lpFile);
3959 ret = RegSaveKeyW( hkey, lpFileW, sa );
3960 free(lpFileW);
3961 return ret;
3965 /******************************************************************************
3966 * RegRestoreKey32W [ADVAPI32.164]
3968 * PARAMS
3969 * hkey [I] Handle of key where restore begins
3970 * lpFile [I] Address of filename containing saved tree
3971 * dwFlags [I] Optional flags
3973 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3975 LPKEYSTRUCT lpkey;
3977 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3979 /* It seems to do this check before the hkey check */
3980 if (!lpFile || !*lpFile)
3981 return ERROR_INVALID_PARAMETER;
3983 lpkey = lookup_hkey( hkey );
3984 if (!lpkey)
3985 return ERROR_INVALID_HANDLE;
3987 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3989 /* Check for file existence */
3991 return ERROR_SUCCESS;
3995 /******************************************************************************
3996 * RegRestoreKey32A [ADVAPI32.163]
3998 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
4000 LONG ret;
4001 LPWSTR lpFileW = strdupA2W(lpFile);
4002 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4003 if(lpFileW) free(lpFileW);
4004 return ret;
4008 /******************************************************************************
4009 * RegReplaceKey32W [ADVAPI32.162]
4011 * PARAMS
4012 * hkey [I] Handle of open key
4013 * lpSubKey [I] Address of name of subkey
4014 * lpNewFile [I] Address of filename for file with new data
4015 * lpOldFile [I] Address of filename for backup file
4017 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4018 LPCWSTR lpOldFile )
4020 LPKEYSTRUCT lpkey;
4022 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4023 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4025 lpkey = lookup_hkey( hkey );
4026 if (!lpkey)
4027 return ERROR_INVALID_HANDLE;
4029 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
4030 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4032 return ERROR_SUCCESS;
4036 /******************************************************************************
4037 * RegReplaceKey32A [ADVAPI32.161]
4039 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4040 LPCSTR lpOldFile )
4042 LONG ret;
4043 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4044 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4045 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4046 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4047 free(lpOldFileW);
4048 free(lpNewFileW);
4049 free(lpSubKeyW);
4050 return ret;