Added support for anonymous structs/unions on compilers that implement it.
[wine.git] / misc / registry.c
blob14178452d62127746a670cb4146dd156ec4fa6a0
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 while (lpcurrkey)
438 if (lpcurrkey == lpkey_to_find)
439 return 1;
440 if (subkey_found(lpcurrkey->nextsub, lpkey_to_find))
441 return 1;
443 lpcurrkey = lpcurrkey->next;
446 TRACE_(reg)("No key found in this root key branch\n");
447 return 0;
452 * finds the corresponding root key for a sub key, i.e. e.g. HKEY_CLASSES_ROOT.
454 static HKEY find_root_key(LPKEYSTRUCT lpkey)
456 typedef struct tagROOT_KEYS {
457 KEYSTRUCT *lpkey;
458 HKEY hkey;
459 } ROOT_KEYS;
460 ROOT_KEYS root_keys[] = { { key_classes_root, HKEY_CLASSES_ROOT },
461 { key_current_user, HKEY_CURRENT_USER },
462 { key_local_machine, HKEY_LOCAL_MACHINE },
463 { key_users, HKEY_USERS } };
464 int i;
466 for (i=0; i<4;i++)
468 if (subkey_found(root_keys[i].lpkey, lpkey))
469 return root_keys[i].hkey;
471 ERR_(reg)("Didn't find corresponding root key entry ! Search strategy broken ??\n");
472 return 0;
473 #undef ROOT_KEYS
475 #undef ADD_ROOT_KEY
476 /* so we don't accidently access them ... */
477 #define key_current_config NULL NULL
478 #define key_current_user NULL NULL
479 #define key_users NULL NULL
480 #define key_local_machine NULL NULL
481 #define key_classes_root NULL NULL
482 #define key_dyn_data NULL NULL
483 #define key_performance_data NULL NULL
485 /******************************************************************************
486 * split_keypath [Internal]
487 * splits the unicode string 'wp' into an array of strings.
488 * the array is allocated by this function.
489 * Free the array using FREE_KEY_PATH
491 * PARAMS
492 * wp [I] String to split up
493 * wpv [O] Array of pointers to strings
494 * wpc [O] Number of components
496 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
498 int i,j,len;
499 LPWSTR ws;
501 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
503 ws = HEAP_strdupW( SystemHeap, 0, wp );
505 /* We know we have at least one substring */
506 *wpc = 1;
508 /* Replace each backslash with NULL, and increment the count */
509 for (i=0;ws[i];i++) {
510 if (ws[i]=='\\') {
511 ws[i]=0;
512 (*wpc)++;
516 len = i;
518 /* Allocate the space for the array of pointers, leaving room for the
519 NULL at the end */
520 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
521 (*wpv)[0]= ws;
523 /* Assign each pointer to the appropriate character in the string */
524 j = 1;
525 for (i=1;i<len;i++)
526 if (ws[i-1]==0) {
527 (*wpv)[j++]=ws+i;
528 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
531 (*wpv)[j]=NULL;
533 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
538 /******************************************************************************
539 * REGISTRY_Init [Internal]
540 * Registry initialisation, allocates some default keys.
542 static void REGISTRY_Init(void) {
543 HKEY hkey;
544 char buf[200];
546 TRACE_(reg)("(void)\n");
548 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
549 RegCloseKey(hkey);
551 /* This was an Open, but since it is called before the real registries
552 are loaded, it was changed to a Create - MTB 980507*/
553 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
554 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
555 RegCloseKey(hkey);
557 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
558 * CurrentVersion
559 * CurrentBuildNumber
560 * CurrentType
561 * string RegisteredOwner
562 * string RegisteredOrganization
565 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
566 * string SysContact
567 * string SysLocation
568 * SysServices
570 if (-1!=gethostname(buf,200)) {
571 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
572 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
573 RegCloseKey(hkey);
578 /************************ SAVE Registry Function ****************************/
580 #define REGISTRY_SAVE_VERSION 0x00000001
582 /* Registry saveformat:
583 * If you change it, increase above number by 1, which will flush
584 * old registry database files.
586 * Global:
587 * "WINE REGISTRY Version %d"
588 * subkeys....
589 * Subkeys:
590 * keyname
591 * valuename=lastmodified,type,data
592 * ...
593 * subkeys
594 * ...
595 * keyname,valuename,stringdata:
596 * the usual ascii characters from 0x00-0xff (well, not 0x00)
597 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
598 * ( "=\\\t" escaped in \uXXXX form.)
599 * type,lastmodified:
600 * int
602 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
604 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
605 * SaveOnlyUpdatedKeys=yes
608 /******************************************************************************
609 * _save_check_tainted [Internal]
611 static int _save_check_tainted( LPKEYSTRUCT lpkey )
613 int tainted;
615 if (!lpkey)
616 return 0;
617 if (lpkey->flags & REG_OPTION_TAINTED)
618 tainted = 1;
619 else
620 tainted = 0;
621 while (lpkey) {
622 if (_save_check_tainted(lpkey->nextsub)) {
623 lpkey->flags |= REG_OPTION_TAINTED;
624 tainted = 1;
626 lpkey = lpkey->next;
628 return tainted;
631 /******************************************************************************
632 * _save_USTRING [Internal]
634 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
636 LPWSTR s;
637 int doescape;
639 if (wstr==NULL)
640 return;
641 s=wstr;
642 while (*s) {
643 doescape=0;
644 if (*s>0xff)
645 doescape = 1;
646 if (*s=='\n')
647 doescape = 1;
648 if (escapeeq && *s=='=')
649 doescape = 1;
650 if (*s=='\\')
651 fputc(*s,F); /* if \\ then put it twice. */
652 if (doescape)
653 fprintf(F,"\\u%04x",*((unsigned short*)s));
654 else
655 fputc(*s,F);
656 s++;
660 /******************************************************************************
661 * _savesubkey [Internal]
663 * NOTES
664 * REG_MULTI_SZ is handled as binary (like in win95) (js)
666 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
668 LPKEYSTRUCT lpxkey;
669 int i,tabs,j;
671 lpxkey = lpkey;
672 while (lpxkey) {
673 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
674 (all || (lpxkey->flags & REG_OPTION_TAINTED))
676 for (tabs=level;tabs--;)
677 fputc('\t',F);
678 _save_USTRING(F,lpxkey->keyname,1);
679 fputs("\n",F);
680 for (i=0;i<lpxkey->nrofvalues;i++) {
681 LPKEYVALUE val=lpxkey->values+i;
683 for (tabs=level+1;tabs--;)
684 fputc('\t',F);
685 _save_USTRING(F,val->name,0);
686 fputc('=',F);
687 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
688 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
689 _save_USTRING(F,(LPWSTR)val->data,0);
690 else
691 for (j=0;j<val->len;j++)
692 fprintf(F,"%02x",*((unsigned char*)val->data+j));
693 fputs("\n",F);
695 /* descend recursively */
696 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
697 return 0;
699 lpxkey=lpxkey->next;
701 return 1;
705 /******************************************************************************
706 * _savesubreg [Internal]
708 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
710 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
711 _save_check_tainted(lpkey->nextsub);
712 return _savesubkey(F,lpkey->nextsub,0,all);
716 /******************************************************************************
717 * _savereg [Internal]
719 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
721 FILE *F;
723 F=fopen(fn,"w");
724 if (F==NULL) {
725 WARN_(reg)("Couldn't open %s for writing: %s\n",
726 fn,strerror(errno)
728 return FALSE;
730 if (!_savesubreg(F,lpkey,all)) {
731 fclose(F);
732 unlink(fn);
733 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
734 return FALSE;
736 fclose(F);
737 return TRUE;
741 /******************************************************************************
742 * SHELL_SaveRegistryBranch [Internal]
744 * Saves main registry branch specified by hkey.
746 static void SHELL_SaveRegistryBranch(HKEY hkey, int all)
748 char *fn, *home, *tmp;
750 /* FIXME: does this check apply to all keys written below ? */
751 if (!(home = getenv( "HOME" )))
753 ERR_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
754 return;
757 /* HKEY_LOCAL_MACHINE contains the HKEY_CLASSES_ROOT branch */
758 if (hkey == HKEY_CLASSES_ROOT)
759 hkey = HKEY_LOCAL_MACHINE;
761 switch (hkey)
763 case HKEY_CURRENT_USER:
765 int usedCfgUser = 0;
767 fn = xmalloc( MAX_PATHNAME_LEN );
768 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "",
769 fn, MAX_PATHNAME_LEN - 1))
771 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
772 usedCfgUser = 1;
774 free (fn);
776 if (usedCfgUser != 1)
778 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
779 strlen(SAVE_CURRENT_USER) + 2 );
780 strcpy(fn,home);
781 strcat(fn,WINE_PREFIX);
783 /* create the directory. don't care about errorcodes. */
784 mkdir(fn,0755); /* drwxr-xr-x */
785 strcat(fn,"/"SAVE_CURRENT_USER);
787 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
788 strcpy(tmp,fn);
789 strcat(tmp,".tmp");
791 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
792 if (-1==rename(tmp,fn)) {
793 perror("rename tmp registry");
794 unlink(tmp);
797 free(tmp);
798 free(fn);
801 break;
802 case HKEY_LOCAL_MACHINE:
804 int usedCfgLM = 0;
805 /* Try first saving according to the defined location in .winerc */
806 fn = xmalloc ( MAX_PATHNAME_LEN);
807 if (PROFILE_GetWineIniString ( "Registry",
808 "LocalMachineFileName", "", fn, MAX_PATHNAME_LEN - 1))
810 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
811 usedCfgLM = 1;
813 free (fn);
815 if ( usedCfgLM != 1)
817 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
818 strlen(SAVE_LOCAL_MACHINE) + 2);
819 strcpy(fn,home);
820 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
822 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
823 strcpy(tmp,fn);
824 strcat(tmp,".tmp");
826 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
827 if (-1==rename(tmp,fn)) {
828 perror("rename tmp registry");
829 unlink(tmp);
832 free(tmp);
833 free(fn);
836 break;
837 case HKEY_USERS:
838 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
839 strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
841 strcpy(fn,home);
842 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
844 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
845 strcpy(tmp,fn);strcat(tmp,".tmp");
846 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
847 if (-1==rename(tmp,fn)) {
848 perror("rename tmp registry");
849 unlink(tmp);
852 free(tmp);
853 free(fn);
854 break;
855 default:
856 ERR_(reg)("unknown/invalid key handle !\n");
861 /******************************************************************************
862 * SHELL_SaveRegistry [Internal]
864 void SHELL_SaveRegistry( void )
866 char buf[4];
867 HKEY hkey;
868 int all;
870 TRACE_(reg)("(void)\n");
872 all=0;
873 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
875 strcpy(buf,"yes");
877 else
879 DWORD len,junk,type;
881 len=4;
882 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
883 VAL_SAVEUPDATED,
884 &junk,
885 &type,
886 buf,
887 &len)) || (type!=REG_SZ))
889 strcpy(buf,"yes");
891 RegCloseKey(hkey);
894 if (lstrcmpiA(buf,"yes"))
895 all = 1;
897 SHELL_SaveRegistryBranch(HKEY_CURRENT_USER, all);
898 SHELL_SaveRegistryBranch(HKEY_LOCAL_MACHINE, all);
899 SHELL_SaveRegistryBranch(HKEY_USERS, all);
903 /************************ LOAD Registry Function ****************************/
907 /******************************************************************************
908 * _find_or_add_key [Internal]
910 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
912 LPKEYSTRUCT lpxkey,*lplpkey;
914 if ((!keyname) || (keyname[0]==0)) {
915 free(keyname);
916 return lpkey;
918 lplpkey= &(lpkey->nextsub);
919 lpxkey = *lplpkey;
920 while (lpxkey) {
921 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
922 !lstrcmpiW(lpxkey->keyname,keyname)
924 break;
925 lplpkey = &(lpxkey->next);
926 lpxkey = *lplpkey;
928 if (lpxkey==NULL) {
929 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
930 lpxkey = *lplpkey;
931 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
932 lpxkey->keyname = keyname;
933 } else
934 free(keyname);
935 return lpxkey;
938 /******************************************************************************
939 * _find_or_add_value [Internal]
941 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
942 LPBYTE data, DWORD len, DWORD lastmodified )
944 LPKEYVALUE val=NULL;
945 int i;
947 if (name && !*name) {/* empty string equals default (NULL) value */
948 free(name);
949 name = NULL;
952 for (i=0;i<lpkey->nrofvalues;i++) {
953 val=lpkey->values+i;
954 if (name==NULL) {
955 if (val->name==NULL)
956 break;
957 } else {
958 if ( val->name!=NULL &&
959 tolower(val->name[0])==tolower(name[0]) &&
960 !lstrcmpiW(val->name,name)
962 break;
965 if (i==lpkey->nrofvalues) {
966 lpkey->values = xrealloc(
967 lpkey->values,
968 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
970 val=lpkey->values+i;
971 memset(val,'\0',sizeof(KEYVALUE));
972 val->name = name;
973 } else {
974 if (name)
975 free(name);
977 if (val->lastmodified<lastmodified) {
978 val->lastmodified=lastmodified;
979 val->type = type;
981 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
983 data=xmalloc(sizeof(WCHAR));
984 memset(data,0,sizeof(WCHAR));
985 len =sizeof(WCHAR);
988 val->len = len;
989 if (val->data)
990 free(val->data);
991 val->data = data;
992 } else
993 free(data);
997 /******************************************************************************
998 * _wine_read_line [Internal]
1000 * reads a line including dynamically enlarging the readbuffer and throwing
1001 * away comments
1003 static int _wine_read_line( FILE *F, char **buf, int *len )
1005 char *s,*curread;
1006 int mylen,curoff;
1008 curread = *buf;
1009 mylen = *len;
1010 **buf = '\0';
1011 while (1) {
1012 while (1) {
1013 s=fgets(curread,mylen,F);
1014 if (s==NULL)
1015 return 0; /* EOF */
1016 if (NULL==(s=strchr(curread,'\n'))) {
1017 /* buffer wasn't large enough */
1018 curoff = strlen(*buf);
1019 *buf = xrealloc(*buf,*len*2);
1020 curread = *buf + curoff;
1021 mylen = *len; /* we filled up the buffer and
1022 * got new '*len' bytes to fill
1024 *len = *len * 2;
1025 } else {
1026 *s='\0';
1027 break;
1030 /* throw away comments */
1031 if (**buf=='#' || **buf==';') {
1032 curread = *buf;
1033 mylen = *len;
1034 continue;
1036 if (s) /* got end of line */
1037 break;
1039 return 1;
1043 /******************************************************************************
1044 * _wine_read_USTRING [Internal]
1046 * converts a char* into a UNICODE string (up to a special char)
1047 * and returns the position exactly after that string
1049 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1051 char *s;
1052 LPWSTR ws;
1054 /* read up to "=" or "\0" or "\n" */
1055 s = buf;
1056 if (*s == '=') {
1057 /* empty string is the win3.1 default value(NULL)*/
1058 *str = NULL;
1059 return s;
1061 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1062 ws = *str;
1063 while (*s && (*s!='\n') && (*s!='=')) {
1064 if (*s!='\\')
1065 *ws++=*((unsigned char*)s++);
1066 else {
1067 s++;
1068 if (!*s) {
1069 /* Dangling \ ... may only happen if a registry
1070 * write was short. FIXME: What do to?
1072 break;
1074 if (*s=='\\') {
1075 *ws++='\\';
1076 s++;
1077 continue;
1079 if (*s!='u') {
1080 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1081 *ws++='\\';
1082 *ws++=*s++;
1083 } else {
1084 char xbuf[5];
1085 int wc;
1087 s++;
1088 memcpy(xbuf,s,4);xbuf[4]='\0';
1089 if (!sscanf(xbuf,"%x",&wc))
1090 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1091 s+=4;
1092 *ws++ =(unsigned short)wc;
1096 *ws = 0;
1097 ws = *str;
1098 if (*ws)
1099 *str = strdupW(*str);
1100 else
1101 *str = NULL;
1102 free(ws);
1103 return s;
1107 /******************************************************************************
1108 * _wine_loadsubkey [Internal]
1110 * NOTES
1111 * It seems like this is returning a boolean. Should it?
1113 * RETURNS
1114 * Success: 1
1115 * Failure: 0
1117 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1118 int *buflen, DWORD optflag )
1120 LPKEYSTRUCT lpxkey;
1121 int i;
1122 char *s;
1123 LPWSTR name;
1125 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1126 *buflen, optflag);
1128 lpkey->flags |= optflag;
1130 /* Good. We already got a line here ... so parse it */
1131 lpxkey = NULL;
1132 while (1) {
1133 i=0;s=*buf;
1134 while (*s=='\t') {
1135 s++;
1136 i++;
1138 if (i>level) {
1139 if (lpxkey==NULL) {
1140 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1141 return 0;
1143 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1144 continue;
1147 /* let the caller handle this line */
1148 if (i<level || **buf=='\0')
1149 return 1;
1151 /* it can be: a value or a keyname. Parse the name first */
1152 s=_wine_read_USTRING(s,&name);
1154 /* switch() default: hack to avoid gotos */
1155 switch (0) {
1156 default:
1157 if (*s=='\0') {
1158 lpxkey=_find_or_add_key(lpkey,name);
1159 } else {
1160 LPBYTE data;
1161 int len,lastmodified,type;
1163 if (*s!='=') {
1164 WARN_(reg)("Unexpected character: %c\n",*s);
1165 break;
1167 s++;
1168 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1169 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1170 break;
1172 /* skip the 2 , */
1173 s=strchr(s,',');s++;
1174 s=strchr(s,',');s++;
1175 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1176 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1177 if (data)
1178 len = lstrlenW((LPWSTR)data)*2+2;
1179 else
1180 len = 0;
1181 } else {
1182 len=strlen(s)/2;
1183 data = (LPBYTE)xmalloc(len+1);
1184 for (i=0;i<len;i++) {
1185 data[i]=0;
1186 if (*s>='0' && *s<='9')
1187 data[i]=(*s-'0')<<4;
1188 if (*s>='a' && *s<='f')
1189 data[i]=(*s-'a'+'\xa')<<4;
1190 if (*s>='A' && *s<='F')
1191 data[i]=(*s-'A'+'\xa')<<4;
1192 s++;
1193 if (*s>='0' && *s<='9')
1194 data[i]|=*s-'0';
1195 if (*s>='a' && *s<='f')
1196 data[i]|=*s-'a'+'\xa';
1197 if (*s>='A' && *s<='F')
1198 data[i]|=*s-'A'+'\xa';
1199 s++;
1202 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1205 /* read the next line */
1206 if (!_wine_read_line(F,buf,buflen))
1207 return 1;
1209 return 1;
1213 /******************************************************************************
1214 * _wine_loadsubreg [Internal]
1216 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1218 int ver;
1219 char *buf;
1220 int buflen;
1222 buf=xmalloc(10);buflen=10;
1223 if (!_wine_read_line(F,&buf,&buflen)) {
1224 free(buf);
1225 return 0;
1227 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1228 free(buf);
1229 return 0;
1231 if (ver!=REGISTRY_SAVE_VERSION) {
1232 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1233 free(buf);
1234 return 0;
1236 if (!_wine_read_line(F,&buf,&buflen)) {
1237 free(buf);
1238 return 0;
1240 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1241 free(buf);
1242 return 0;
1244 free(buf);
1245 return 1;
1249 /******************************************************************************
1250 * _wine_loadreg [Internal]
1252 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1254 FILE *F;
1256 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1258 F = fopen(fn,"rb");
1259 if (F==NULL) {
1260 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1261 return;
1263 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1264 fclose(F);
1265 unlink(fn);
1266 return;
1268 fclose(F);
1271 /******************************************************************************
1272 * _flush_registry [Internal]
1274 * This function allow to flush section of the internal registry. It is mainly
1275 * implements to fix a problem with the global HKU and the local HKU.
1276 * Those two files are read to build the HKU\.Default branch to finaly copy
1277 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1278 * all the global HKU are saved onto the user's personal version of HKU hive.
1279 * which is bad...
1282 /* Forward declaration of recusive agent */
1283 static void _flush_reg(LPKEYSTRUCT from);
1285 static void _flush_registry( LPKEYSTRUCT from )
1287 /* make sure we have something... */
1288 if (from == NULL)
1289 return;
1291 /* Launch the recusive agent on sub branches */
1292 _flush_reg( from->nextsub );
1293 _flush_reg( from->next );
1295 /* Initialize pointers */
1296 from->nextsub = NULL;
1297 from->next = NULL;
1299 static void _flush_reg( LPKEYSTRUCT from )
1301 int j;
1303 /* make sure we have something... */
1304 if (from == NULL)
1305 return;
1308 * do the same for the child keys
1310 if (from->nextsub != NULL)
1311 _flush_reg(from->nextsub);
1314 * do the same for the sibling keys
1316 if (from->next != NULL)
1317 _flush_reg(from->next);
1320 * iterate through this key's values and delete them
1322 for (j=0;j<from->nrofvalues;j++)
1324 free( (from->values+j)->name);
1325 free( (from->values+j)->data);
1329 * free the structure
1331 if ( from != NULL )
1332 free(from);
1336 /******************************************************************************
1337 * _copy_registry [Internal]
1339 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1341 LPKEYSTRUCT lpxkey;
1342 int j;
1343 LPKEYVALUE valfrom;
1345 from=from->nextsub;
1346 while (from) {
1347 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1349 for (j=0;j<from->nrofvalues;j++) {
1350 LPWSTR name;
1351 LPBYTE data;
1353 valfrom = from->values+j;
1354 name=valfrom->name;
1355 if (name) name=strdupW(name);
1356 data=(LPBYTE)xmalloc(valfrom->len);
1357 memcpy(data,valfrom->data,valfrom->len);
1359 _find_or_add_value(
1360 lpxkey,
1361 name,
1362 valfrom->type,
1363 data,
1364 valfrom->len,
1365 valfrom->lastmodified
1368 _copy_registry(from,lpxkey);
1369 from = from->next;
1374 /* WINDOWS 95 REGISTRY LOADER */
1376 * Structure of a win95 registry database.
1377 * main header:
1378 * 0 : "CREG" - magic
1379 * 4 : DWORD version
1380 * 8 : DWORD offset_of_RGDB_part
1381 * 0C..0F: ? (someone fill in please)
1382 * 10: WORD number of RGDB blocks
1383 * 12: WORD ?
1384 * 14: WORD always 0000?
1385 * 16: WORD always 0001?
1386 * 18..1F: ? (someone fill in please)
1388 * 20: RGKN_section:
1389 * header:
1390 * 0 : "RGKN" - magic
1391 * 4 : DWORD offset to first RGDB section
1392 * 8 : DWORD offset to the root record
1393 * C..0x1B: ? (fill in)
1394 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1396 * Disk Key Entry Structure:
1397 * 00: DWORD - Free entry indicator(?)
1398 * 04: DWORD - Hash = sum of bytes of keyname
1399 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1400 * 0C: DWORD - disk address of PreviousLevel Key.
1401 * 10: DWORD - disk address of Next Sublevel Key.
1402 * 14: DWORD - disk address of Next Key (on same level).
1403 * DKEP>18: WORD - Nr, Low Significant part.
1404 * 1A: WORD - Nr, High Significant part.
1406 * The disk address always points to the nr part of the previous key entry
1407 * of the referenced key. Don't ask me why, or even if I got this correct
1408 * from staring at 1kg of hexdumps. (DKEP)
1410 * The High significant part of the structure seems to equal the number
1411 * of the RGDB section. The low significant part is a unique ID within
1412 * that RGDB section
1414 * There are two minor corrections to the position of that structure.
1415 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1416 * the DKE reread from there.
1417 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1418 * CPS - I have not experienced the above phenomenon in my registry files
1420 * RGDB_section:
1421 * 00: "RGDB" - magic
1422 * 04: DWORD offset to next RGDB section
1423 * 08: DWORD ?
1424 * 0C: WORD always 000d?
1425 * 0E: WORD RGDB block number
1426 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1427 * 14..1F: ?
1428 * 20.....: disk keys
1430 * disk key:
1431 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1432 * 08: WORD nrLS - low significant part of NR
1433 * 0A: WORD nrHS - high significant part of NR
1434 * 0C: DWORD bytesused - bytes used in this structure.
1435 * 10: WORD name_len - length of name in bytes. without \0
1436 * 12: WORD nr_of_values - number of values.
1437 * 14: char name[name_len] - name string. No \0.
1438 * 14+name_len: disk values
1439 * nextkeyoffset: ... next disk key
1441 * disk value:
1442 * 00: DWORD type - value type (hmm, could be WORD too)
1443 * 04: DWORD - unknown, usually 0
1444 * 08: WORD namelen - length of Name. 0 means name=NULL
1445 * 0C: WORD datalen - length of Data.
1446 * 10: char name[namelen] - name, no \0
1447 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1448 * 10+namelen+datalen: next values or disk key
1450 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1451 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1452 * structure) and reading another RGDB_section.
1453 * repeat until end of file.
1455 * An interesting relationship exists in RGDB_section. The value at offset
1456 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1457 * idea at the moment what this means. (Kevin Cozens)
1459 * FIXME: this description needs some serious help, yes.
1462 struct _w95keyvalue {
1463 unsigned long type;
1464 unsigned short datalen;
1465 char *name;
1466 unsigned char *data;
1467 unsigned long x1;
1468 int lastmodified;
1471 struct _w95key {
1472 char *name;
1473 int nrofvals;
1474 struct _w95keyvalue *values;
1475 struct _w95key *prevlvl;
1476 struct _w95key *nextsub;
1477 struct _w95key *next;
1481 struct _w95_info {
1482 char *rgknbuffer;
1483 int rgknsize;
1484 char *rgdbbuffer;
1485 int rgdbsize;
1486 int depth;
1487 int lastmodified;
1491 /******************************************************************************
1492 * _w95_processKey [Internal]
1494 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1495 int nrLS, int nrMS, struct _w95_info *info )
1498 /* Disk Key Header structure (RGDB part) */
1499 struct dkh {
1500 unsigned long nextkeyoff;
1501 unsigned short nrLS;
1502 unsigned short nrMS;
1503 unsigned long bytesused;
1504 unsigned short keynamelen;
1505 unsigned short values;
1506 unsigned long xx1;
1507 /* keyname */
1508 /* disk key values or nothing */
1510 /* Disk Key Value structure */
1511 struct dkv {
1512 unsigned long type;
1513 unsigned long x1;
1514 unsigned short valnamelen;
1515 unsigned short valdatalen;
1516 /* valname, valdata */
1520 struct dkh dkh;
1521 int bytesread = 0;
1522 char *rgdbdata = info->rgdbbuffer;
1523 int nbytes = info->rgdbsize;
1524 char *curdata = rgdbdata;
1525 char *end = rgdbdata + nbytes;
1526 int off_next_rgdb;
1527 char *next = rgdbdata;
1528 int nrgdb, i;
1529 LPKEYSTRUCT lpxkey;
1531 do {
1532 curdata = next;
1533 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1535 memcpy(&off_next_rgdb,curdata+4,4);
1536 next = curdata + off_next_rgdb;
1537 nrgdb = (int) *((short *)curdata + 7);
1539 } while (nrgdb != nrMS && (next < end));
1541 /* curdata now points to the start of the right RGDB section */
1542 curdata += 0x20;
1544 #define XREAD(whereto,len) \
1545 if ((curdata + len) <= end) {\
1546 memcpy(whereto,curdata,len);\
1547 curdata+=len;\
1548 bytesread+=len;\
1551 while (curdata < next) {
1552 struct dkh *xdkh = (struct dkh*)curdata;
1554 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1555 if (xdkh->nrLS == nrLS) {
1556 memcpy(&dkh,xdkh,sizeof(dkh));
1557 curdata += sizeof(dkh);
1558 break;
1560 curdata += xdkh->nextkeyoff;
1563 if (dkh.nrLS != nrLS) return (NULL);
1565 if (nrgdb != dkh.nrMS)
1566 return (NULL);
1568 assert((dkh.keynamelen<2) || curdata[0]);
1569 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1570 curdata += dkh.keynamelen;
1572 for (i=0;i< dkh.values; i++) {
1573 struct dkv dkv;
1574 LPBYTE data;
1575 int len;
1576 LPWSTR name;
1578 XREAD(&dkv,sizeof(dkv));
1580 name = strcvtA2W(curdata, dkv.valnamelen);
1581 curdata += dkv.valnamelen;
1583 if ((1 << dkv.type) & UNICONVMASK) {
1584 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1585 len = 2*(dkv.valdatalen + 1);
1586 } else {
1587 /* I don't think we want to NULL terminate all data */
1588 data = xmalloc(dkv.valdatalen);
1589 memcpy (data, curdata, dkv.valdatalen);
1590 len = dkv.valdatalen;
1593 curdata += dkv.valdatalen;
1595 _find_or_add_value(
1596 lpxkey,
1597 name,
1598 dkv.type,
1599 data,
1600 len,
1601 info->lastmodified
1604 return (lpxkey);
1607 /******************************************************************************
1608 * _w95_walkrgkn [Internal]
1610 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1611 struct _w95_info *info )
1614 /* Disk Key Entry structure (RGKN part) */
1615 struct dke {
1616 unsigned long x1;
1617 unsigned long x2;
1618 unsigned long x3;/*usually 0xFFFFFFFF */
1619 unsigned long prevlvl;
1620 unsigned long nextsub;
1621 unsigned long next;
1622 unsigned short nrLS;
1623 unsigned short nrMS;
1624 } *dke = (struct dke *)off;
1625 LPKEYSTRUCT lpxkey;
1627 if (dke == NULL) {
1628 dke = (struct dke *) ((char *)info->rgknbuffer);
1631 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1632 /* XXX <-- This is a hack*/
1633 if (!lpxkey) {
1634 lpxkey = prevkey;
1637 if (dke->nextsub != -1 &&
1638 ((dke->nextsub - 0x20) < info->rgknsize)
1639 && (dke->nextsub > 0x20)) {
1641 _w95_walkrgkn(lpxkey,
1642 info->rgknbuffer + dke->nextsub - 0x20,
1643 info);
1646 if (dke->next != -1 &&
1647 ((dke->next - 0x20) < info->rgknsize) &&
1648 (dke->next > 0x20)) {
1649 _w95_walkrgkn(prevkey,
1650 info->rgknbuffer + dke->next - 0x20,
1651 info);
1654 return;
1658 /******************************************************************************
1659 * _w95_loadreg [Internal]
1661 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1663 HFILE hfd;
1664 char magic[5];
1665 unsigned long where,version,rgdbsection,end;
1666 struct _w95_info info;
1667 OFSTRUCT ofs;
1668 BY_HANDLE_FILE_INFORMATION hfdinfo;
1670 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1671 hfd=OpenFile(fn,&ofs,OF_READ);
1672 if (hfd==HFILE_ERROR)
1673 return;
1674 magic[4]=0;
1675 if (4!=_lread(hfd,magic,4))
1676 return;
1677 if (strcmp(magic,"CREG")) {
1678 WARN_(reg)("%s is not a w95 registry.\n",fn);
1679 return;
1681 if (4!=_lread(hfd,&version,4))
1682 return;
1683 if (4!=_lread(hfd,&rgdbsection,4))
1684 return;
1685 if (-1==_llseek(hfd,0x20,SEEK_SET))
1686 return;
1687 if (4!=_lread(hfd,magic,4))
1688 return;
1689 if (strcmp(magic,"RGKN")) {
1690 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1691 return;
1694 /* STEP 1: Keylink structures */
1695 if (-1==_llseek(hfd,0x40,SEEK_SET))
1696 return;
1697 where = 0x40;
1698 end = rgdbsection;
1700 info.rgknsize = end - where;
1701 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1702 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1703 return;
1705 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1706 return;
1708 end = hfdinfo.nFileSizeLow;
1709 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1711 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1712 return;
1714 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1715 info.rgdbsize = end - rgdbsection;
1717 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1718 return;
1719 _lclose(hfd);
1721 _w95_walkrgkn(lpkey, NULL, &info);
1723 free (info.rgdbbuffer);
1724 free (info.rgknbuffer);
1728 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1731 reghack - windows 3.11 registry data format demo program.
1733 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1734 a combined hash table and tree description, and finally a text table.
1736 The header is obvious from the struct header. The taboff1 and taboff2
1737 fields are always 0x20, and their usage is unknown.
1739 The 8-byte entry table has various entry types.
1741 tabent[0] is a root index. The second word has the index of the root of
1742 the directory.
1743 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1744 the index of the key/value that has that hash. Data with the same
1745 hash value are on a circular list. The other three words in the
1746 hash entry are always zero.
1747 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1748 entry: dirent and keyent/valent. They are identified by context.
1749 tabent[freeidx] is the first free entry. The first word in a free entry
1750 is the index of the next free entry. The last has 0 as a link.
1751 The other three words in the free list are probably irrelevant.
1753 Entries in text table are preceeded by a word at offset-2. This word
1754 has the value (2*index)+1, where index is the referring keyent/valent
1755 entry in the table. I have no suggestion for the 2* and the +1.
1756 Following the word, there are N bytes of data, as per the keyent/valent
1757 entry length. The offset of the keyent/valent entry is from the start
1758 of the text table to the first data byte.
1760 This information is not available from Microsoft. The data format is
1761 deduced from the reg.dat file by me. Mistakes may
1762 have been made. I claim no rights and give no guarantees for this program.
1764 Tor Sjøwall, tor@sn.no
1767 /* reg.dat header format */
1768 struct _w31_header {
1769 char cookie[8]; /* 'SHCC3.10' */
1770 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1771 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1772 unsigned long tabcnt; /* number of entries in index table */
1773 unsigned long textoff; /* offset of text part */
1774 unsigned long textsize; /* byte size of text part */
1775 unsigned short hashsize; /* hash size */
1776 unsigned short freeidx; /* free index */
1779 /* generic format of table entries */
1780 struct _w31_tabent {
1781 unsigned short w0, w1, w2, w3;
1784 /* directory tabent: */
1785 struct _w31_dirent {
1786 unsigned short sibling_idx; /* table index of sibling dirent */
1787 unsigned short child_idx; /* table index of child dirent */
1788 unsigned short key_idx; /* table index of key keyent */
1789 unsigned short value_idx; /* table index of value valent */
1792 /* key tabent: */
1793 struct _w31_keyent {
1794 unsigned short hash_idx; /* hash chain index for string */
1795 unsigned short refcnt; /* reference count */
1796 unsigned short length; /* length of string */
1797 unsigned short string_off; /* offset of string in text table */
1800 /* value tabent: */
1801 struct _w31_valent {
1802 unsigned short hash_idx; /* hash chain index for string */
1803 unsigned short refcnt; /* reference count */
1804 unsigned short length; /* length of string */
1805 unsigned short string_off; /* offset of string in text table */
1808 /* recursive helper function to display a directory tree */
1809 void
1810 __w31_dumptree( unsigned short idx,
1811 unsigned char *txt,
1812 struct _w31_tabent *tab,
1813 struct _w31_header *head,
1814 LPKEYSTRUCT lpkey,
1815 time_t lastmodified,
1816 int level
1818 struct _w31_dirent *dir;
1819 struct _w31_keyent *key;
1820 struct _w31_valent *val;
1821 LPKEYSTRUCT xlpkey = NULL;
1822 LPWSTR name,value;
1823 static char tail[400];
1825 while (idx!=0) {
1826 dir=(struct _w31_dirent*)&tab[idx];
1828 if (dir->key_idx) {
1829 key = (struct _w31_keyent*)&tab[dir->key_idx];
1831 memcpy(tail,&txt[key->string_off],key->length);
1832 tail[key->length]='\0';
1833 /* all toplevel entries AND the entries in the
1834 * toplevel subdirectory belong to \SOFTWARE\Classes
1836 if (!level && !lstrcmpA(tail,".classes")) {
1837 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1838 idx=dir->sibling_idx;
1839 continue;
1841 name=strdupA2W(tail);
1843 xlpkey=_find_or_add_key(lpkey,name);
1845 /* only add if leaf node or valued node */
1846 if (dir->value_idx!=0||dir->child_idx==0) {
1847 if (dir->value_idx) {
1848 val=(struct _w31_valent*)&tab[dir->value_idx];
1849 memcpy(tail,&txt[val->string_off],val->length);
1850 tail[val->length]='\0';
1851 value=strdupA2W(tail);
1852 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1855 } else {
1856 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1858 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1859 idx=dir->sibling_idx;
1864 /******************************************************************************
1865 * _w31_loadreg [Internal]
1867 void _w31_loadreg(void) {
1868 HFILE hf;
1869 struct _w31_header head;
1870 struct _w31_tabent *tab;
1871 unsigned char *txt;
1872 int len;
1873 OFSTRUCT ofs;
1874 BY_HANDLE_FILE_INFORMATION hfinfo;
1875 time_t lastmodified;
1876 LPKEYSTRUCT lpkey;
1878 TRACE_(reg)("(void)\n");
1880 hf = OpenFile("reg.dat",&ofs,OF_READ);
1881 if (hf==HFILE_ERROR)
1882 return;
1884 /* read & dump header */
1885 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1886 ERR_(reg)("reg.dat is too short.\n");
1887 _lclose(hf);
1888 return;
1890 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1891 ERR_(reg)("reg.dat has bad signature.\n");
1892 _lclose(hf);
1893 return;
1896 len = head.tabcnt * sizeof(struct _w31_tabent);
1897 /* read and dump index table */
1898 tab = xmalloc(len);
1899 if (len!=_lread(hf,tab,len)) {
1900 ERR_(reg)("couldn't read %d bytes.\n",len);
1901 free(tab);
1902 _lclose(hf);
1903 return;
1906 /* read text */
1907 txt = xmalloc(head.textsize);
1908 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1909 ERR_(reg)("couldn't seek to textblock.\n");
1910 free(tab);
1911 free(txt);
1912 _lclose(hf);
1913 return;
1915 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1916 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1917 free(tab);
1918 free(txt);
1919 _lclose(hf);
1920 return;
1923 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1924 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1925 free(tab);
1926 free(txt);
1927 _lclose(hf);
1928 return;
1930 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1931 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1932 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1933 free(tab);
1934 free(txt);
1935 _lclose(hf);
1936 return;
1940 /**********************************************************************************
1941 * SHELL_LoadRegistry [Internal]
1943 void SHELL_LoadRegistry( void )
1945 char *fn, *home;
1946 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1947 HKEY hkey;
1949 TRACE_(reg)("(void)\n");
1951 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1952 HKU = lookup_hkey(HKEY_USERS);
1953 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1955 /* Load windows 3.1 entries */
1956 _w31_loadreg();
1957 /* Load windows 95 entries */
1958 _w95_loadreg("C:\\system.1st", HKLM);
1959 _w95_loadreg("system.dat", HKLM);
1960 _w95_loadreg("user.dat", HKU);
1963 * Load the global HKU hive directly from sysconfdir
1965 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1968 * Load the global machine defaults directly form sysconfdir
1970 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1973 * Load the user saved registries
1975 if ((home = getenv( "HOME" )))
1978 * Load user's personal versions of global HKU/.Default keys
1980 fn=(char*)xmalloc(
1981 strlen(home)+
1982 strlen(WINE_PREFIX)+
1983 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1985 strcpy(fn, home);
1986 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1987 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1988 free(fn);
1991 * Load HKCU, attempt to get the registry location from the config
1992 * file first, if exist, load and keep going.
1994 fn = xmalloc( MAX_PATHNAME_LEN );
1995 if ( PROFILE_GetWineIniString(
1996 "Registry",
1997 "UserFileName",
1998 "",
1999 fn,
2000 MAX_PATHNAME_LEN - 1))
2002 _wine_loadreg(HKCU,fn,0);
2004 free (fn);
2006 fn=(char*)xmalloc(
2007 strlen(home)+
2008 strlen(WINE_PREFIX)+
2009 strlen(SAVE_CURRENT_USER)+2);
2011 strcpy(fn, home);
2012 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
2013 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
2014 free(fn);
2017 * Load HKLM, attempt to get the registry location from the config
2018 * file first, if exist, load and keep going.
2020 fn = xmalloc ( MAX_PATHNAME_LEN);
2021 if ( PROFILE_GetWineIniString(
2022 "Registry",
2023 "LocalMachineFileName",
2024 "",
2025 fn,
2026 MAX_PATHNAME_LEN - 1))
2028 _wine_loadreg(HKLM, fn, 0);
2030 free(fn);
2032 fn=(char*)xmalloc(
2033 strlen(home)+
2034 strlen(WINE_PREFIX)+
2035 strlen(SAVE_LOCAL_MACHINE)+2);
2037 strcpy(fn,home);
2038 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2039 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2040 free(fn);
2042 else
2044 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
2048 * Obtain the handle of the HKU\.Default key.
2049 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2051 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2052 lpkey = lookup_hkey(hkey);
2053 if(!lpkey)
2054 WARN_(reg)("Could not create global user default key\n");
2055 else
2056 _copy_registry(lpkey, HKCU );
2058 RegCloseKey(hkey);
2061 * Since HKU is built from the global HKU and the local user HKU file we must
2062 * flush the HKU tree we have built at this point otherwise the part brought
2063 * in from the global HKU is saved into the local HKU. To avoid this
2064 * useless dupplication of HKU keys we reread the local HKU key.
2067 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2068 _flush_registry(HKU);
2070 /* Reload user's local HKU hive */
2071 if (home)
2073 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
2074 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2076 strcpy(fn,home);
2077 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2079 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2081 free(fn);
2085 * Make sure the update mode is there
2087 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2089 DWORD junk,type,len;
2090 char data[5];
2092 len=4;
2093 if (( RegQueryValueExA(
2094 hkey,
2095 VAL_SAVEUPDATED,
2096 &junk,
2097 &type,
2098 data,
2099 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2101 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2104 RegCloseKey(hkey);
2109 /********************* API FUNCTIONS ***************************************/
2111 * Open Keys.
2113 * All functions are stubs to RegOpenKeyEx32W where all the
2114 * magic happens.
2116 * Callpath:
2117 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2118 * RegOpenKey32W -> RegOpenKeyEx32W
2122 /******************************************************************************
2123 * RegOpenKeyEx32W [ADVAPI32.150]
2124 * Opens the specified key
2126 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2128 * PARAMS
2129 * hkey [I] Handle of open key
2130 * lpszSubKey [I] Name of subkey to open
2131 * dwReserved [I] Reserved - must be zero
2132 * samDesired [I] Security access mask
2133 * retkey [O] Address of handle of open key
2135 * RETURNS
2136 * Success: ERROR_SUCCESS
2137 * Failure: Error code
2139 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2140 REGSAM samDesired, LPHKEY retkey )
2142 LPKEYSTRUCT lpNextKey,lpxkey;
2143 LPWSTR *wps;
2144 int wpc,i;
2146 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2147 samDesired,retkey);
2149 lpNextKey = lookup_hkey( hkey );
2150 if (!lpNextKey)
2151 return ERROR_INVALID_HANDLE;
2153 if (!lpszSubKey || !*lpszSubKey) {
2154 /* Either NULL or pointer to empty string, so return a new handle
2155 to the original hkey */
2156 currenthandle += 2;
2157 add_handle(currenthandle,lpNextKey,samDesired);
2158 *retkey=currenthandle;
2159 return ERROR_SUCCESS;
2162 if (lpszSubKey[0] == '\\') {
2163 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2164 return ERROR_BAD_PATHNAME;
2167 split_keypath(lpszSubKey,&wps,&wpc);
2168 i = 0;
2169 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2170 lpxkey = lpNextKey;
2172 while (wps[i]) {
2173 lpxkey=lpNextKey->nextsub;
2174 while (lpxkey) {
2175 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2176 break;
2178 lpxkey=lpxkey->next;
2181 if (!lpxkey) {
2182 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2183 FREE_KEY_PATH;
2184 return ERROR_FILE_NOT_FOUND;
2186 i++;
2187 lpNextKey = lpxkey;
2190 currenthandle += 2;
2191 add_handle(currenthandle,lpxkey,samDesired);
2192 *retkey = currenthandle;
2193 TRACE_(reg)(" Returning %x\n", currenthandle);
2194 FREE_KEY_PATH;
2195 return ERROR_SUCCESS;
2199 /******************************************************************************
2200 * RegOpenKeyEx32A [ADVAPI32.149]
2202 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2203 REGSAM samDesired, LPHKEY retkey )
2205 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2206 DWORD ret;
2208 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2209 samDesired,retkey);
2210 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2211 free(lpszSubKeyW);
2212 return ret;
2216 /******************************************************************************
2217 * RegOpenKey32W [ADVAPI32.151]
2219 * PARAMS
2220 * hkey [I] Handle of open key
2221 * lpszSubKey [I] Address of name of subkey to open
2222 * retkey [O] Address of handle of open key
2224 * RETURNS
2225 * Success: ERROR_SUCCESS
2226 * Failure: Error code
2228 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2230 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2231 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2235 /******************************************************************************
2236 * RegOpenKey32A [ADVAPI32.148]
2238 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2240 DWORD ret;
2241 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2242 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2243 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2244 free(lpszSubKeyW);
2245 return ret;
2249 /******************************************************************************
2250 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2252 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2254 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2255 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2260 * Create keys
2262 * All those functions convert their respective
2263 * arguments and call RegCreateKeyExW at the end.
2265 * We stay away from the Ex functions as long as possible because there are
2266 * differences in the return values
2268 * Callpath:
2269 * RegCreateKeyEx32A \
2270 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2274 /******************************************************************************
2275 * RegCreateKeyEx32W [ADVAPI32.131]
2277 * PARAMS
2278 * hkey [I] Handle of an open key
2279 * lpszSubKey [I] Address of subkey name
2280 * dwReserved [I] Reserved - must be 0
2281 * lpszClass [I] Address of class string
2282 * fdwOptions [I] Special options flag
2283 * samDesired [I] Desired security access
2284 * lpSecAttribs [I] Address of key security structure
2285 * retkey [O] Address of buffer for opened handle
2286 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2288 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2289 DWORD dwReserved, LPWSTR lpszClass,
2290 DWORD fdwOptions, REGSAM samDesired,
2291 LPSECURITY_ATTRIBUTES lpSecAttribs,
2292 LPHKEY retkey, LPDWORD lpDispos )
2294 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2295 LPWSTR *wps;
2296 int wpc,i;
2298 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2299 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2300 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2302 lpNextKey = lookup_hkey(hkey);
2303 if (!lpNextKey)
2304 return ERROR_INVALID_HANDLE;
2306 /* Check for valid options */
2307 switch(fdwOptions) {
2308 case REG_OPTION_NON_VOLATILE:
2309 case REG_OPTION_VOLATILE:
2310 case REG_OPTION_BACKUP_RESTORE:
2311 break;
2312 default:
2313 return ERROR_INVALID_PARAMETER;
2316 /* Sam has to be a combination of the following */
2317 if (!(samDesired &
2318 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2319 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2320 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2321 return ERROR_INVALID_PARAMETER;
2323 if (!lpszSubKey || !*lpszSubKey) {
2324 currenthandle += 2;
2325 add_handle(currenthandle,lpNextKey,samDesired);
2326 *retkey=currenthandle;
2327 TRACE_(reg)("Returning %x\n", currenthandle);
2328 lpNextKey->flags|=REG_OPTION_TAINTED;
2329 return ERROR_SUCCESS;
2332 if (lpszSubKey[0] == '\\') {
2333 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2334 return ERROR_BAD_PATHNAME;
2337 split_keypath(lpszSubKey,&wps,&wpc);
2338 i = 0;
2339 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2340 lpxkey = lpNextKey;
2341 while (wps[i]) {
2342 lpxkey=lpNextKey->nextsub;
2343 while (lpxkey) {
2344 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2345 break;
2346 lpxkey=lpxkey->next;
2348 if (!lpxkey)
2349 break;
2350 i++;
2351 lpNextKey = lpxkey;
2353 if (lpxkey) {
2354 currenthandle += 2;
2355 add_handle(currenthandle,lpxkey,samDesired);
2356 lpxkey->flags |= REG_OPTION_TAINTED;
2357 *retkey = currenthandle;
2358 TRACE_(reg)("Returning %x\n", currenthandle);
2359 if (lpDispos)
2360 *lpDispos = REG_OPENED_EXISTING_KEY;
2361 FREE_KEY_PATH;
2362 return ERROR_SUCCESS;
2365 /* Good. Now the hard part */
2366 while (wps[i]) {
2367 lplpPrevKey = &(lpNextKey->nextsub);
2368 lpxkey = *lplpPrevKey;
2369 while (lpxkey) {
2370 lplpPrevKey = &(lpxkey->next);
2371 lpxkey = *lplpPrevKey;
2373 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2374 if (!*lplpPrevKey) {
2375 FREE_KEY_PATH;
2376 TRACE_(reg)("Returning OUTOFMEMORY\n");
2377 return ERROR_OUTOFMEMORY;
2379 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2380 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2381 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2382 (*lplpPrevKey)->next = NULL;
2383 (*lplpPrevKey)->nextsub = NULL;
2384 (*lplpPrevKey)->values = NULL;
2385 (*lplpPrevKey)->nrofvalues = 0;
2386 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2387 if (lpszClass)
2388 (*lplpPrevKey)->class = strdupW(lpszClass);
2389 else
2390 (*lplpPrevKey)->class = NULL;
2391 lpNextKey = *lplpPrevKey;
2392 i++;
2394 currenthandle += 2;
2395 add_handle(currenthandle,lpNextKey,samDesired);
2397 /*FIXME: flag handling correct? */
2398 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2399 if (lpszClass)
2400 lpNextKey->class = strdupW(lpszClass);
2401 else
2402 lpNextKey->class = NULL;
2403 *retkey = currenthandle;
2404 TRACE_(reg)("Returning %x\n", currenthandle);
2405 if (lpDispos)
2406 *lpDispos = REG_CREATED_NEW_KEY;
2407 FREE_KEY_PATH;
2408 return ERROR_SUCCESS;
2412 /******************************************************************************
2413 * RegCreateKeyEx32A [ADVAPI32.130]
2415 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2416 LPSTR lpszClass, DWORD fdwOptions,
2417 REGSAM samDesired,
2418 LPSECURITY_ATTRIBUTES lpSecAttribs,
2419 LPHKEY retkey, LPDWORD lpDispos )
2421 LPWSTR lpszSubKeyW, lpszClassW;
2422 DWORD ret;
2424 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2425 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2426 retkey,lpDispos);
2428 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2429 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2431 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2432 fdwOptions, samDesired, lpSecAttribs, retkey,
2433 lpDispos );
2435 if(lpszSubKeyW) free(lpszSubKeyW);
2436 if(lpszClassW) free(lpszClassW);
2438 return ret;
2442 /******************************************************************************
2443 * RegCreateKey32W [ADVAPI32.132]
2445 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2447 DWORD junk;
2448 LPKEYSTRUCT lpNextKey;
2450 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2452 /* This check is here because the return value is different than the
2453 one from the Ex functions */
2454 lpNextKey = lookup_hkey(hkey);
2455 if (!lpNextKey)
2456 return ERROR_BADKEY;
2458 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2459 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2460 retkey, &junk);
2464 /******************************************************************************
2465 * RegCreateKey32A [ADVAPI32.129]
2467 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2469 DWORD ret;
2470 LPWSTR lpszSubKeyW;
2472 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2473 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2474 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2475 if(lpszSubKeyW) free(lpszSubKeyW);
2476 return ret;
2480 /******************************************************************************
2481 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2483 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2485 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2486 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2491 * Query Value Functions
2492 * Win32 differs between keynames and valuenames.
2493 * multiple values may belong to one key, the special value
2494 * with name NULL is the default value used by the win31
2495 * compat functions.
2497 * Callpath:
2498 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2499 * RegQueryValue32W -> RegQueryValueEx32W
2503 /******************************************************************************
2504 * RegQueryValueEx32W [ADVAPI32.158]
2505 * Retrieves type and data for a specified name associated with an open key
2507 * PARAMS
2508 * hkey [I] Handle of key to query
2509 * lpValueName [I] Name of value to query
2510 * lpdwReserved [I] Reserved - must be NULL
2511 * lpdwType [O] Address of buffer for value type. If NULL, the type
2512 * is not required.
2513 * lpbData [O] Address of data buffer. If NULL, the actual data is
2514 * not required.
2515 * lpcbData [I/O] Address of data buffer size
2517 * RETURNS
2518 * ERROR_SUCCESS: Success
2519 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2520 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2522 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2523 LPDWORD lpdwReserved, LPDWORD lpdwType,
2524 LPBYTE lpbData, LPDWORD lpcbData )
2526 LPKEYSTRUCT lpkey;
2527 int i;
2528 DWORD ret;
2530 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2531 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2533 lpkey = lookup_hkey(hkey);
2535 if (!lpkey)
2536 return ERROR_INVALID_HANDLE;
2538 if ((lpbData && ! lpcbData) || lpdwReserved)
2539 return ERROR_INVALID_PARAMETER;
2541 /* An empty name string is equivalent to NULL */
2542 if (lpValueName && !*lpValueName)
2543 lpValueName = NULL;
2545 if (lpValueName==NULL)
2546 { /* Use key's unnamed or default value, if any */
2547 for (i=0;i<lpkey->nrofvalues;i++)
2548 if (lpkey->values[i].name==NULL)
2549 break;
2551 else
2552 { /* Search for the key name */
2553 for (i=0;i<lpkey->nrofvalues;i++)
2554 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2555 break;
2558 if (i==lpkey->nrofvalues)
2559 { TRACE_(reg)(" Key not found\n");
2560 if (lpValueName==NULL)
2561 { /* Empty keyname not found */
2562 if (lpbData)
2563 { *(WCHAR*)lpbData = 0;
2564 *lpcbData = 2;
2566 if (lpdwType)
2567 *lpdwType = REG_SZ;
2568 TRACE_(reg)(" Returning an empty string\n");
2569 return ERROR_SUCCESS;
2571 return ERROR_FILE_NOT_FOUND;
2574 ret = ERROR_SUCCESS;
2576 if (lpdwType) /* type required ?*/
2577 *lpdwType = lpkey->values[i].type;
2579 if (lpbData) /* data required ?*/
2580 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2581 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2582 else {
2583 *lpcbData = lpkey->values[i].len;
2584 ret = ERROR_MORE_DATA;
2588 if (lpcbData) /* size required ?*/
2589 { *lpcbData = lpkey->values[i].len;
2592 debug_print_value ( lpbData, &lpkey->values[i]);
2594 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2596 return ret;
2600 /******************************************************************************
2601 * RegQueryValue32W [ADVAPI32.159]
2603 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2604 LPLONG lpcbData )
2606 HKEY xhkey;
2607 DWORD ret,lpdwType;
2609 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2610 lpcbData?*lpcbData:0);
2612 /* Only open subkey, if we really do descend */
2613 if (lpszSubKey && *lpszSubKey) {
2614 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2615 if (ret != ERROR_SUCCESS) {
2616 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2617 return ret;
2619 } else
2620 xhkey = hkey;
2622 lpdwType = REG_SZ;
2623 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2624 lpcbData );
2625 if (xhkey != hkey)
2626 RegCloseKey(xhkey);
2627 return ret;
2631 /******************************************************************************
2632 * RegQueryValueEx32A [ADVAPI32.157]
2634 * NOTES:
2635 * the documantation is wrong: if the buffer is to small it remains untouched
2637 * FIXME: check returnvalue (len) for an empty key
2639 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2640 LPDWORD lpdwReserved, LPDWORD lpdwType,
2641 LPBYTE lpbData, LPDWORD lpcbData )
2643 LPWSTR lpszValueNameW;
2644 LPBYTE mybuf = NULL;
2645 DWORD ret, mytype, mylen = 0;
2647 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2648 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2650 if (!lpcbData && lpbData) /* buffer without size is illegal */
2651 { return ERROR_INVALID_PARAMETER;
2654 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2656 /* get just the type first */
2657 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2659 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2660 { if(lpszValueNameW) free(lpszValueNameW);
2661 return ret;
2664 if (lpcbData) /* at least length requested? */
2665 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2666 { if (lpbData ) /* value requested? */
2667 { mylen = 2*( *lpcbData );
2668 mybuf = (LPBYTE)xmalloc( mylen );
2671 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2673 if (ret == ERROR_SUCCESS )
2674 { if ( lpbData )
2675 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2679 *lpcbData = mylen/2; /* size is in byte! */
2681 else /* no strings, call it straight */
2682 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2686 if (lpdwType) /* type when requested */
2687 { *lpdwType = mytype;
2690 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2692 if(mybuf) free(mybuf);
2693 if(lpszValueNameW) free(lpszValueNameW);
2694 return ret;
2698 /******************************************************************************
2699 * RegQueryValueEx16 [KERNEL.225]
2701 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2702 LPDWORD lpdwReserved, LPDWORD lpdwType,
2703 LPBYTE lpbData, LPDWORD lpcbData )
2705 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2706 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2707 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2708 lpbData, lpcbData );
2712 /******************************************************************************
2713 * RegQueryValue32A [ADVAPI32.156]
2715 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2716 LPLONG lpcbData )
2718 HKEY xhkey;
2719 DWORD ret, dwType;
2721 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2722 lpcbData?*lpcbData:0);
2724 if (lpszSubKey && *lpszSubKey) {
2725 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2726 if( ret != ERROR_SUCCESS )
2727 return ret;
2728 } else
2729 xhkey = hkey;
2731 dwType = REG_SZ;
2732 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2733 lpcbData );
2734 if( xhkey != hkey )
2735 RegCloseKey( xhkey );
2736 return ret;
2740 /******************************************************************************
2741 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2743 * NOTES
2744 * Is this HACK still applicable?
2746 * HACK
2747 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2748 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2749 * Aldus FH4)
2751 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2752 LPDWORD lpcbData )
2754 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2755 lpcbData?*lpcbData:0);
2757 if (lpcbData)
2758 *lpcbData &= 0xFFFF;
2759 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2764 * Setting values of Registry keys
2766 * Callpath:
2767 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2768 * RegSetValue32W -> RegSetValueEx32W
2772 /******************************************************************************
2773 * RegSetValueEx32W [ADVAPI32.170]
2774 * Sets the data and type of a value under a register key
2776 * PARAMS
2777 * hkey [I] Handle of key to set value for
2778 * lpszValueName [I] Name of value to set
2779 * dwReserved [I] Reserved - must be zero
2780 * dwType [I] Flag for value type
2781 * lpbData [I] Address of value data
2782 * cbData [I] Size of value data
2784 * RETURNS
2785 * Success: ERROR_SUCCESS
2786 * Failure: Error code
2788 * NOTES
2789 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2791 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2792 DWORD dwReserved, DWORD dwType,
2793 CONST BYTE *lpbData, DWORD cbData)
2795 LPKEYSTRUCT lpkey;
2796 int i;
2798 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2799 dwReserved, dwType, lpbData, cbData);
2801 lpkey = lookup_hkey( hkey );
2803 if (!lpkey)
2804 return ERROR_INVALID_HANDLE;
2806 lpkey->flags |= REG_OPTION_TAINTED;
2808 if (lpszValueName==NULL) {
2809 /* Sets type and name for key's unnamed or default value */
2810 for (i=0;i<lpkey->nrofvalues;i++)
2811 if (lpkey->values[i].name==NULL)
2812 break;
2813 } else {
2814 for (i=0;i<lpkey->nrofvalues;i++)
2815 if ( lpkey->values[i].name &&
2816 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2818 break;
2820 if (i==lpkey->nrofvalues) {
2821 lpkey->values = (LPKEYVALUE)xrealloc(
2822 lpkey->values,
2823 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2825 lpkey->nrofvalues++;
2826 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2828 if (lpkey->values[i].name==NULL) {
2829 if (lpszValueName)
2830 lpkey->values[i].name = strdupW(lpszValueName);
2831 else
2832 lpkey->values[i].name = NULL;
2835 if (dwType == REG_SZ)
2836 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2838 lpkey->values[i].len = cbData;
2839 lpkey->values[i].type = dwType;
2840 if (lpkey->values[i].data !=NULL)
2841 free(lpkey->values[i].data);
2842 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2843 lpkey->values[i].lastmodified = time(NULL);
2844 memcpy(lpkey->values[i].data,lpbData,cbData);
2845 return ERROR_SUCCESS;
2849 /******************************************************************************
2850 * RegSetValueEx32A [ADVAPI32.169]
2852 * NOTES
2853 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2855 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2856 DWORD dwReserved, DWORD dwType,
2857 CONST BYTE *lpbData, DWORD cbData )
2859 LPBYTE buf;
2860 LPWSTR lpszValueNameW;
2861 DWORD ret;
2863 if (!lpbData)
2864 return (ERROR_INVALID_PARAMETER);
2866 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2867 dwReserved,dwType,lpbData,cbData);
2869 if ((1<<dwType) & UNICONVMASK)
2870 { if (dwType == REG_SZ)
2871 cbData = strlen ((LPCSTR)lpbData)+1;
2873 buf = (LPBYTE)xmalloc( cbData *2 );
2874 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2875 cbData=2*cbData;
2877 else
2878 buf=(LPBYTE)lpbData;
2880 if (lpszValueName)
2881 lpszValueNameW = strdupA2W(lpszValueName);
2882 else
2883 lpszValueNameW = NULL;
2885 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2887 if (lpszValueNameW)
2888 free(lpszValueNameW);
2890 if (buf!=lpbData)
2891 free(buf);
2893 return ret;
2897 /******************************************************************************
2898 * RegSetValueEx16 [KERNEL.226]
2900 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2901 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2903 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2904 dwReserved,dwType,lpbData,cbData);
2905 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2906 cbData );
2910 /******************************************************************************
2911 * RegSetValue32W [ADVAPI32.171]
2913 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2914 LPCWSTR lpszData, DWORD cbData )
2916 HKEY xhkey;
2917 DWORD ret;
2919 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2920 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2922 if (lpszSubKey && *lpszSubKey) {
2923 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2924 if (ret!=ERROR_SUCCESS)
2925 return ret;
2926 } else
2927 xhkey=hkey;
2928 if (dwType!=REG_SZ) {
2929 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2930 dwType=REG_SZ;
2932 if (cbData!=2*lstrlenW(lpszData)+2) {
2933 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2934 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2936 cbData=2*lstrlenW(lpszData)+2;
2938 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2939 if (hkey!=xhkey)
2940 RegCloseKey(xhkey);
2941 return ret;
2945 /******************************************************************************
2946 * RegSetValue32A [ADVAPI32.168]
2949 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2950 LPCSTR lpszData, DWORD cbData )
2952 DWORD ret;
2953 HKEY xhkey;
2955 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2956 if (lpszSubKey && *lpszSubKey) {
2957 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2958 if (ret!=ERROR_SUCCESS)
2959 return ret;
2960 } else
2961 xhkey=hkey;
2963 if (dwType!=REG_SZ) {
2964 TRACE_(reg)("dwType=%ld!\n",dwType);
2965 dwType=REG_SZ;
2967 if (cbData!=strlen(lpszData)+1)
2968 cbData=strlen(lpszData)+1;
2969 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2970 if (xhkey!=hkey)
2971 RegCloseKey(xhkey);
2972 return ret;
2976 /******************************************************************************
2977 * RegSetValue16 [KERNEL.221] [SHELL.5]
2979 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2980 LPCSTR lpszData, DWORD cbData )
2982 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2983 debugstr_a(lpszData),cbData);
2984 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2989 * Key Enumeration
2991 * Callpath:
2992 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2993 * RegEnumKey32W -> RegEnumKeyEx32W
2997 /******************************************************************************
2998 * RegEnumKeyEx32W [ADVAPI32.139]
3000 * PARAMS
3001 * hkey [I] Handle to key to enumerate
3002 * iSubKey [I] Index of subkey to enumerate
3003 * lpszName [O] Buffer for subkey name
3004 * lpcchName [O] Size of subkey buffer
3005 * lpdwReserved [I] Reserved
3006 * lpszClass [O] Buffer for class string
3007 * lpcchClass [O] Size of class buffer
3008 * ft [O] Time key last written to
3010 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3011 LPDWORD lpcchName, LPDWORD lpdwReserved,
3012 LPWSTR lpszClass, LPDWORD lpcchClass,
3013 FILETIME *ft )
3015 LPKEYSTRUCT lpkey,lpxkey;
3017 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
3018 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
3020 lpkey = lookup_hkey( hkey );
3021 if (!lpkey)
3022 return ERROR_INVALID_HANDLE;
3024 if (!lpkey->nextsub)
3025 return ERROR_NO_MORE_ITEMS;
3026 lpxkey=lpkey->nextsub;
3028 /* Traverse the subkeys */
3029 while (iSubkey && lpxkey) {
3030 iSubkey--;
3031 lpxkey=lpxkey->next;
3034 if (iSubkey || !lpxkey)
3035 return ERROR_NO_MORE_ITEMS;
3036 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
3037 *lpcchName = lstrlenW(lpxkey->keyname)+1;
3038 return ERROR_MORE_DATA;
3040 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3042 if (*lpcchName)
3043 *lpcchName = lstrlenW(lpszName);
3045 if (lpszClass) {
3046 /* FIXME: what should we write into it? */
3047 *lpszClass = 0;
3048 *lpcchClass = 2;
3050 return ERROR_SUCCESS;
3054 /******************************************************************************
3055 * RegEnumKey32W [ADVAPI32.140]
3057 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3058 DWORD lpcchName )
3060 FILETIME ft;
3062 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3063 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3067 /******************************************************************************
3068 * RegEnumKeyEx32A [ADVAPI32.138]
3070 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3071 LPDWORD lpcchName, LPDWORD lpdwReserved,
3072 LPSTR lpszClass, LPDWORD lpcchClass,
3073 FILETIME *ft )
3075 DWORD ret,lpcchNameW,lpcchClassW;
3076 LPWSTR lpszNameW,lpszClassW;
3079 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3080 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3082 if (lpszName) {
3083 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3084 lpcchNameW = *lpcchName;
3085 } else {
3086 lpszNameW = NULL;
3087 lpcchNameW = 0;
3089 if (lpszClass) {
3090 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3091 lpcchClassW = *lpcchClass;
3092 } else {
3093 lpszClassW =0;
3094 lpcchClassW=0;
3096 ret=RegEnumKeyExW(
3097 hkey,
3098 iSubkey,
3099 lpszNameW,
3100 &lpcchNameW,
3101 lpdwReserved,
3102 lpszClassW,
3103 &lpcchClassW,
3106 if (ret==ERROR_SUCCESS) {
3107 lstrcpyWtoA(lpszName,lpszNameW);
3108 *lpcchName=strlen(lpszName);
3109 if (lpszClassW) {
3110 lstrcpyWtoA(lpszClass,lpszClassW);
3111 *lpcchClass=strlen(lpszClass);
3114 if (lpszNameW)
3115 free(lpszNameW);
3116 if (lpszClassW)
3117 free(lpszClassW);
3118 return ret;
3122 /******************************************************************************
3123 * RegEnumKey32A [ADVAPI32.137]
3125 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3126 DWORD lpcchName )
3128 FILETIME ft;
3130 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3131 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3132 NULL, &ft );
3136 /******************************************************************************
3137 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3139 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3140 DWORD lpcchName )
3142 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3143 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3148 * Enumerate Registry Values
3150 * Callpath:
3151 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3155 /******************************************************************************
3156 * RegEnumValue32W [ADVAPI32.142]
3158 * PARAMS
3159 * hkey [I] Handle to key to query
3160 * iValue [I] Index of value to query
3161 * lpszValue [O] Value string
3162 * lpcchValue [I/O] Size of value buffer (in wchars)
3163 * lpdReserved [I] Reserved
3164 * lpdwType [O] Type code
3165 * lpbData [O] Value data
3166 * lpcbData [I/O] Size of data buffer (in bytes)
3168 * Note: wide character functions that take and/or return "character counts"
3169 * use TCHAR (that is unsigned short or char) not byte counts.
3171 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3172 LPDWORD lpcchValue, LPDWORD lpdReserved,
3173 LPDWORD lpdwType, LPBYTE lpbData,
3174 LPDWORD lpcbData )
3176 LPKEYSTRUCT lpkey;
3177 LPKEYVALUE val;
3179 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3180 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3182 lpkey = lookup_hkey( hkey );
3184 if (!lpcbData && lpbData)
3185 return ERROR_INVALID_PARAMETER;
3187 if (!lpkey)
3188 return ERROR_INVALID_HANDLE;
3190 if (lpkey->nrofvalues <= iValue)
3191 return ERROR_NO_MORE_ITEMS;
3193 val = &(lpkey->values[iValue]);
3195 if (val->name) {
3196 if (lstrlenW(val->name)+1>*lpcchValue) {
3197 *lpcchValue = lstrlenW(val->name)+1;
3198 return ERROR_MORE_DATA;
3200 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3201 *lpcchValue=lstrlenW(val->name);
3202 } else {
3203 *lpszValue = 0;
3204 *lpcchValue = 0;
3207 /* Can be NULL if the type code is not required */
3208 if (lpdwType)
3209 *lpdwType = val->type;
3211 if (lpbData) {
3212 if (val->len>*lpcbData) {
3213 *lpcbData = val->len;
3214 return ERROR_MORE_DATA;
3216 memcpy(lpbData,val->data,val->len);
3217 *lpcbData = val->len;
3220 debug_print_value ( val->data, val );
3221 return ERROR_SUCCESS;
3225 /******************************************************************************
3226 * RegEnumValue32A [ADVAPI32.141]
3228 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3229 LPDWORD lpcchValue, LPDWORD lpdReserved,
3230 LPDWORD lpdwType, LPBYTE lpbData,
3231 LPDWORD lpcbData )
3233 LPWSTR lpszValueW;
3234 LPBYTE lpbDataW;
3235 DWORD ret,lpcbDataW;
3236 DWORD dwType;
3238 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3239 lpdReserved,lpdwType,lpbData,lpcbData);
3241 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3242 if (lpbData) {
3243 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3244 lpcbDataW = *lpcbData;
3245 } else
3246 lpbDataW = NULL;
3248 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3249 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3251 if (lpdwType)
3252 *lpdwType = dwType;
3254 if (ret==ERROR_SUCCESS) {
3255 lstrcpyWtoA(lpszValue,lpszValueW);
3256 if (lpbData) {
3257 if ((1<<dwType) & UNICONVMASK) {
3258 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3259 } else {
3260 if (lpcbDataW > *lpcbData) {
3261 *lpcbData = lpcbDataW;
3262 ret = ERROR_MORE_DATA;
3263 } else
3264 memcpy(lpbData,lpbDataW,lpcbDataW);
3266 *lpcbData = lpcbDataW;
3269 if (lpbDataW) free(lpbDataW);
3270 if (lpszValueW) free(lpszValueW);
3271 return ret;
3275 /******************************************************************************
3276 * RegEnumValue16 [KERNEL.223]
3278 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3279 LPDWORD lpcchValue, LPDWORD lpdReserved,
3280 LPDWORD lpdwType, LPBYTE lpbData,
3281 LPDWORD lpcbData )
3283 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3284 lpdReserved,lpdwType,lpbData,lpcbData);
3285 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3286 lpdwType, lpbData, lpcbData );
3290 /******************************************************************************
3291 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3292 * Releases the handle of the specified key
3294 * PARAMS
3295 * hkey [I] Handle of key to close
3297 * RETURNS
3298 * Success: ERROR_SUCCESS
3299 * Failure: Error code
3301 DWORD WINAPI RegCloseKey( HKEY hkey )
3303 TRACE_(reg)("(%x)\n",hkey);
3305 /* The standard handles are allowed to succeed, even though they are not
3306 closed */
3307 if (is_standard_hkey(hkey))
3308 return ERROR_SUCCESS;
3310 return remove_handle(hkey);
3315 * Delete registry key
3317 * Callpath:
3318 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3322 /******************************************************************************
3323 * RegDeleteKey32W [ADVAPI32.134]
3325 * PARAMS
3326 * hkey [I] Handle to open key
3327 * lpszSubKey [I] Name of subkey to delete
3329 * RETURNS
3330 * Success: ERROR_SUCCESS
3331 * Failure: Error code
3333 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3335 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3336 LPWSTR *wps;
3337 int wpc,i;
3339 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3341 lpNextKey = lookup_hkey(hkey);
3342 if (!lpNextKey)
3343 return ERROR_INVALID_HANDLE;
3345 /* Subkey param cannot be NULL */
3346 if (!lpszSubKey || !*lpszSubKey)
3347 return ERROR_BADKEY;
3349 /* We need to know the previous key in the hier. */
3350 split_keypath(lpszSubKey,&wps,&wpc);
3351 i = 0;
3352 lpxkey = lpNextKey;
3353 while (i<wpc-1) {
3354 lpxkey=lpNextKey->nextsub;
3355 while (lpxkey) {
3356 TRACE_(reg)(" Scanning [%s]\n",
3357 debugstr_w(lpxkey->keyname));
3358 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3359 break;
3360 lpxkey=lpxkey->next;
3362 if (!lpxkey) {
3363 FREE_KEY_PATH;
3364 TRACE_(reg)(" Not found.\n");
3365 /* not found is success */
3366 return ERROR_SUCCESS;
3368 i++;
3369 lpNextKey = lpxkey;
3371 lpxkey = lpNextKey->nextsub;
3372 lplpPrevKey = &(lpNextKey->nextsub);
3373 while (lpxkey) {
3374 TRACE_(reg)(" Scanning [%s]\n",
3375 debugstr_w(lpxkey->keyname));
3376 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3377 break;
3378 lplpPrevKey = &(lpxkey->next);
3379 lpxkey = lpxkey->next;
3382 if (!lpxkey) {
3383 FREE_KEY_PATH;
3384 WARN_(reg)(" Not found.\n");
3385 return ERROR_FILE_NOT_FOUND;
3388 if (lpxkey->nextsub) {
3389 FREE_KEY_PATH;
3390 WARN_(reg)(" Not empty.\n");
3391 return ERROR_CANTWRITE;
3393 *lplpPrevKey = lpxkey->next;
3394 free(lpxkey->keyname);
3395 if (lpxkey->class)
3396 free(lpxkey->class);
3397 if (lpxkey->values)
3398 free(lpxkey->values);
3399 free(lpxkey);
3400 FREE_KEY_PATH;
3401 TRACE_(reg)(" Done.\n");
3402 return ERROR_SUCCESS;
3406 /******************************************************************************
3407 * RegDeleteKey32A [ADVAPI32.133]
3409 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3411 LPWSTR lpszSubKeyW;
3412 DWORD ret;
3414 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3415 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3416 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3417 if(lpszSubKeyW) free(lpszSubKeyW);
3418 return ret;
3422 /******************************************************************************
3423 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3425 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3427 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3428 return RegDeleteKeyA( hkey, lpszSubKey );
3433 * Delete registry value
3435 * Callpath:
3436 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3440 /******************************************************************************
3441 * RegDeleteValue32W [ADVAPI32.136]
3443 * PARAMS
3444 * hkey [I]
3445 * lpszValue [I]
3447 * RETURNS
3449 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3451 DWORD i;
3452 LPKEYSTRUCT lpkey;
3453 LPKEYVALUE val;
3455 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3457 lpkey = lookup_hkey( hkey );
3458 if (!lpkey)
3459 return ERROR_INVALID_HANDLE;
3461 if (lpszValue) {
3462 for (i=0;i<lpkey->nrofvalues;i++)
3463 if ( lpkey->values[i].name &&
3464 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3466 break;
3467 } else {
3468 for (i=0;i<lpkey->nrofvalues;i++)
3469 if (lpkey->values[i].name==NULL)
3470 break;
3473 if (i == lpkey->nrofvalues)
3474 return ERROR_FILE_NOT_FOUND;
3476 val = lpkey->values+i;
3477 if (val->name) free(val->name);
3478 if (val->data) free(val->data);
3479 memcpy(
3480 lpkey->values+i,
3481 lpkey->values+i+1,
3482 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3484 lpkey->values = (LPKEYVALUE)xrealloc(
3485 lpkey->values,
3486 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3488 lpkey->nrofvalues--;
3489 return ERROR_SUCCESS;
3493 /******************************************************************************
3494 * RegDeleteValue32A [ADVAPI32.135]
3496 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3498 LPWSTR lpszValueW;
3499 DWORD ret;
3501 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3502 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3503 ret = RegDeleteValueW( hkey, lpszValueW );
3504 if(lpszValueW) free(lpszValueW);
3505 return ret;
3509 /******************************************************************************
3510 * RegDeleteValue16 [KERNEL.222]
3512 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3514 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3515 return RegDeleteValueA( hkey, lpszValue );
3519 /******************************************************************************
3520 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3521 * Immediately writes key to registry.
3522 * Only returns after data has been written to disk.
3524 * FIXME: does it really wait until data is written ?
3526 * I guess that we can remove the REG_OPTION_TAINTED flag from every key
3527 * written if this function really works (and only if !).
3529 * PARAMS
3530 * hkey [I] Handle of key to write
3532 * RETURNS
3533 * Success: ERROR_SUCCESS
3534 * Failure: Error code
3536 DWORD WINAPI RegFlushKey( HKEY hkey )
3538 LPKEYSTRUCT lpkey;
3540 TRACE_(reg)("(%x)\n", hkey);
3542 lpkey = lookup_hkey( hkey );
3543 if (!lpkey)
3544 return ERROR_BADKEY;
3546 SHELL_SaveRegistryBranch(find_root_key(lpkey), TRUE);
3547 return ERROR_SUCCESS;
3551 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3554 /******************************************************************************
3555 * RegQueryInfoKey32W [ADVAPI32.153]
3557 * PARAMS
3558 * hkey [I] Handle to key to query
3559 * lpszClass [O] Buffer for class string
3560 * lpcchClass [O] Size of class string buffer
3561 * lpdwReserved [I] Reserved
3562 * lpcSubKeys [I] Buffer for number of subkeys
3563 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3564 * lpcchMaxClass [O] Buffer for longest class string length
3565 * lpcValues [O] Buffer for number of value entries
3566 * lpcchMaxValueName [O] Buffer for longest value name length
3567 * lpccbMaxValueData [O] Buffer for longest value data length
3568 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3569 * ft
3570 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3571 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3572 * lpcchClass is NULL
3573 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3574 * (it's hard to test validity, so test !NULL instead)
3576 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3577 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3578 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3579 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3580 LPDWORD lpcchMaxValueName,
3581 LPDWORD lpccbMaxValueData,
3582 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3584 LPKEYSTRUCT lpkey,lpxkey;
3585 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3586 int i;
3588 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3589 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3590 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3591 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3593 lpkey = lookup_hkey(hkey);
3594 if (!lpkey)
3595 return ERROR_INVALID_HANDLE;
3596 if (lpszClass) {
3597 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3598 return ERROR_INVALID_PARAMETER;
3600 /* either lpcchClass is valid or this is win95 and lpcchClass
3601 could be invalid */
3602 if (lpkey->class) {
3603 DWORD classLen = lstrlenW(lpkey->class);
3605 if (lpcchClass && classLen+1>*lpcchClass) {
3606 *lpcchClass=classLen+1;
3607 return ERROR_MORE_DATA;
3609 if (lpcchClass)
3610 *lpcchClass=classLen;
3611 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3612 } else {
3613 *lpszClass = 0;
3614 if (lpcchClass)
3615 *lpcchClass = 0;
3617 } else {
3618 if (lpcchClass)
3619 *lpcchClass = lstrlenW(lpkey->class);
3621 lpxkey=lpkey->nextsub;
3622 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3623 while (lpxkey) {
3624 nrofkeys++;
3625 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3626 maxsubkey=lstrlenW(lpxkey->keyname);
3627 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3628 maxclass=lstrlenW(lpxkey->class);
3629 lpxkey=lpxkey->next;
3631 for (i=0;i<lpkey->nrofvalues;i++) {
3632 LPKEYVALUE val=lpkey->values+i;
3634 if (val->name && lstrlenW(val->name)>maxvname)
3635 maxvname=lstrlenW(val->name);
3636 if (val->len>maxvdata)
3637 maxvdata=val->len;
3639 if (!maxclass) maxclass = 1;
3640 if (!maxvname) maxvname = 1;
3641 if (lpcValues)
3642 *lpcValues = lpkey->nrofvalues;
3643 if (lpcSubKeys)
3644 *lpcSubKeys = nrofkeys;
3645 if (lpcchMaxSubkey)
3646 *lpcchMaxSubkey = maxsubkey;
3647 if (lpcchMaxClass)
3648 *lpcchMaxClass = maxclass;
3649 if (lpcchMaxValueName)
3650 *lpcchMaxValueName= maxvname;
3651 if (lpccbMaxValueData)
3652 *lpccbMaxValueData= maxvdata;
3653 return ERROR_SUCCESS;
3657 /******************************************************************************
3658 * RegQueryInfoKey32A [ADVAPI32.152]
3660 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3661 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3662 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3663 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3664 LPDWORD lpccbMaxValueData,
3665 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3667 LPWSTR lpszClassW = NULL;
3668 DWORD ret;
3670 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3671 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3672 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3673 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3675 if (lpszClass) {
3676 if (lpcchClass) {
3677 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3678 } else if (VERSION_GetVersion() == WIN95) {
3679 /* win95 allows lpcchClass to be null */
3680 /* we don't know how big lpszClass is, would
3681 MAX_PATHNAME_LEN be the correct default? */
3682 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3685 } else
3686 lpszClassW = NULL;
3687 ret=RegQueryInfoKeyW(
3688 hkey,
3689 lpszClassW,
3690 lpcchClass,
3691 lpdwReserved,
3692 lpcSubKeys,
3693 lpcchMaxSubkey,
3694 lpcchMaxClass,
3695 lpcValues,
3696 lpcchMaxValueName,
3697 lpccbMaxValueData,
3698 lpcbSecurityDescriptor,
3701 if (ret==ERROR_SUCCESS && lpszClass)
3702 lstrcpyWtoA(lpszClass,lpszClassW);
3703 if (lpszClassW)
3704 free(lpszClassW);
3705 return ret;
3709 /******************************************************************************
3710 * RegConnectRegistry32W [ADVAPI32.128]
3712 * PARAMS
3713 * lpMachineName [I] Address of name of remote computer
3714 * hHey [I] Predefined registry handle
3715 * phkResult [I] Address of buffer for remote registry handle
3717 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3718 LPHKEY phkResult )
3720 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3722 if (!lpMachineName || !*lpMachineName) {
3723 /* Use the local machine name */
3724 return RegOpenKey16( hKey, "", phkResult );
3727 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3728 return ERROR_BAD_NETPATH;
3732 /******************************************************************************
3733 * RegConnectRegistry32A [ADVAPI32.127]
3735 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3737 DWORD ret;
3738 LPWSTR machineW = strdupA2W(machine);
3739 ret = RegConnectRegistryW( machineW, hkey, reskey );
3740 free(machineW);
3741 return ret;
3745 /******************************************************************************
3746 * RegGetKeySecurity [ADVAPI32.144]
3747 * Retrieves a copy of security descriptor protecting the registry key
3749 * PARAMS
3750 * hkey [I] Open handle of key to set
3751 * SecurityInformation [I] Descriptor contents
3752 * pSecurityDescriptor [O] Address of descriptor for key
3753 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3755 * RETURNS
3756 * Success: ERROR_SUCCESS
3757 * Failure: Error code
3759 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3760 SECURITY_INFORMATION SecurityInformation,
3761 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3762 LPDWORD lpcbSecurityDescriptor )
3764 LPKEYSTRUCT lpkey;
3766 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3767 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3769 lpkey = lookup_hkey( hkey );
3770 if (!lpkey)
3771 return ERROR_INVALID_HANDLE;
3773 /* FIXME: Check for valid SecurityInformation values */
3775 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3776 return ERROR_INSUFFICIENT_BUFFER;
3778 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3779 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3781 return ERROR_SUCCESS;
3785 /******************************************************************************
3786 * RegLoadKey32W [ADVAPI32.???]
3788 * PARAMS
3789 * hkey [I] Handle of open key
3790 * lpszSubKey [I] Address of name of subkey
3791 * lpszFile [I] Address of filename for registry information
3793 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3795 LPKEYSTRUCT lpkey;
3796 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3798 /* Do this check before the hkey check */
3799 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3800 return ERROR_INVALID_PARAMETER;
3802 lpkey = lookup_hkey( hkey );
3803 if (!lpkey)
3804 return ERROR_INVALID_HANDLE;
3806 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3807 debugstr_w(lpszFile));
3809 return ERROR_SUCCESS;
3813 /******************************************************************************
3814 * RegLoadKey32A [ADVAPI32.???]
3816 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3818 LONG ret;
3819 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3820 LPWSTR lpszFileW = strdupA2W(lpszFile);
3821 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3822 if(lpszFileW) free(lpszFileW);
3823 if(lpszSubKeyW) free(lpszSubKeyW);
3824 return ret;
3828 /******************************************************************************
3829 * RegNotifyChangeKeyValue [ADVAPI32.???]
3831 * PARAMS
3832 * hkey [I] Handle of key to watch
3833 * fWatchSubTree [I] Flag for subkey notification
3834 * fdwNotifyFilter [I] Changes to be reported
3835 * hEvent [I] Handle of signaled event
3836 * fAsync [I] Flag for asynchronous reporting
3838 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3839 DWORD fdwNotifyFilter, HANDLE hEvent,
3840 BOOL fAsync )
3842 LPKEYSTRUCT lpkey;
3843 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3844 hEvent,fAsync);
3846 lpkey = lookup_hkey( hkey );
3847 if (!lpkey)
3848 return ERROR_INVALID_HANDLE;
3850 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3851 hEvent,fAsync);
3853 return ERROR_SUCCESS;
3857 /******************************************************************************
3858 * RegUnLoadKey32W [ADVAPI32.173]
3860 * PARAMS
3861 * hkey [I] Handle of open key
3862 * lpSubKey [I] Address of name of subkey to unload
3864 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3866 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3867 return ERROR_SUCCESS;
3871 /******************************************************************************
3872 * RegUnLoadKey32A [ADVAPI32.172]
3874 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3876 LONG ret;
3877 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3878 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3879 if(lpSubKeyW) free(lpSubKeyW);
3880 return ret;
3884 /******************************************************************************
3885 * RegSetKeySecurity [ADVAPI32.167]
3887 * PARAMS
3888 * hkey [I] Open handle of key to set
3889 * SecurityInfo [I] Descriptor contents
3890 * pSecurityDesc [I] Address of descriptor for key
3892 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3893 PSECURITY_DESCRIPTOR pSecurityDesc )
3895 LPKEYSTRUCT lpkey;
3897 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3899 /* It seems to perform this check before the hkey check */
3900 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3901 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3902 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3903 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3904 /* Param OK */
3905 } else
3906 return ERROR_INVALID_PARAMETER;
3908 if (!pSecurityDesc)
3909 return ERROR_INVALID_PARAMETER;
3911 lpkey = lookup_hkey( hkey );
3912 if (!lpkey)
3913 return ERROR_INVALID_HANDLE;
3915 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3917 return ERROR_SUCCESS;
3921 /******************************************************************************
3922 * RegSaveKey32W [ADVAPI32.166]
3924 * PARAMS
3925 * hkey [I] Handle of key where save begins
3926 * lpFile [I] Address of filename to save to
3927 * sa [I] Address of security structure
3929 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3930 LPSECURITY_ATTRIBUTES sa )
3932 LPKEYSTRUCT lpkey;
3934 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3936 /* It appears to do this check before the hkey check */
3937 if (!lpFile || !*lpFile)
3938 return ERROR_INVALID_PARAMETER;
3940 lpkey = lookup_hkey( hkey );
3941 if (!lpkey)
3942 return ERROR_INVALID_HANDLE;
3944 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3946 return ERROR_SUCCESS;
3950 /******************************************************************************
3951 * RegSaveKey32A [ADVAPI32.165]
3953 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3954 LPSECURITY_ATTRIBUTES sa )
3956 LONG ret;
3957 LPWSTR lpFileW = strdupA2W(lpFile);
3958 ret = RegSaveKeyW( hkey, lpFileW, sa );
3959 free(lpFileW);
3960 return ret;
3964 /******************************************************************************
3965 * RegRestoreKey32W [ADVAPI32.164]
3967 * PARAMS
3968 * hkey [I] Handle of key where restore begins
3969 * lpFile [I] Address of filename containing saved tree
3970 * dwFlags [I] Optional flags
3972 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3974 LPKEYSTRUCT lpkey;
3976 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3978 /* It seems to do this check before the hkey check */
3979 if (!lpFile || !*lpFile)
3980 return ERROR_INVALID_PARAMETER;
3982 lpkey = lookup_hkey( hkey );
3983 if (!lpkey)
3984 return ERROR_INVALID_HANDLE;
3986 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3988 /* Check for file existence */
3990 return ERROR_SUCCESS;
3994 /******************************************************************************
3995 * RegRestoreKey32A [ADVAPI32.163]
3997 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3999 LONG ret;
4000 LPWSTR lpFileW = strdupA2W(lpFile);
4001 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
4002 if(lpFileW) free(lpFileW);
4003 return ret;
4007 /******************************************************************************
4008 * RegReplaceKey32W [ADVAPI32.162]
4010 * PARAMS
4011 * hkey [I] Handle of open key
4012 * lpSubKey [I] Address of name of subkey
4013 * lpNewFile [I] Address of filename for file with new data
4014 * lpOldFile [I] Address of filename for backup file
4016 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
4017 LPCWSTR lpOldFile )
4019 LPKEYSTRUCT lpkey;
4021 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
4022 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4024 lpkey = lookup_hkey( hkey );
4025 if (!lpkey)
4026 return ERROR_INVALID_HANDLE;
4028 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
4029 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
4031 return ERROR_SUCCESS;
4035 /******************************************************************************
4036 * RegReplaceKey32A [ADVAPI32.161]
4038 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
4039 LPCSTR lpOldFile )
4041 LONG ret;
4042 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4043 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4044 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4045 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4046 free(lpOldFileW);
4047 free(lpNewFileW);
4048 free(lpSubKeyW);
4049 return ret;