Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbejy@wpi.edu>
[wine/multimedia.git] / misc / registry.c
blobd55b46aad60ea2b3605d10c7f8af74c705764e3a
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/fcntl.h>
30 #include <sys/stat.h>
31 #include <pwd.h>
32 #include <assert.h>
33 #include <time.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wine/winbase16.h"
37 #include "wine/winestring.h"
38 #include "winerror.h"
39 #include "file.h"
40 #include "heap.h"
41 #include "debug.h"
42 #include "xmalloc.h"
43 #include "options.h"
44 #include "winreg.h"
45 #include "winversion.h"
47 DECLARE_DEBUG_CHANNEL(reg)
48 DECLARE_DEBUG_CHANNEL(string)
50 static void REGISTRY_Init(void);
51 /* FIXME: following defines should be configured global ... */
53 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
54 #define WINE_PREFIX "/.wine"
55 #define SAVE_USERS_DEFAULT "/usr/local/etc/wine.userreg"
56 #define SAVE_LOCAL_MACHINE_DEFAULT "/usr/local/etc/wine.systemreg"
58 /* relative in ~user/.wine/ : */
59 #define SAVE_CURRENT_USER "user.reg"
60 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
61 #define SAVE_LOCAL_MACHINE "system.reg"
63 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
64 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
66 /* one value of a key */
67 typedef struct tagKEYVALUE
69 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
70 DWORD type; /* type of value */
71 DWORD len; /* length of data in BYTEs */
72 DWORD lastmodified; /* time of seconds since 1.1.1970 */
73 LPBYTE data; /* content, may be strings, binaries, etc. */
74 } KEYVALUE,*LPKEYVALUE;
76 /* a registry key */
77 typedef struct tagKEYSTRUCT
79 LPWSTR keyname; /* name of THIS key (UNICODE) */
80 DWORD flags; /* flags. */
81 LPWSTR class;
82 /* values */
83 DWORD nrofvalues; /* nr of values in THIS key */
84 LPKEYVALUE values; /* values in THIS key */
85 /* key management pointers */
86 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
87 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
88 } KEYSTRUCT, *LPKEYSTRUCT;
91 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
92 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
93 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
94 static KEYSTRUCT *key_users=NULL; /* all users? */
96 /* dynamic, not saved */
97 static KEYSTRUCT *key_performance_data=NULL;
98 static KEYSTRUCT *key_current_config=NULL;
99 static KEYSTRUCT *key_dyn_data=NULL;
101 /* what valuetypes do we need to convert? */
102 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
105 static struct openhandle {
106 LPKEYSTRUCT lpkey;
107 HKEY hkey;
108 REGSAM accessmask;
109 } *openhandles=NULL;
110 static int nrofopenhandles=0;
111 /* Starts after 1 because 0,1 are reserved for Win16 */
112 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
113 HKEYs for remote registry access */
114 static int currenthandle=2;
118 * QUESTION
119 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
120 * If so, can we remove them?
121 * ANSWER
122 * No, the memory handling functions are called very often in here,
123 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
124 * loading 100 times slower. -MM
126 static LPWSTR strdupA2W(LPCSTR src)
128 if(src) {
129 LPWSTR dest=xmalloc(2*strlen(src)+2);
130 lstrcpyAtoW(dest,src);
131 return dest;
133 return NULL;
136 static LPWSTR strdupW(LPCWSTR a) {
137 LPWSTR b;
138 int len;
140 if(a) {
141 len=sizeof(WCHAR)*(lstrlenW(a)+1);
142 b=(LPWSTR)xmalloc(len);
143 memcpy(b,a,len);
144 return b;
146 return NULL;
149 LPWSTR strcvtA2W(LPCSTR src, int nchars)
152 LPWSTR dest = xmalloc (2 * nchars + 2);
154 lstrcpynAtoW(dest,src,nchars+1);
155 dest[nchars] = 0;
156 return dest;
159 * we need to convert A to W with '\0' in strings (MULTI_SZ)
162 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
163 { LPWSTR p = dst;
165 TRACE(reg,"\"%s\" %i\n",src, n);
167 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
169 return dst;
171 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
172 { LPSTR p = dst;
174 TRACE(string,"L\"%s\" %i\n",debugstr_w(src), n);
176 while (n-- > 0) *p++ = (CHAR)*src++;
178 return dst;
181 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
183 if (TRACE_ON(reg) && lpbData)
185 switch(key->type)
187 case HEX_REG_EXPAND_SZ:
188 case HEX_REG_SZ:
189 case REG_SZ:
190 TRACE(reg," Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
193 break;
195 case HEX_REG_DWORD:
196 case REG_DWORD:
197 TRACE(reg," Value %s, Data(dword)=0x%08lx\n",
198 debugstr_w(key->name),
199 (DWORD)*lpbData);
200 break;
202 case HEX_REG_MULTI_SZ:
203 case REG_MULTI_SZ:
205 int i;
206 LPCWSTR ptr = (LPCWSTR)lpbData;
207 for (i=0;ptr[0];i++)
209 TRACE(reg, " Value %s, MULTI_SZ(%i=%s)\n",
210 debugstr_w(key->name),
212 debugstr_w(ptr));
214 ptr += lstrlenW(ptr)+1;
217 break;
219 case HEX_REG_NONE:
220 case HEX_REG_BINARY:
221 case HEX_REG_LINK:
222 case HEX_REG_RESOURCE_LIST:
223 case HEX_REG_FULL_RESOURCE_DESCRIPTOR:
224 case REG_NONE:
225 case REG_LINK:
226 case REG_RESOURCE_LIST:
227 case REG_FULL_RESOURCE_DESCRIPTOR:
228 case REG_BINARY:
230 char szTemp[100]; /* 3*32 + 3 + 1 */
231 int i;
232 for ( i = 0; i < key->len ; i++)
234 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
235 if (i>=31)
237 sprintf (&(szTemp[i*3+3]),"...");
238 break;
241 TRACE(reg," Value %s, Data(raw)=(%s)\n",
242 debugstr_w(key->name),
243 szTemp);
245 break;
247 default:
248 FIXME(reg, " Value %s, Unknown data type %ld\n",
249 debugstr_w(key->name),
250 key->type);
251 } /* switch */
252 } /* if */
256 /******************************************************************************
257 * is_standard_hkey [Internal]
258 * Determines if a hkey is a standard key
260 static BOOL is_standard_hkey( HKEY hkey )
262 switch(hkey) {
263 case 0x00000000:
264 case 0x00000001:
265 case HKEY_CLASSES_ROOT:
266 case HKEY_CURRENT_CONFIG:
267 case HKEY_CURRENT_USER:
268 case HKEY_LOCAL_MACHINE:
269 case HKEY_USERS:
270 case HKEY_PERFORMANCE_DATA:
271 case HKEY_DYN_DATA:
272 return TRUE;
273 default:
274 return FALSE;
278 /******************************************************************************
279 * add_handle [Internal]
281 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
283 int i;
285 TRACE(reg,"(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
286 /* Check for duplicates */
287 for (i=0;i<nrofopenhandles;i++) {
288 if (openhandles[i].lpkey==lpkey) {
289 /* This is not really an error - the user is allowed to create
290 two (or more) handles to the same key */
291 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
293 if (openhandles[i].hkey==hkey) {
294 WARN(reg, "Adding handle %x twice\n",hkey);
297 openhandles=xrealloc( openhandles,
298 sizeof(struct openhandle)*(nrofopenhandles+1));
300 openhandles[i].lpkey = lpkey;
301 openhandles[i].hkey = hkey;
302 openhandles[i].accessmask = accessmask;
303 nrofopenhandles++;
307 /******************************************************************************
308 * get_handle [Internal]
310 * RETURNS
311 * Success: Pointer to key
312 * Failure: NULL
314 static LPKEYSTRUCT get_handle( HKEY hkey )
316 int i;
318 for (i=0; i<nrofopenhandles; i++)
319 if (openhandles[i].hkey == hkey)
320 return openhandles[i].lpkey;
321 WARN(reg, "Could not find handle 0x%x\n",hkey);
322 return NULL;
326 /******************************************************************************
327 * remove_handle [Internal]
329 * PARAMS
330 * hkey [I] Handle of key to remove
332 * RETURNS
333 * Success: ERROR_SUCCESS
334 * Failure: ERROR_INVALID_HANDLE
336 static DWORD remove_handle( HKEY hkey )
338 int i;
340 for (i=0;i<nrofopenhandles;i++)
341 if (openhandles[i].hkey==hkey)
342 break;
344 if (i == nrofopenhandles) {
345 WARN(reg, "Could not find handle 0x%x\n",hkey);
346 return ERROR_INVALID_HANDLE;
349 memcpy( openhandles+i,
350 openhandles+i+1,
351 sizeof(struct openhandle)*(nrofopenhandles-i-1)
353 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
354 nrofopenhandles--;
355 return ERROR_SUCCESS;
358 /******************************************************************************
359 * lookup_hkey [Internal]
361 * Just as the name says. Creates the root keys on demand, so we can call the
362 * Reg* functions at any time.
364 * RETURNS
365 * Success: Pointer to key structure
366 * Failure: NULL
368 #define ADD_ROOT_KEY(xx) \
369 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
370 memset(xx,'\0',sizeof(KEYSTRUCT));\
371 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
373 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
375 switch (hkey) {
376 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
377 * some programs. Do not remove those cases. -MM
379 case 0x00000000:
380 case 0x00000001:
381 case HKEY_CLASSES_ROOT:
383 if (!key_classes_root)
385 HKEY cl_r_hkey;
387 /* calls lookup_hkey recursively, TWICE */
388 if ( RegCreateKey16(
389 HKEY_LOCAL_MACHINE,
390 "SOFTWARE\\Classes",
391 &cl_r_hkey) != ERROR_SUCCESS)
393 ERR(
394 reg,
395 "Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
396 exit(1);
399 key_classes_root = lookup_hkey(cl_r_hkey);
401 return key_classes_root;
404 case HKEY_CURRENT_USER:
405 if (!key_current_user) {
406 ADD_ROOT_KEY(key_current_user);
408 return key_current_user;
410 case HKEY_LOCAL_MACHINE:
411 if (!key_local_machine) {
412 ADD_ROOT_KEY(key_local_machine);
413 REGISTRY_Init();
415 return key_local_machine;
417 case HKEY_USERS:
418 if (!key_users) {
419 ADD_ROOT_KEY(key_users);
421 return key_users;
423 case HKEY_PERFORMANCE_DATA:
424 if (!key_performance_data) {
425 ADD_ROOT_KEY(key_performance_data);
427 return key_performance_data;
429 case HKEY_DYN_DATA:
430 if (!key_dyn_data) {
431 ADD_ROOT_KEY(key_dyn_data);
433 return key_dyn_data;
435 case HKEY_CURRENT_CONFIG:
436 if (!key_current_config) {
437 ADD_ROOT_KEY(key_current_config);
439 return key_current_config;
441 default:
442 return get_handle(hkey);
445 /*NOTREACHED*/
447 #undef ADD_ROOT_KEY
448 /* so we don't accidently access them ... */
449 #define key_current_config NULL NULL
450 #define key_current_user NULL NULL
451 #define key_users NULL NULL
452 #define key_local_machine NULL NULL
453 #define key_classes_root NULL NULL
454 #define key_dyn_data NULL NULL
455 #define key_performance_data NULL NULL
457 /******************************************************************************
458 * split_keypath [Internal]
459 * splits the unicode string 'wp' into an array of strings.
460 * the array is allocated by this function.
461 * Free the array using FREE_KEY_PATH
463 * PARAMS
464 * wp [I] String to split up
465 * wpv [O] Array of pointers to strings
466 * wpc [O] Number of components
468 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
470 int i,j,len;
471 LPWSTR ws;
473 TRACE(reg,"(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
475 ws = HEAP_strdupW( SystemHeap, 0, wp );
477 /* We know we have at least one substring */
478 *wpc = 1;
480 /* Replace each backslash with NULL, and increment the count */
481 for (i=0;ws[i];i++) {
482 if (ws[i]=='\\') {
483 ws[i]=0;
484 (*wpc)++;
488 len = i;
490 /* Allocate the space for the array of pointers, leaving room for the
491 NULL at the end */
492 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
493 (*wpv)[0]= ws;
495 /* Assign each pointer to the appropriate character in the string */
496 j = 1;
497 for (i=1;i<len;i++)
498 if (ws[i-1]==0) {
499 (*wpv)[j++]=ws+i;
500 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
503 (*wpv)[j]=NULL;
505 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
510 /******************************************************************************
511 * REGISTRY_Init [Internal]
512 * Registry initialisation, allocates some default keys.
514 static void REGISTRY_Init(void) {
515 HKEY hkey;
516 char buf[200];
518 TRACE(reg,"(void)\n");
520 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
521 RegCloseKey(hkey);
523 /* This was an Open, but since it is called before the real registries
524 are loaded, it was changed to a Create - MTB 980507*/
525 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
526 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
527 RegCloseKey(hkey);
529 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
530 * CurrentVersion
531 * CurrentBuildNumber
532 * CurrentType
533 * string RegisteredOwner
534 * string RegisteredOrganization
537 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
538 * string SysContact
539 * string SysLocation
540 * SysServices
542 if (-1!=gethostname(buf,200)) {
543 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
544 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
545 RegCloseKey(hkey);
550 /************************ SAVE Registry Function ****************************/
552 #define REGISTRY_SAVE_VERSION 0x00000001
554 /* Registry saveformat:
555 * If you change it, increase above number by 1, which will flush
556 * old registry database files.
558 * Global:
559 * "WINE REGISTRY Version %d"
560 * subkeys....
561 * Subkeys:
562 * keyname
563 * valuename=lastmodified,type,data
564 * ...
565 * subkeys
566 * ...
567 * keyname,valuename,stringdata:
568 * the usual ascii characters from 0x00-0xff (well, not 0x00)
569 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
570 * ( "=\\\t" escaped in \uXXXX form.)
571 * type,lastmodified:
572 * int
574 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
576 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
577 * SaveOnlyUpdatedKeys=yes
580 /******************************************************************************
581 * _save_check_tainted [Internal]
583 static int _save_check_tainted( LPKEYSTRUCT lpkey )
585 int tainted;
587 if (!lpkey)
588 return 0;
589 if (lpkey->flags & REG_OPTION_TAINTED)
590 tainted = 1;
591 else
592 tainted = 0;
593 while (lpkey) {
594 if (_save_check_tainted(lpkey->nextsub)) {
595 lpkey->flags |= REG_OPTION_TAINTED;
596 tainted = 1;
598 lpkey = lpkey->next;
600 return tainted;
603 /******************************************************************************
604 * _save_USTRING [Internal]
606 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
608 LPWSTR s;
609 int doescape;
611 if (wstr==NULL)
612 return;
613 s=wstr;
614 while (*s) {
615 doescape=0;
616 if (*s>0xff)
617 doescape = 1;
618 if (*s=='\n')
619 doescape = 1;
620 if (escapeeq && *s=='=')
621 doescape = 1;
622 if (*s=='\\')
623 fputc(*s,F); /* if \\ then put it twice. */
624 if (doescape)
625 fprintf(F,"\\u%04x",*((unsigned short*)s));
626 else
627 fputc(*s,F);
628 s++;
632 /******************************************************************************
633 * _savesubkey [Internal]
635 * NOTES
636 * REG_MULTI_SZ is handled as binary (like in win95) (js)
638 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
640 LPKEYSTRUCT lpxkey;
641 int i,tabs,j;
643 lpxkey = lpkey;
644 while (lpxkey) {
645 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
646 (all || (lpxkey->flags & REG_OPTION_TAINTED))
648 for (tabs=level;tabs--;)
649 fputc('\t',F);
650 _save_USTRING(F,lpxkey->keyname,1);
651 fputs("\n",F);
652 for (i=0;i<lpxkey->nrofvalues;i++) {
653 LPKEYVALUE val=lpxkey->values+i;
655 for (tabs=level+1;tabs--;)
656 fputc('\t',F);
657 _save_USTRING(F,val->name,0);
658 fputc('=',F);
659 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
660 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
661 _save_USTRING(F,(LPWSTR)val->data,0);
662 else
663 for (j=0;j<val->len;j++)
664 fprintf(F,"%02x",*((unsigned char*)val->data+j));
665 fputs("\n",F);
667 /* descend recursively */
668 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
669 return 0;
671 lpxkey=lpxkey->next;
673 return 1;
677 /******************************************************************************
678 * _savesubreg [Internal]
680 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
682 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
683 _save_check_tainted(lpkey->nextsub);
684 return _savesubkey(F,lpkey->nextsub,0,all);
688 /******************************************************************************
689 * _savereg [Internal]
691 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
693 FILE *F;
695 F=fopen(fn,"w");
696 if (F==NULL) {
697 WARN(reg,"Couldn't open %s for writing: %s\n",
698 fn,strerror(errno)
700 return FALSE;
702 if (!_savesubreg(F,lpkey,all)) {
703 fclose(F);
704 unlink(fn);
705 WARN(reg,"Failed to save keys, perhaps no more diskspace for %s?\n",fn);
706 return FALSE;
708 fclose(F);
709 return TRUE;
713 /******************************************************************************
714 * SHELL_SaveRegistry [Internal]
716 void SHELL_SaveRegistry( void )
718 char *fn;
719 struct passwd *pwd;
720 char buf[4];
721 HKEY hkey;
722 int all;
723 int usedCfgUser = 0;
724 int usedCfgLM = 0;
726 TRACE(reg,"(void)\n");
728 all=0;
729 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
731 strcpy(buf,"yes");
733 else
735 DWORD len,junk,type;
737 len=4;
738 if ( (ERROR_SUCCESS!=RegQueryValueExA(
739 hkey,
740 VAL_SAVEUPDATED,
741 &junk,
742 &type,
743 buf,
744 &len)) || (type!=REG_SZ))
746 strcpy(buf,"yes");
748 RegCloseKey(hkey);
751 if (lstrcmpiA(buf,"yes"))
752 all=1;
754 pwd=getpwuid(getuid());
755 if ( (pwd!=NULL) && (pwd->pw_dir!=NULL))
757 char *tmp;
759 * Save HKEY_CURRENT_USER
760 * Try first saving according to the defined location in .winerc
762 fn = xmalloc( MAX_PATHNAME_LEN );
763 if (PROFILE_GetWineIniString (
764 "Registry",
765 "UserFileName",
766 "",
767 fn,
768 MAX_PATHNAME_LEN - 1))
770 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
771 usedCfgUser = 1;
773 free (fn);
775 if (usedCfgUser != 1)
777 fn=(char*)xmalloc(
778 strlen(pwd->pw_dir) +
779 strlen(WINE_PREFIX) +
780 strlen(SAVE_CURRENT_USER) + 2 );
782 strcpy(fn,pwd->pw_dir);
783 strcat(fn,WINE_PREFIX);
785 /* create the directory. don't care about errorcodes. */
786 mkdir(fn,0755); /* drwxr-xr-x */
787 strcat(fn,"/"SAVE_CURRENT_USER);
789 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
790 strcpy(tmp,fn);
791 strcat(tmp,".tmp");
793 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
794 if (-1==rename(tmp,fn)) {
795 perror("rename tmp registry");
796 unlink(tmp);
799 free(tmp);
800 free(fn);
804 * Save HKEY_LOCAL_MACHINE
805 * Try first saving according to the defined location in .winerc
807 fn = xmalloc ( MAX_PATHNAME_LEN);
808 if (PROFILE_GetWineIniString (
809 "Registry",
810 "LocalMachineFileName",
811 "",
812 fn,
813 MAX_PATHNAME_LEN - 1))
815 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
816 usedCfgLM = 1;
818 free (fn);
820 if ( usedCfgLM != 1)
822 fn=(char*)xmalloc(
823 strlen(pwd->pw_dir)+
824 strlen(WINE_PREFIX)+
825 strlen(SAVE_LOCAL_MACHINE)+2);
827 strcpy(fn,pwd->pw_dir);
828 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
830 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
831 strcpy(tmp,fn);
832 strcat(tmp,".tmp");
834 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
835 if (-1==rename(tmp,fn)) {
836 perror("rename tmp registry");
837 unlink(tmp);
840 free(tmp);
841 free(fn);
845 * Save HKEY_USERS
847 fn=(char*)xmalloc(
848 strlen(pwd->pw_dir)+
849 strlen(WINE_PREFIX)+
850 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
852 strcpy(fn,pwd->pw_dir);
853 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
855 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
856 strcpy(tmp,fn);strcat(tmp,".tmp");
857 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
858 if (-1==rename(tmp,fn)) {
859 perror("rename tmp registry");
860 unlink(tmp);
863 free(tmp);
864 free(fn);
866 else
868 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
873 /************************ LOAD Registry Function ****************************/
877 /******************************************************************************
878 * _find_or_add_key [Internal]
880 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
882 LPKEYSTRUCT lpxkey,*lplpkey;
884 if ((!keyname) || (keyname[0]==0)) {
885 free(keyname);
886 return lpkey;
888 lplpkey= &(lpkey->nextsub);
889 lpxkey = *lplpkey;
890 while (lpxkey) {
891 if ( (lpxkey->keyname[0]==keyname[0]) &&
892 !lstrcmpiW(lpxkey->keyname,keyname)
894 break;
895 lplpkey = &(lpxkey->next);
896 lpxkey = *lplpkey;
898 if (lpxkey==NULL) {
899 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
900 lpxkey = *lplpkey;
901 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
902 lpxkey->keyname = keyname;
903 } else
904 free(keyname);
905 return lpxkey;
908 /******************************************************************************
909 * _find_or_add_value [Internal]
911 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
912 LPBYTE data, DWORD len, DWORD lastmodified )
914 LPKEYVALUE val=NULL;
915 int i;
917 if (name && !*name) {/* empty string equals default (NULL) value */
918 free(name);
919 name = NULL;
922 for (i=0;i<lpkey->nrofvalues;i++) {
923 val=lpkey->values+i;
924 if (name==NULL) {
925 if (val->name==NULL)
926 break;
927 } else {
928 if ( val->name!=NULL &&
929 val->name[0]==name[0] &&
930 !lstrcmpiW(val->name,name)
932 break;
935 if (i==lpkey->nrofvalues) {
936 lpkey->values = xrealloc(
937 lpkey->values,
938 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
940 val=lpkey->values+i;
941 memset(val,'\0',sizeof(KEYVALUE));
942 val->name = name;
943 } else {
944 if (name)
945 free(name);
947 if (val->lastmodified<lastmodified) {
948 val->lastmodified=lastmodified;
949 val->type = type;
951 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
953 data=xmalloc(sizeof(WCHAR));
954 memset(data,0,sizeof(WCHAR));
955 len =sizeof(WCHAR);
958 val->len = len;
959 if (val->data)
960 free(val->data);
961 val->data = data;
962 } else
963 free(data);
967 /******************************************************************************
968 * _wine_read_line [Internal]
970 * reads a line including dynamically enlarging the readbuffer and throwing
971 * away comments
973 static int _wine_read_line( FILE *F, char **buf, int *len )
975 char *s,*curread;
976 int mylen,curoff;
978 curread = *buf;
979 mylen = *len;
980 **buf = '\0';
981 while (1) {
982 while (1) {
983 s=fgets(curread,mylen,F);
984 if (s==NULL)
985 return 0; /* EOF */
986 if (NULL==(s=strchr(curread,'\n'))) {
987 /* buffer wasn't large enough */
988 curoff = strlen(*buf);
989 *buf = xrealloc(*buf,*len*2);
990 curread = *buf + curoff;
991 mylen = *len; /* we filled up the buffer and
992 * got new '*len' bytes to fill
994 *len = *len * 2;
995 } else {
996 *s='\0';
997 break;
1000 /* throw away comments */
1001 if (**buf=='#' || **buf==';') {
1002 curread = *buf;
1003 mylen = *len;
1004 continue;
1006 if (s) /* got end of line */
1007 break;
1009 return 1;
1013 /******************************************************************************
1014 * _wine_read_USTRING [Internal]
1016 * converts a char* into a UNICODE string (up to a special char)
1017 * and returns the position exactly after that string
1019 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
1021 char *s;
1022 LPWSTR ws;
1024 /* read up to "=" or "\0" or "\n" */
1025 s = buf;
1026 if (*s == '=') {
1027 /* empty string is the win3.1 default value(NULL)*/
1028 *str = NULL;
1029 return s;
1031 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
1032 ws = *str;
1033 while (*s && (*s!='\n') && (*s!='=')) {
1034 if (*s!='\\')
1035 *ws++=*((unsigned char*)s++);
1036 else {
1037 s++;
1038 if (!*s) {
1039 /* Dangling \ ... may only happen if a registry
1040 * write was short. FIXME: What do to?
1042 break;
1044 if (*s=='\\') {
1045 *ws++='\\';
1046 s++;
1047 continue;
1049 if (*s!='u') {
1050 WARN(reg,"Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1051 *ws++='\\';
1052 *ws++=*s++;
1053 } else {
1054 char xbuf[5];
1055 int wc;
1057 s++;
1058 memcpy(xbuf,s,4);xbuf[4]='\0';
1059 if (!sscanf(xbuf,"%x",&wc))
1060 WARN(reg,"Strange escape sequence %s found in |%s|\n",xbuf,buf);
1061 s+=4;
1062 *ws++ =(unsigned short)wc;
1066 *ws = 0;
1067 ws = *str;
1068 if (*ws)
1069 *str = strdupW(*str);
1070 else
1071 *str = NULL;
1072 free(ws);
1073 return s;
1077 /******************************************************************************
1078 * _wine_loadsubkey [Internal]
1080 * NOTES
1081 * It seems like this is returning a boolean. Should it?
1083 * RETURNS
1084 * Success: 1
1085 * Failure: 0
1087 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1088 int *buflen, DWORD optflag )
1090 LPKEYSTRUCT lpxkey;
1091 int i;
1092 char *s;
1093 LPWSTR name;
1095 TRACE(reg,"(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1096 *buflen, optflag);
1098 lpkey->flags |= optflag;
1100 /* Good. We already got a line here ... so parse it */
1101 lpxkey = NULL;
1102 while (1) {
1103 i=0;s=*buf;
1104 while (*s=='\t') {
1105 s++;
1106 i++;
1108 if (i>level) {
1109 if (lpxkey==NULL) {
1110 WARN(reg,"Got a subhierarchy without resp. key?\n");
1111 return 0;
1113 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1114 continue;
1117 /* let the caller handle this line */
1118 if (i<level || **buf=='\0')
1119 return 1;
1121 /* it can be: a value or a keyname. Parse the name first */
1122 s=_wine_read_USTRING(s,&name);
1124 /* switch() default: hack to avoid gotos */
1125 switch (0) {
1126 default:
1127 if (*s=='\0') {
1128 lpxkey=_find_or_add_key(lpkey,name);
1129 } else {
1130 LPBYTE data;
1131 int len,lastmodified,type;
1133 if (*s!='=') {
1134 WARN(reg,"Unexpected character: %c\n",*s);
1135 break;
1137 s++;
1138 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1139 WARN(reg,"Haven't understood possible value in |%s|, skipping.\n",*buf);
1140 break;
1142 /* skip the 2 , */
1143 s=strchr(s,',');s++;
1144 s=strchr(s,',');s++;
1145 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1146 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1147 if (data)
1148 len = lstrlenW((LPWSTR)data)*2+2;
1149 else
1150 len = 0;
1151 } else {
1152 len=strlen(s)/2;
1153 data = (LPBYTE)xmalloc(len+1);
1154 for (i=0;i<len;i++) {
1155 data[i]=0;
1156 if (*s>='0' && *s<='9')
1157 data[i]=(*s-'0')<<4;
1158 if (*s>='a' && *s<='f')
1159 data[i]=(*s-'a'+'\xa')<<4;
1160 if (*s>='A' && *s<='F')
1161 data[i]=(*s-'A'+'\xa')<<4;
1162 s++;
1163 if (*s>='0' && *s<='9')
1164 data[i]|=*s-'0';
1165 if (*s>='a' && *s<='f')
1166 data[i]|=*s-'a'+'\xa';
1167 if (*s>='A' && *s<='F')
1168 data[i]|=*s-'A'+'\xa';
1169 s++;
1172 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1175 /* read the next line */
1176 if (!_wine_read_line(F,buf,buflen))
1177 return 1;
1179 return 1;
1183 /******************************************************************************
1184 * _wine_loadsubreg [Internal]
1186 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1188 int ver;
1189 char *buf;
1190 int buflen;
1192 buf=xmalloc(10);buflen=10;
1193 if (!_wine_read_line(F,&buf,&buflen)) {
1194 free(buf);
1195 return 0;
1197 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1198 free(buf);
1199 return 0;
1201 if (ver!=REGISTRY_SAVE_VERSION) {
1202 TRACE(reg,"Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1203 free(buf);
1204 return 0;
1206 if (!_wine_read_line(F,&buf,&buflen)) {
1207 free(buf);
1208 return 0;
1210 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1211 free(buf);
1212 return 0;
1214 free(buf);
1215 return 1;
1219 /******************************************************************************
1220 * _wine_loadreg [Internal]
1222 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1224 FILE *F;
1226 TRACE(reg,"(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1228 F = fopen(fn,"rb");
1229 if (F==NULL) {
1230 WARN(reg,"Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1231 return;
1233 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1234 fclose(F);
1235 unlink(fn);
1236 return;
1238 fclose(F);
1241 /******************************************************************************
1242 * _flush_registry [Internal]
1244 * This function allow to flush section of the internal registry. It is mainly
1245 * implements to fix a problem with the global HKU and the local HKU.
1246 * Those two files are read to build the HKU\.Default branch to finaly copy
1247 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1248 * all the global HKU are saved onto the user's personal version of HKU hive.
1249 * which is bad...
1252 /* Forward declaration of recusive agent */
1253 static void _flush_reg(LPKEYSTRUCT from);
1255 static void _flush_registry( LPKEYSTRUCT from )
1257 /* make sure we have something... */
1258 if (from == NULL)
1259 return;
1261 /* Launch the recusive agent on sub branches */
1262 _flush_reg( from->nextsub );
1263 _flush_reg( from->next );
1265 /* Initialize pointers */
1266 from->nextsub = NULL;
1267 from->next = NULL;
1269 static void _flush_reg( LPKEYSTRUCT from )
1271 int j;
1273 /* make sure we have something... */
1274 if (from == NULL)
1275 return;
1278 * do the same for the child keys
1280 if (from->nextsub != NULL)
1281 _flush_reg(from->nextsub);
1284 * do the same for the sibling keys
1286 if (from->next != NULL)
1287 _flush_reg(from->next);
1290 * iterate through this key's values and delete them
1292 for (j=0;j<from->nrofvalues;j++)
1294 free( (from->values+j)->name);
1295 free( (from->values+j)->data);
1299 * free the structure
1301 if ( from != NULL )
1302 free(from);
1306 /******************************************************************************
1307 * _copy_registry [Internal]
1309 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1311 LPKEYSTRUCT lpxkey;
1312 int j;
1313 LPKEYVALUE valfrom;
1315 from=from->nextsub;
1316 while (from) {
1317 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1319 for (j=0;j<from->nrofvalues;j++) {
1320 LPWSTR name;
1321 LPBYTE data;
1323 valfrom = from->values+j;
1324 name=valfrom->name;
1325 if (name) name=strdupW(name);
1326 data=(LPBYTE)xmalloc(valfrom->len);
1327 memcpy(data,valfrom->data,valfrom->len);
1329 _find_or_add_value(
1330 lpxkey,
1331 name,
1332 valfrom->type,
1333 data,
1334 valfrom->len,
1335 valfrom->lastmodified
1338 _copy_registry(from,lpxkey);
1339 from = from->next;
1344 /* WINDOWS 95 REGISTRY LOADER */
1346 * Structure of a win95 registry database.
1347 * main header:
1348 * 0 : "CREG" - magic
1349 * 4 : DWORD version
1350 * 8 : DWORD offset_of_RGDB_part
1351 * 0C..0F: ? (someone fill in please)
1352 * 10: WORD number of RGDB blocks
1353 * 12: WORD ?
1354 * 14: WORD always 0000?
1355 * 16: WORD always 0001?
1356 * 18..1F: ? (someone fill in please)
1358 * 20: RGKN_section:
1359 * header:
1360 * 0 : "RGKN" - magic
1361 * 4 : DWORD offset to first RGDB section
1362 * 8 : DWORD offset to the root record
1363 * C..0x1B: ? (fill in)
1364 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1366 * Disk Key Entry Structure:
1367 * 00: DWORD - Free entry indicator(?)
1368 * 04: DWORD - Hash = sum of bytes of keyname
1369 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1370 * 0C: DWORD - disk address of PreviousLevel Key.
1371 * 10: DWORD - disk address of Next Sublevel Key.
1372 * 14: DWORD - disk address of Next Key (on same level).
1373 * DKEP>18: WORD - Nr, Low Significant part.
1374 * 1A: WORD - Nr, High Significant part.
1376 * The disk address always points to the nr part of the previous key entry
1377 * of the referenced key. Don't ask me why, or even if I got this correct
1378 * from staring at 1kg of hexdumps. (DKEP)
1380 * The High significant part of the structure seems to equal the number
1381 * of the RGDB section. The low significant part is a unique ID within
1382 * that RGDB section
1384 * There are two minor corrections to the position of that structure.
1385 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1386 * the DKE reread from there.
1387 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1388 * CPS - I have not experienced the above phenomenon in my registry files
1390 * RGDB_section:
1391 * 00: "RGDB" - magic
1392 * 04: DWORD offset to next RGDB section
1393 * 08: DWORD ?
1394 * 0C: WORD always 000d?
1395 * 0E: WORD RGDB block number
1396 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1397 * 14..1F: ?
1398 * 20.....: disk keys
1400 * disk key:
1401 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1402 * 08: WORD nrLS - low significant part of NR
1403 * 0A: WORD nrHS - high significant part of NR
1404 * 0C: DWORD bytesused - bytes used in this structure.
1405 * 10: WORD name_len - length of name in bytes. without \0
1406 * 12: WORD nr_of_values - number of values.
1407 * 14: char name[name_len] - name string. No \0.
1408 * 14+name_len: disk values
1409 * nextkeyoffset: ... next disk key
1411 * disk value:
1412 * 00: DWORD type - value type (hmm, could be WORD too)
1413 * 04: DWORD - unknown, usually 0
1414 * 08: WORD namelen - length of Name. 0 means name=NULL
1415 * 0C: WORD datalen - length of Data.
1416 * 10: char name[namelen] - name, no \0
1417 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1418 * 10+namelen+datalen: next values or disk key
1420 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1421 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1422 * structure) and reading another RGDB_section.
1423 * repeat until end of file.
1425 * An interesting relationship exists in RGDB_section. The value at offset
1426 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1427 * idea at the moment what this means. (Kevin Cozens)
1429 * FIXME: this description needs some serious help, yes.
1432 struct _w95keyvalue {
1433 unsigned long type;
1434 unsigned short datalen;
1435 char *name;
1436 unsigned char *data;
1437 unsigned long x1;
1438 int lastmodified;
1441 struct _w95key {
1442 char *name;
1443 int nrofvals;
1444 struct _w95keyvalue *values;
1445 struct _w95key *prevlvl;
1446 struct _w95key *nextsub;
1447 struct _w95key *next;
1451 struct _w95_info {
1452 char *rgknbuffer;
1453 int rgknsize;
1454 char *rgdbbuffer;
1455 int rgdbsize;
1456 int depth;
1457 int lastmodified;
1461 /******************************************************************************
1462 * _w95_processKey [Internal]
1464 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1465 int nrLS, int nrMS, struct _w95_info *info )
1468 /* Disk Key Header structure (RGDB part) */
1469 struct dkh {
1470 unsigned long nextkeyoff;
1471 unsigned short nrLS;
1472 unsigned short nrMS;
1473 unsigned long bytesused;
1474 unsigned short keynamelen;
1475 unsigned short values;
1476 unsigned long xx1;
1477 /* keyname */
1478 /* disk key values or nothing */
1480 /* Disk Key Value structure */
1481 struct dkv {
1482 unsigned long type;
1483 unsigned long x1;
1484 unsigned short valnamelen;
1485 unsigned short valdatalen;
1486 /* valname, valdata */
1490 struct dkh dkh;
1491 int bytesread = 0;
1492 char *rgdbdata = info->rgdbbuffer;
1493 int nbytes = info->rgdbsize;
1494 char *curdata = rgdbdata;
1495 char *end = rgdbdata + nbytes;
1496 int off_next_rgdb;
1497 char *next = rgdbdata;
1498 int nrgdb, i;
1499 LPKEYSTRUCT lpxkey;
1501 do {
1502 curdata = next;
1503 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1505 memcpy(&off_next_rgdb,curdata+4,4);
1506 next = curdata + off_next_rgdb;
1507 nrgdb = (int) *((short *)curdata + 7);
1509 } while (nrgdb != nrMS && (next < end));
1511 /* curdata now points to the start of the right RGDB section */
1512 curdata += 0x20;
1514 #define XREAD(whereto,len) \
1515 if ((curdata + len) <= end) {\
1516 memcpy(whereto,curdata,len);\
1517 curdata+=len;\
1518 bytesread+=len;\
1521 while (curdata < next) {
1522 struct dkh *xdkh = (struct dkh*)curdata;
1524 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1525 if (xdkh->nrLS == nrLS) {
1526 memcpy(&dkh,xdkh,sizeof(dkh));
1527 curdata += sizeof(dkh);
1528 break;
1530 curdata += xdkh->nextkeyoff;
1533 if (dkh.nrLS != nrLS) return (NULL);
1535 if (nrgdb != dkh.nrMS)
1536 return (NULL);
1538 assert((dkh.keynamelen<2) || curdata[0]);
1539 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1540 curdata += dkh.keynamelen;
1542 for (i=0;i< dkh.values; i++) {
1543 struct dkv dkv;
1544 LPBYTE data;
1545 int len;
1546 LPWSTR name;
1548 XREAD(&dkv,sizeof(dkv));
1550 name = strcvtA2W(curdata, dkv.valnamelen);
1551 curdata += dkv.valnamelen;
1553 if ((1 << dkv.type) & UNICONVMASK) {
1554 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1555 len = 2*(dkv.valdatalen + 1);
1556 } else {
1557 /* I don't think we want to NULL terminate all data */
1558 data = xmalloc(dkv.valdatalen);
1559 memcpy (data, curdata, dkv.valdatalen);
1560 len = dkv.valdatalen;
1563 curdata += dkv.valdatalen;
1565 _find_or_add_value(
1566 lpxkey,
1567 name,
1568 dkv.type,
1569 data,
1570 len,
1571 info->lastmodified
1574 return (lpxkey);
1577 /******************************************************************************
1578 * _w95_walkrgkn [Internal]
1580 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1581 struct _w95_info *info )
1584 /* Disk Key Entry structure (RGKN part) */
1585 struct dke {
1586 unsigned long x1;
1587 unsigned long x2;
1588 unsigned long x3;/*usually 0xFFFFFFFF */
1589 unsigned long prevlvl;
1590 unsigned long nextsub;
1591 unsigned long next;
1592 unsigned short nrLS;
1593 unsigned short nrMS;
1594 } *dke = (struct dke *)off;
1595 LPKEYSTRUCT lpxkey;
1597 if (dke == NULL) {
1598 dke = (struct dke *) ((char *)info->rgknbuffer);
1601 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1602 /* XXX <-- This is a hack*/
1603 if (!lpxkey) {
1604 lpxkey = prevkey;
1607 if (dke->nextsub != -1 &&
1608 ((dke->nextsub - 0x20) < info->rgknsize)
1609 && (dke->nextsub > 0x20)) {
1611 _w95_walkrgkn(lpxkey,
1612 info->rgknbuffer + dke->nextsub - 0x20,
1613 info);
1616 if (dke->next != -1 &&
1617 ((dke->next - 0x20) < info->rgknsize) &&
1618 (dke->next > 0x20)) {
1619 _w95_walkrgkn(prevkey,
1620 info->rgknbuffer + dke->next - 0x20,
1621 info);
1624 return;
1628 /******************************************************************************
1629 * _w95_loadreg [Internal]
1631 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1633 HFILE hfd;
1634 char magic[5];
1635 unsigned long where,version,rgdbsection,end;
1636 struct _w95_info info;
1637 OFSTRUCT ofs;
1638 BY_HANDLE_FILE_INFORMATION hfdinfo;
1640 TRACE(reg,"Loading Win95 registry database '%s'\n",fn);
1641 hfd=OpenFile(fn,&ofs,OF_READ);
1642 if (hfd==HFILE_ERROR)
1643 return;
1644 magic[4]=0;
1645 if (4!=_lread(hfd,magic,4))
1646 return;
1647 if (strcmp(magic,"CREG")) {
1648 WARN(reg,"%s is not a w95 registry.\n",fn);
1649 return;
1651 if (4!=_lread(hfd,&version,4))
1652 return;
1653 if (4!=_lread(hfd,&rgdbsection,4))
1654 return;
1655 if (-1==_llseek(hfd,0x20,SEEK_SET))
1656 return;
1657 if (4!=_lread(hfd,magic,4))
1658 return;
1659 if (strcmp(magic,"RGKN")) {
1660 WARN(reg, "second IFF header not RGKN, but %s\n", magic);
1661 return;
1664 /* STEP 1: Keylink structures */
1665 if (-1==_llseek(hfd,0x40,SEEK_SET))
1666 return;
1667 where = 0x40;
1668 end = rgdbsection;
1670 info.rgknsize = end - where;
1671 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1672 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1673 return;
1675 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1676 return;
1678 end = hfdinfo.nFileSizeLow;
1679 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1681 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1682 return;
1684 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1685 info.rgdbsize = end - rgdbsection;
1687 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1688 return;
1689 _lclose(hfd);
1691 _w95_walkrgkn(lpkey, NULL, &info);
1693 free (info.rgdbbuffer);
1694 free (info.rgknbuffer);
1698 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1701 reghack - windows 3.11 registry data format demo program.
1703 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1704 a combined hash table and tree description, and finally a text table.
1706 The header is obvious from the struct header. The taboff1 and taboff2
1707 fields are always 0x20, and their usage is unknown.
1709 The 8-byte entry table has various entry types.
1711 tabent[0] is a root index. The second word has the index of the root of
1712 the directory.
1713 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1714 the index of the key/value that has that hash. Data with the same
1715 hash value are on a circular list. The other three words in the
1716 hash entry are always zero.
1717 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1718 entry: dirent and keyent/valent. They are identified by context.
1719 tabent[freeidx] is the first free entry. The first word in a free entry
1720 is the index of the next free entry. The last has 0 as a link.
1721 The other three words in the free list are probably irrelevant.
1723 Entries in text table are preceeded by a word at offset-2. This word
1724 has the value (2*index)+1, where index is the referring keyent/valent
1725 entry in the table. I have no suggestion for the 2* and the +1.
1726 Following the word, there are N bytes of data, as per the keyent/valent
1727 entry length. The offset of the keyent/valent entry is from the start
1728 of the text table to the first data byte.
1730 This information is not available from Microsoft. The data format is
1731 deduced from the reg.dat file by me. Mistakes may
1732 have been made. I claim no rights and give no guarantees for this program.
1734 Tor Sjøwall, tor@sn.no
1737 /* reg.dat header format */
1738 struct _w31_header {
1739 char cookie[8]; /* 'SHCC3.10' */
1740 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1741 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1742 unsigned long tabcnt; /* number of entries in index table */
1743 unsigned long textoff; /* offset of text part */
1744 unsigned long textsize; /* byte size of text part */
1745 unsigned short hashsize; /* hash size */
1746 unsigned short freeidx; /* free index */
1749 /* generic format of table entries */
1750 struct _w31_tabent {
1751 unsigned short w0, w1, w2, w3;
1754 /* directory tabent: */
1755 struct _w31_dirent {
1756 unsigned short sibling_idx; /* table index of sibling dirent */
1757 unsigned short child_idx; /* table index of child dirent */
1758 unsigned short key_idx; /* table index of key keyent */
1759 unsigned short value_idx; /* table index of value valent */
1762 /* key tabent: */
1763 struct _w31_keyent {
1764 unsigned short hash_idx; /* hash chain index for string */
1765 unsigned short refcnt; /* reference count */
1766 unsigned short length; /* length of string */
1767 unsigned short string_off; /* offset of string in text table */
1770 /* value tabent: */
1771 struct _w31_valent {
1772 unsigned short hash_idx; /* hash chain index for string */
1773 unsigned short refcnt; /* reference count */
1774 unsigned short length; /* length of string */
1775 unsigned short string_off; /* offset of string in text table */
1778 /* recursive helper function to display a directory tree */
1779 void
1780 __w31_dumptree( unsigned short idx,
1781 unsigned char *txt,
1782 struct _w31_tabent *tab,
1783 struct _w31_header *head,
1784 LPKEYSTRUCT lpkey,
1785 time_t lastmodified,
1786 int level
1788 struct _w31_dirent *dir;
1789 struct _w31_keyent *key;
1790 struct _w31_valent *val;
1791 LPKEYSTRUCT xlpkey = NULL;
1792 LPWSTR name,value;
1793 static char tail[400];
1795 while (idx!=0) {
1796 dir=(struct _w31_dirent*)&tab[idx];
1798 if (dir->key_idx) {
1799 key = (struct _w31_keyent*)&tab[dir->key_idx];
1801 memcpy(tail,&txt[key->string_off],key->length);
1802 tail[key->length]='\0';
1803 /* all toplevel entries AND the entries in the
1804 * toplevel subdirectory belong to \SOFTWARE\Classes
1806 if (!level && !lstrcmpA(tail,".classes")) {
1807 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1808 idx=dir->sibling_idx;
1809 continue;
1811 name=strdupA2W(tail);
1813 xlpkey=_find_or_add_key(lpkey,name);
1815 /* only add if leaf node or valued node */
1816 if (dir->value_idx!=0||dir->child_idx==0) {
1817 if (dir->value_idx) {
1818 val=(struct _w31_valent*)&tab[dir->value_idx];
1819 memcpy(tail,&txt[val->string_off],val->length);
1820 tail[val->length]='\0';
1821 value=strdupA2W(tail);
1822 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1825 } else {
1826 TRACE(reg,"strange: no directory key name, idx=%04x\n", idx);
1828 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1829 idx=dir->sibling_idx;
1834 /******************************************************************************
1835 * _w31_loadreg [Internal]
1837 void _w31_loadreg(void) {
1838 HFILE hf;
1839 struct _w31_header head;
1840 struct _w31_tabent *tab;
1841 unsigned char *txt;
1842 int len;
1843 OFSTRUCT ofs;
1844 BY_HANDLE_FILE_INFORMATION hfinfo;
1845 time_t lastmodified;
1846 LPKEYSTRUCT lpkey;
1848 TRACE(reg,"(void)\n");
1850 hf = OpenFile("reg.dat",&ofs,OF_READ);
1851 if (hf==HFILE_ERROR)
1852 return;
1854 /* read & dump header */
1855 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1856 ERR(reg, "reg.dat is too short.\n");
1857 _lclose(hf);
1858 return;
1860 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1861 ERR(reg, "reg.dat has bad signature.\n");
1862 _lclose(hf);
1863 return;
1866 len = head.tabcnt * sizeof(struct _w31_tabent);
1867 /* read and dump index table */
1868 tab = xmalloc(len);
1869 if (len!=_lread(hf,tab,len)) {
1870 ERR(reg,"couldn't read %d bytes.\n",len);
1871 free(tab);
1872 _lclose(hf);
1873 return;
1876 /* read text */
1877 txt = xmalloc(head.textsize);
1878 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1879 ERR(reg,"couldn't seek to textblock.\n");
1880 free(tab);
1881 free(txt);
1882 _lclose(hf);
1883 return;
1885 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1886 ERR(reg,"textblock too short (%d instead of %ld).\n",len,head.textsize);
1887 free(tab);
1888 free(txt);
1889 _lclose(hf);
1890 return;
1893 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1894 ERR(reg,"GetFileInformationByHandle failed?.\n");
1895 free(tab);
1896 free(txt);
1897 _lclose(hf);
1898 return;
1900 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1901 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1902 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1903 free(tab);
1904 free(txt);
1905 _lclose(hf);
1906 return;
1910 /**********************************************************************************
1911 * SHELL_LoadRegistry [Internal]
1913 void SHELL_LoadRegistry( void )
1915 char *fn;
1916 struct passwd *pwd;
1917 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1918 HKEY hkey;
1920 TRACE(reg,"(void)\n");
1922 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1923 HKU = lookup_hkey(HKEY_USERS);
1924 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1926 /* Load windows 3.1 entries */
1927 _w31_loadreg();
1928 /* Load windows 95 entries */
1929 _w95_loadreg("C:\\system.1st", HKLM);
1930 _w95_loadreg("system.dat", HKLM);
1931 _w95_loadreg("user.dat", HKU);
1934 * Load the global HKU hive directly from /usr/local/etc
1936 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1939 * Load the global machine defaults directly form /usr/local/etc
1941 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1943 /* Get current user info */
1944 pwd=getpwuid(getuid());
1947 * Load the user saved registries
1949 if ( (pwd != NULL) &&
1950 (pwd->pw_dir != NULL) )
1953 * Load user's personal versions of global HKU/.Default keys
1955 fn=(char*)xmalloc(
1956 strlen(pwd->pw_dir)+
1957 strlen(WINE_PREFIX)+
1958 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1960 strcpy(fn, pwd->pw_dir);
1961 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1962 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1963 free(fn);
1966 * Load HKCU, attempt to get the registry location from the config
1967 * file first, if exist, load and keep going.
1969 fn = xmalloc( MAX_PATHNAME_LEN );
1970 if ( PROFILE_GetWineIniString(
1971 "Registry",
1972 "UserFileName",
1973 "",
1974 fn,
1975 MAX_PATHNAME_LEN - 1))
1977 _wine_loadreg(HKCU,fn,0);
1979 free (fn);
1981 fn=(char*)xmalloc(
1982 strlen(pwd->pw_dir)+
1983 strlen(WINE_PREFIX)+
1984 strlen(SAVE_CURRENT_USER)+2);
1986 strcpy(fn, pwd->pw_dir);
1987 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1988 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1989 free(fn);
1992 * Load HKLM, attempt to get the registry location from the config
1993 * file first, if exist, load and keep going.
1995 fn = xmalloc ( MAX_PATHNAME_LEN);
1996 if ( PROFILE_GetWineIniString(
1997 "Registry",
1998 "LocalMachineFileName",
1999 "",
2000 fn,
2001 MAX_PATHNAME_LEN - 1))
2003 _wine_loadreg(HKLM, fn, 0);
2005 free(fn);
2007 fn=(char*)xmalloc(
2008 strlen(pwd->pw_dir)+
2009 strlen(WINE_PREFIX)+
2010 strlen(SAVE_LOCAL_MACHINE)+2);
2012 strcpy(fn,pwd->pw_dir);
2013 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
2014 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
2015 free(fn);
2017 else
2019 WARN(reg,"Failed to get homedirectory of UID %d.\n",getuid());
2023 * Obtain the handle of the HKU\.Default key.
2024 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
2026 RegCreateKey16(HKEY_USERS,".Default",&hkey);
2027 lpkey = lookup_hkey(hkey);
2028 if(!lpkey)
2029 WARN(reg,"Could not create global user default key\n");
2030 else
2031 _copy_registry(lpkey, HKCU );
2033 RegCloseKey(hkey);
2036 * Since HKU is built from the global HKU and the local user HKU file we must
2037 * flush the HKU tree we have built at this point otherwise the part brought
2038 * in from the global HKU is saved into the local HKU. To avoid this
2039 * useless dupplication of HKU keys we reread the local HKU key.
2042 /* Allways flush the HKU hive and reload it only with user's personal HKU */
2043 _flush_registry(HKU);
2045 /* Reload user's local HKU hive */
2046 fn=(char*)xmalloc(
2047 strlen(pwd->pw_dir)+
2048 strlen(WINE_PREFIX)+
2049 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
2051 strcpy(fn,pwd->pw_dir);
2052 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2054 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2056 free(fn);
2059 * Make sure the update mode is there
2061 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2063 DWORD junk,type,len;
2064 char data[5];
2066 len=4;
2067 if (( RegQueryValueExA(
2068 hkey,
2069 VAL_SAVEUPDATED,
2070 &junk,
2071 &type,
2072 data,
2073 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2075 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2078 RegCloseKey(hkey);
2083 /********************* API FUNCTIONS ***************************************/
2085 * Open Keys.
2087 * All functions are stubs to RegOpenKeyEx32W where all the
2088 * magic happens.
2090 * Callpath:
2091 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2092 * RegOpenKey32W -> RegOpenKeyEx32W
2096 /******************************************************************************
2097 * RegOpenKeyEx32W [ADVAPI32.150]
2098 * Opens the specified key
2100 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2102 * PARAMS
2103 * hkey [I] Handle of open key
2104 * lpszSubKey [I] Name of subkey to open
2105 * dwReserved [I] Reserved - must be zero
2106 * samDesired [I] Security access mask
2107 * retkey [O] Address of handle of open key
2109 * RETURNS
2110 * Success: ERROR_SUCCESS
2111 * Failure: Error code
2113 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2114 REGSAM samDesired, LPHKEY retkey )
2116 LPKEYSTRUCT lpNextKey,lpxkey;
2117 LPWSTR *wps;
2118 int wpc,i;
2120 TRACE(reg,"(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2121 samDesired,retkey);
2123 lpNextKey = lookup_hkey( hkey );
2124 if (!lpNextKey)
2125 return ERROR_INVALID_HANDLE;
2127 if (!lpszSubKey || !*lpszSubKey) {
2128 /* Either NULL or pointer to empty string, so return a new handle
2129 to the original hkey */
2130 currenthandle += 2;
2131 add_handle(currenthandle,lpNextKey,samDesired);
2132 *retkey=currenthandle;
2133 return ERROR_SUCCESS;
2136 if (lpszSubKey[0] == '\\') {
2137 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2138 return ERROR_BAD_PATHNAME;
2141 split_keypath(lpszSubKey,&wps,&wpc);
2142 i = 0;
2143 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2144 lpxkey = lpNextKey;
2146 while (wps[i]) {
2147 lpxkey=lpNextKey->nextsub;
2148 while (lpxkey) {
2149 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2150 break;
2152 lpxkey=lpxkey->next;
2155 if (!lpxkey) {
2156 TRACE(reg,"Could not find subkey %s\n",debugstr_w(wps[i]));
2157 FREE_KEY_PATH;
2158 return ERROR_FILE_NOT_FOUND;
2160 i++;
2161 lpNextKey = lpxkey;
2164 currenthandle += 2;
2165 add_handle(currenthandle,lpxkey,samDesired);
2166 *retkey = currenthandle;
2167 TRACE(reg," Returning %x\n", currenthandle);
2168 FREE_KEY_PATH;
2169 return ERROR_SUCCESS;
2173 /******************************************************************************
2174 * RegOpenKeyEx32A [ADVAPI32.149]
2176 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2177 REGSAM samDesired, LPHKEY retkey )
2179 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2180 DWORD ret;
2182 TRACE(reg,"(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2183 samDesired,retkey);
2184 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2185 free(lpszSubKeyW);
2186 return ret;
2190 /******************************************************************************
2191 * RegOpenKey32W [ADVAPI32.151]
2193 * PARAMS
2194 * hkey [I] Handle of open key
2195 * lpszSubKey [I] Address of name of subkey to open
2196 * retkey [O] Address of handle of open key
2198 * RETURNS
2199 * Success: ERROR_SUCCESS
2200 * Failure: Error code
2202 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2204 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2205 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2209 /******************************************************************************
2210 * RegOpenKey32A [ADVAPI32.148]
2212 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2214 DWORD ret;
2215 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2216 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2217 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2218 free(lpszSubKeyW);
2219 return ret;
2223 /******************************************************************************
2224 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2226 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2228 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2229 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2234 * Create keys
2236 * All those functions convert their respective
2237 * arguments and call RegCreateKeyExW at the end.
2239 * We stay away from the Ex functions as long as possible because there are
2240 * differences in the return values
2242 * Callpath:
2243 * RegCreateKeyEx32A \
2244 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2248 /******************************************************************************
2249 * RegCreateKeyEx32W [ADVAPI32.131]
2251 * PARAMS
2252 * hkey [I] Handle of an open key
2253 * lpszSubKey [I] Address of subkey name
2254 * dwReserved [I] Reserved - must be 0
2255 * lpszClass [I] Address of class string
2256 * fdwOptions [I] Special options flag
2257 * samDesired [I] Desired security access
2258 * lpSecAttribs [I] Address of key security structure
2259 * retkey [O] Address of buffer for opened handle
2260 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2262 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2263 DWORD dwReserved, LPWSTR lpszClass,
2264 DWORD fdwOptions, REGSAM samDesired,
2265 LPSECURITY_ATTRIBUTES lpSecAttribs,
2266 LPHKEY retkey, LPDWORD lpDispos )
2268 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2269 LPWSTR *wps;
2270 int wpc,i;
2272 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2273 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2274 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2276 lpNextKey = lookup_hkey(hkey);
2277 if (!lpNextKey)
2278 return ERROR_INVALID_HANDLE;
2280 /* Check for valid options */
2281 switch(fdwOptions) {
2282 case REG_OPTION_NON_VOLATILE:
2283 case REG_OPTION_VOLATILE:
2284 case REG_OPTION_BACKUP_RESTORE:
2285 break;
2286 default:
2287 return ERROR_INVALID_PARAMETER;
2290 /* Sam has to be a combination of the following */
2291 if (!(samDesired &
2292 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2293 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2294 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2295 return ERROR_INVALID_PARAMETER;
2297 if (!lpszSubKey || !*lpszSubKey) {
2298 currenthandle += 2;
2299 add_handle(currenthandle,lpNextKey,samDesired);
2300 *retkey=currenthandle;
2301 TRACE(reg, "Returning %x\n", currenthandle);
2302 lpNextKey->flags|=REG_OPTION_TAINTED;
2303 return ERROR_SUCCESS;
2306 if (lpszSubKey[0] == '\\') {
2307 WARN(reg,"Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2308 return ERROR_BAD_PATHNAME;
2311 split_keypath(lpszSubKey,&wps,&wpc);
2312 i = 0;
2313 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2314 lpxkey = lpNextKey;
2315 while (wps[i]) {
2316 lpxkey=lpNextKey->nextsub;
2317 while (lpxkey) {
2318 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2319 break;
2320 lpxkey=lpxkey->next;
2322 if (!lpxkey)
2323 break;
2324 i++;
2325 lpNextKey = lpxkey;
2327 if (lpxkey) {
2328 currenthandle += 2;
2329 add_handle(currenthandle,lpxkey,samDesired);
2330 lpxkey->flags |= REG_OPTION_TAINTED;
2331 *retkey = currenthandle;
2332 TRACE(reg, "Returning %x\n", currenthandle);
2333 if (lpDispos)
2334 *lpDispos = REG_OPENED_EXISTING_KEY;
2335 FREE_KEY_PATH;
2336 return ERROR_SUCCESS;
2339 /* Good. Now the hard part */
2340 while (wps[i]) {
2341 lplpPrevKey = &(lpNextKey->nextsub);
2342 lpxkey = *lplpPrevKey;
2343 while (lpxkey) {
2344 lplpPrevKey = &(lpxkey->next);
2345 lpxkey = *lplpPrevKey;
2347 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2348 if (!*lplpPrevKey) {
2349 FREE_KEY_PATH;
2350 TRACE(reg, "Returning OUTOFMEMORY\n");
2351 return ERROR_OUTOFMEMORY;
2353 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2354 TRACE(reg,"Adding %s\n", debugstr_w(wps[i]));
2355 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2356 (*lplpPrevKey)->next = NULL;
2357 (*lplpPrevKey)->nextsub = NULL;
2358 (*lplpPrevKey)->values = NULL;
2359 (*lplpPrevKey)->nrofvalues = 0;
2360 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2361 if (lpszClass)
2362 (*lplpPrevKey)->class = strdupW(lpszClass);
2363 else
2364 (*lplpPrevKey)->class = NULL;
2365 lpNextKey = *lplpPrevKey;
2366 i++;
2368 currenthandle += 2;
2369 add_handle(currenthandle,lpNextKey,samDesired);
2371 /*FIXME: flag handling correct? */
2372 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2373 if (lpszClass)
2374 lpNextKey->class = strdupW(lpszClass);
2375 else
2376 lpNextKey->class = NULL;
2377 *retkey = currenthandle;
2378 TRACE(reg, "Returning %x\n", currenthandle);
2379 if (lpDispos)
2380 *lpDispos = REG_CREATED_NEW_KEY;
2381 FREE_KEY_PATH;
2382 return ERROR_SUCCESS;
2386 /******************************************************************************
2387 * RegCreateKeyEx32A [ADVAPI32.130]
2389 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2390 LPSTR lpszClass, DWORD fdwOptions,
2391 REGSAM samDesired,
2392 LPSECURITY_ATTRIBUTES lpSecAttribs,
2393 LPHKEY retkey, LPDWORD lpDispos )
2395 LPWSTR lpszSubKeyW, lpszClassW;
2396 DWORD ret;
2398 TRACE(reg,"(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2399 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2400 retkey,lpDispos);
2402 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2403 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2405 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2406 fdwOptions, samDesired, lpSecAttribs, retkey,
2407 lpDispos );
2409 if(lpszSubKeyW) free(lpszSubKeyW);
2410 if(lpszClassW) free(lpszClassW);
2412 return ret;
2416 /******************************************************************************
2417 * RegCreateKey32W [ADVAPI32.132]
2419 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2421 DWORD junk;
2422 LPKEYSTRUCT lpNextKey;
2424 TRACE(reg,"(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2426 /* This check is here because the return value is different than the
2427 one from the Ex functions */
2428 lpNextKey = lookup_hkey(hkey);
2429 if (!lpNextKey)
2430 return ERROR_BADKEY;
2432 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2433 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2434 retkey, &junk);
2438 /******************************************************************************
2439 * RegCreateKey32A [ADVAPI32.129]
2441 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2443 DWORD ret;
2444 LPWSTR lpszSubKeyW;
2446 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2447 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2448 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2449 if(lpszSubKeyW) free(lpszSubKeyW);
2450 return ret;
2454 /******************************************************************************
2455 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2457 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2459 TRACE(reg,"(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2460 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2465 * Query Value Functions
2466 * Win32 differs between keynames and valuenames.
2467 * multiple values may belong to one key, the special value
2468 * with name NULL is the default value used by the win31
2469 * compat functions.
2471 * Callpath:
2472 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2473 * RegQueryValue32W -> RegQueryValueEx32W
2477 /******************************************************************************
2478 * RegQueryValueEx32W [ADVAPI32.158]
2479 * Retrieves type and data for a specified name associated with an open key
2481 * PARAMS
2482 * hkey [I] Handle of key to query
2483 * lpValueName [I] Name of value to query
2484 * lpdwReserved [I] Reserved - must be NULL
2485 * lpdwType [O] Address of buffer for value type. If NULL, the type
2486 * is not required.
2487 * lpbData [O] Address of data buffer. If NULL, the actual data is
2488 * not required.
2489 * lpcbData [I/O] Address of data buffer size
2491 * RETURNS
2492 * ERROR_SUCCESS: Success
2493 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2494 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2496 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPWSTR lpValueName,
2497 LPDWORD lpdwReserved, LPDWORD lpdwType,
2498 LPBYTE lpbData, LPDWORD lpcbData )
2500 LPKEYSTRUCT lpkey;
2501 int i;
2502 DWORD ret;
2504 TRACE(reg,"(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2505 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2507 lpkey = lookup_hkey(hkey);
2509 if (!lpkey)
2510 return ERROR_INVALID_HANDLE;
2512 if ((lpbData && ! lpcbData) || lpdwReserved)
2513 return ERROR_INVALID_PARAMETER;
2515 /* An empty name string is equivalent to NULL */
2516 if (lpValueName && !*lpValueName)
2517 lpValueName = NULL;
2519 if (lpValueName==NULL)
2520 { /* Use key's unnamed or default value, if any */
2521 for (i=0;i<lpkey->nrofvalues;i++)
2522 if (lpkey->values[i].name==NULL)
2523 break;
2525 else
2526 { /* Search for the key name */
2527 for (i=0;i<lpkey->nrofvalues;i++)
2528 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2529 break;
2532 if (i==lpkey->nrofvalues)
2533 { TRACE(reg," Key not found\n");
2534 if (lpValueName==NULL)
2535 { /* Empty keyname not found */
2536 if (lpbData)
2537 { *(WCHAR*)lpbData = 0;
2538 *lpcbData = 2;
2540 if (lpdwType)
2541 *lpdwType = REG_SZ;
2542 TRACE(reg, " Returning an empty string\n");
2543 return ERROR_SUCCESS;
2545 return ERROR_FILE_NOT_FOUND;
2548 ret = ERROR_SUCCESS;
2550 if (lpdwType) /* type required ?*/
2551 *lpdwType = lpkey->values[i].type;
2553 if (lpbData) /* data required ?*/
2554 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2555 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2556 else
2557 ret = ERROR_MORE_DATA;
2560 if (lpcbData) /* size required ?*/
2561 { *lpcbData = lpkey->values[i].len;
2564 debug_print_value ( lpbData, &lpkey->values[i]);
2566 TRACE(reg," (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2568 return ret;
2572 /******************************************************************************
2573 * RegQueryValue32W [ADVAPI32.159]
2575 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2576 LPLONG lpcbData )
2578 HKEY xhkey;
2579 DWORD ret,lpdwType;
2581 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2582 lpcbData?*lpcbData:0);
2584 /* Only open subkey, if we really do descend */
2585 if (lpszSubKey && *lpszSubKey) {
2586 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2587 if (ret != ERROR_SUCCESS) {
2588 WARN(reg, "Could not open %s\n", debugstr_w(lpszSubKey));
2589 return ret;
2591 } else
2592 xhkey = hkey;
2594 lpdwType = REG_SZ;
2595 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2596 lpcbData );
2597 if (xhkey != hkey)
2598 RegCloseKey(xhkey);
2599 return ret;
2603 /******************************************************************************
2604 * RegQueryValueEx32A [ADVAPI32.157]
2606 * NOTES:
2607 * the documantation is wrong: if the buffer is to small it remains untouched
2609 * FIXME: check returnvalue (len) for an empty key
2611 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPSTR lpszValueName,
2612 LPDWORD lpdwReserved, LPDWORD lpdwType,
2613 LPBYTE lpbData, LPDWORD lpcbData )
2615 LPWSTR lpszValueNameW;
2616 LPBYTE mybuf = NULL;
2617 DWORD ret, mytype, mylen = 0;
2619 TRACE(reg,"(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2620 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2622 if (!lpcbData && lpbData) /* buffer without size is illegal */
2623 { return ERROR_INVALID_PARAMETER;
2626 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2628 /* get just the type first */
2629 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2631 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2632 { if(lpszValueNameW) free(lpszValueNameW);
2633 return ret;
2636 if (lpcbData) /* at least length requested? */
2637 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2638 { if (lpbData ) /* value requested? */
2639 { mylen = 2*( *lpcbData );
2640 mybuf = (LPBYTE)xmalloc( mylen );
2643 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2645 if (ret == ERROR_SUCCESS )
2646 { if ( lpbData )
2647 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2651 *lpcbData = mylen/2; /* size is in byte! */
2653 else /* no strings, call it straight */
2654 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2658 if (lpdwType) /* type when requested */
2659 { *lpdwType = mytype;
2662 TRACE(reg," (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2664 if(mybuf) free(mybuf);
2665 if(lpszValueNameW) free(lpszValueNameW);
2666 return ret;
2670 /******************************************************************************
2671 * RegQueryValueEx16 [KERNEL.225]
2673 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2674 LPDWORD lpdwReserved, LPDWORD lpdwType,
2675 LPBYTE lpbData, LPDWORD lpcbData )
2677 TRACE(reg,"(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2678 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2679 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2680 lpbData, lpcbData );
2684 /******************************************************************************
2685 * RegQueryValue32A [ADVAPI32.156]
2687 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2688 LPLONG lpcbData )
2690 HKEY xhkey;
2691 DWORD ret, dwType;
2693 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2694 lpcbData?*lpcbData:0);
2696 if (lpszSubKey && *lpszSubKey) {
2697 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2698 if( ret != ERROR_SUCCESS )
2699 return ret;
2700 } else
2701 xhkey = hkey;
2703 dwType = REG_SZ;
2704 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2705 lpcbData );
2706 if( xhkey != hkey )
2707 RegCloseKey( xhkey );
2708 return ret;
2712 /******************************************************************************
2713 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2715 * NOTES
2716 * Is this HACK still applicable?
2718 * HACK
2719 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2720 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2721 * Aldus FH4)
2723 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2724 LPDWORD lpcbData )
2726 TRACE(reg,"(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2727 lpcbData?*lpcbData:0);
2729 if (lpcbData)
2730 *lpcbData &= 0xFFFF;
2731 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2736 * Setting values of Registry keys
2738 * Callpath:
2739 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2740 * RegSetValue32W -> RegSetValueEx32W
2744 /******************************************************************************
2745 * RegSetValueEx32W [ADVAPI32.170]
2746 * Sets the data and type of a value under a register key
2748 * PARAMS
2749 * hkey [I] Handle of key to set value for
2750 * lpszValueName [I] Name of value to set
2751 * dwReserved [I] Reserved - must be zero
2752 * dwType [I] Flag for value type
2753 * lpbData [I] Address of value data
2754 * cbData [I] Size of value data
2756 * RETURNS
2757 * Success: ERROR_SUCCESS
2758 * Failure: Error code
2760 * NOTES
2761 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2763 DWORD WINAPI RegSetValueExW( HKEY hkey, LPWSTR lpszValueName,
2764 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2765 DWORD cbData)
2767 LPKEYSTRUCT lpkey;
2768 int i;
2770 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2771 dwReserved, dwType, lpbData, cbData);
2773 lpkey = lookup_hkey( hkey );
2775 if (!lpkey)
2776 return ERROR_INVALID_HANDLE;
2778 lpkey->flags |= REG_OPTION_TAINTED;
2780 if (lpszValueName==NULL) {
2781 /* Sets type and name for key's unnamed or default value */
2782 for (i=0;i<lpkey->nrofvalues;i++)
2783 if (lpkey->values[i].name==NULL)
2784 break;
2785 } else {
2786 for (i=0;i<lpkey->nrofvalues;i++)
2787 if ( lpkey->values[i].name &&
2788 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2790 break;
2792 if (i==lpkey->nrofvalues) {
2793 lpkey->values = (LPKEYVALUE)xrealloc(
2794 lpkey->values,
2795 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2797 lpkey->nrofvalues++;
2798 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2800 if (lpkey->values[i].name==NULL) {
2801 if (lpszValueName)
2802 lpkey->values[i].name = strdupW(lpszValueName);
2803 else
2804 lpkey->values[i].name = NULL;
2807 if (dwType == REG_SZ)
2808 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2810 lpkey->values[i].len = cbData;
2811 lpkey->values[i].type = dwType;
2812 if (lpkey->values[i].data !=NULL)
2813 free(lpkey->values[i].data);
2814 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2815 lpkey->values[i].lastmodified = time(NULL);
2816 memcpy(lpkey->values[i].data,lpbData,cbData);
2817 return ERROR_SUCCESS;
2821 /******************************************************************************
2822 * RegSetValueEx32A [ADVAPI32.169]
2824 * NOTES
2825 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2827 DWORD WINAPI RegSetValueExA( HKEY hkey, LPSTR lpszValueName,
2828 DWORD dwReserved, DWORD dwType, LPBYTE lpbData,
2829 DWORD cbData )
2831 LPBYTE buf;
2832 LPWSTR lpszValueNameW;
2833 DWORD ret;
2835 if (!lpbData)
2836 return (ERROR_INVALID_PARAMETER);
2838 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2839 dwReserved,dwType,lpbData,cbData);
2841 if ((1<<dwType) & UNICONVMASK)
2842 { if (dwType == REG_SZ)
2843 cbData = strlen ((LPCSTR)lpbData)+1;
2845 buf = (LPBYTE)xmalloc( cbData *2 );
2846 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2847 cbData=2*cbData;
2849 else
2850 buf=lpbData;
2852 if (lpszValueName)
2853 lpszValueNameW = strdupA2W(lpszValueName);
2854 else
2855 lpszValueNameW = NULL;
2857 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2859 if (lpszValueNameW)
2860 free(lpszValueNameW);
2862 if (buf!=lpbData)
2863 free(buf);
2865 return ret;
2869 /******************************************************************************
2870 * RegSetValueEx16 [KERNEL.226]
2872 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2873 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2875 TRACE(reg,"(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2876 dwReserved,dwType,lpbData,cbData);
2877 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2878 cbData );
2882 /******************************************************************************
2883 * RegSetValue32W [ADVAPI32.171]
2885 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2886 LPCWSTR lpszData, DWORD cbData )
2888 HKEY xhkey;
2889 DWORD ret;
2891 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",
2892 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2894 if (lpszSubKey && *lpszSubKey) {
2895 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2896 if (ret!=ERROR_SUCCESS)
2897 return ret;
2898 } else
2899 xhkey=hkey;
2900 if (dwType!=REG_SZ) {
2901 TRACE(reg,"dwType=%ld - Changing to REG_SZ\n",dwType);
2902 dwType=REG_SZ;
2904 if (cbData!=2*lstrlenW(lpszData)+2) {
2905 TRACE(reg,"Len=%ld != strlen(%s)+1=%d!\n",
2906 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2908 cbData=2*lstrlenW(lpszData)+2;
2910 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2911 if (hkey!=xhkey)
2912 RegCloseKey(xhkey);
2913 return ret;
2917 /******************************************************************************
2918 * RegSetValue32A [ADVAPI32.168]
2921 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2922 LPCSTR lpszData, DWORD cbData )
2924 DWORD ret;
2925 HKEY xhkey;
2927 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2928 if (lpszSubKey && *lpszSubKey) {
2929 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2930 if (ret!=ERROR_SUCCESS)
2931 return ret;
2932 } else
2933 xhkey=hkey;
2935 if (dwType!=REG_SZ) {
2936 TRACE(reg,"dwType=%ld!\n",dwType);
2937 dwType=REG_SZ;
2939 if (cbData!=strlen(lpszData)+1)
2940 cbData=strlen(lpszData)+1;
2941 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2942 if (xhkey!=hkey)
2943 RegCloseKey(xhkey);
2944 return ret;
2948 /******************************************************************************
2949 * RegSetValue16 [KERNEL.221] [SHELL.5]
2951 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2952 LPCSTR lpszData, DWORD cbData )
2954 TRACE(reg,"(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2955 debugstr_a(lpszData),cbData);
2956 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2961 * Key Enumeration
2963 * Callpath:
2964 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2965 * RegEnumKey32W -> RegEnumKeyEx32W
2969 /******************************************************************************
2970 * RegEnumKeyEx32W [ADVAPI32.139]
2972 * PARAMS
2973 * hkey [I] Handle to key to enumerate
2974 * iSubKey [I] Index of subkey to enumerate
2975 * lpszName [O] Buffer for subkey name
2976 * lpcchName [O] Size of subkey buffer
2977 * lpdwReserved [I] Reserved
2978 * lpszClass [O] Buffer for class string
2979 * lpcchClass [O] Size of class buffer
2980 * ft [O] Time key last written to
2982 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2983 LPDWORD lpcchName, LPDWORD lpdwReserved,
2984 LPWSTR lpszClass, LPDWORD lpcchClass,
2985 FILETIME *ft )
2987 LPKEYSTRUCT lpkey,lpxkey;
2989 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2990 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2992 lpkey = lookup_hkey( hkey );
2993 if (!lpkey)
2994 return ERROR_INVALID_HANDLE;
2996 if (!lpkey->nextsub)
2997 return ERROR_NO_MORE_ITEMS;
2998 lpxkey=lpkey->nextsub;
3000 /* Traverse the subkeys */
3001 while (iSubkey && lpxkey) {
3002 iSubkey--;
3003 lpxkey=lpxkey->next;
3006 if (iSubkey || !lpxkey)
3007 return ERROR_NO_MORE_ITEMS;
3008 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
3009 return ERROR_MORE_DATA;
3010 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
3012 if (*lpcchName)
3013 *lpcchName = lstrlenW(lpszName);
3015 if (lpszClass) {
3016 /* FIXME: what should we write into it? */
3017 *lpszClass = 0;
3018 *lpcchClass = 2;
3020 return ERROR_SUCCESS;
3024 /******************************************************************************
3025 * RegEnumKey32W [ADVAPI32.140]
3027 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
3028 DWORD lpcchName )
3030 FILETIME ft;
3032 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3033 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
3037 /******************************************************************************
3038 * RegEnumKeyEx32A [ADVAPI32.138]
3040 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3041 LPDWORD lpcchName, LPDWORD lpdwReserved,
3042 LPSTR lpszClass, LPDWORD lpcchClass,
3043 FILETIME *ft )
3045 DWORD ret,lpcchNameW,lpcchClassW;
3046 LPWSTR lpszNameW,lpszClassW;
3049 TRACE(reg,"(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3050 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3052 if (lpszName) {
3053 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3054 lpcchNameW = *lpcchName;
3055 } else {
3056 lpszNameW = NULL;
3057 lpcchNameW = 0;
3059 if (lpszClass) {
3060 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3061 lpcchClassW = *lpcchClass;
3062 } else {
3063 lpszClassW =0;
3064 lpcchClassW=0;
3066 ret=RegEnumKeyExW(
3067 hkey,
3068 iSubkey,
3069 lpszNameW,
3070 &lpcchNameW,
3071 lpdwReserved,
3072 lpszClassW,
3073 &lpcchClassW,
3076 if (ret==ERROR_SUCCESS) {
3077 lstrcpyWtoA(lpszName,lpszNameW);
3078 *lpcchName=strlen(lpszName);
3079 if (lpszClassW) {
3080 lstrcpyWtoA(lpszClass,lpszClassW);
3081 *lpcchClass=strlen(lpszClass);
3084 if (lpszNameW)
3085 free(lpszNameW);
3086 if (lpszClassW)
3087 free(lpszClassW);
3088 return ret;
3092 /******************************************************************************
3093 * RegEnumKey32A [ADVAPI32.137]
3095 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3096 DWORD lpcchName )
3098 FILETIME ft;
3100 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3101 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3102 NULL, &ft );
3106 /******************************************************************************
3107 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3109 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3110 DWORD lpcchName )
3112 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3113 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3118 * Enumerate Registry Values
3120 * Callpath:
3121 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3125 /******************************************************************************
3126 * RegEnumValue32W [ADVAPI32.142]
3128 * PARAMS
3129 * hkey [I] Handle to key to query
3130 * iValue [I] Index of value to query
3131 * lpszValue [O] Value string
3132 * lpcchValue [I/O] Size of value buffer (in wchars)
3133 * lpdReserved [I] Reserved
3134 * lpdwType [O] Type code
3135 * lpbData [O] Value data
3136 * lpcbData [I/O] Size of data buffer (in bytes)
3138 * Note: wide character functions that take and/or return "character counts"
3139 * use TCHAR (that is unsigned short or char) not byte counts.
3141 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3142 LPDWORD lpcchValue, LPDWORD lpdReserved,
3143 LPDWORD lpdwType, LPBYTE lpbData,
3144 LPDWORD lpcbData )
3146 LPKEYSTRUCT lpkey;
3147 LPKEYVALUE val;
3149 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3150 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3152 lpkey = lookup_hkey( hkey );
3154 if (!lpcbData && lpbData)
3155 return ERROR_INVALID_PARAMETER;
3157 if (!lpkey)
3158 return ERROR_INVALID_HANDLE;
3160 if (lpkey->nrofvalues <= iValue)
3161 return ERROR_NO_MORE_ITEMS;
3163 val = &(lpkey->values[iValue]);
3165 if (val->name) {
3166 if (lstrlenW(val->name)+1>*lpcchValue) {
3167 *lpcchValue = lstrlenW(val->name)+1;
3168 return ERROR_MORE_DATA;
3170 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3171 *lpcchValue=lstrlenW(val->name);
3172 } else {
3173 *lpszValue = 0;
3174 *lpcchValue = 0;
3177 /* Can be NULL if the type code is not required */
3178 if (lpdwType)
3179 *lpdwType = val->type;
3181 if (lpbData) {
3182 if (val->len>*lpcbData)
3183 return ERROR_MORE_DATA;
3184 memcpy(lpbData,val->data,val->len);
3185 *lpcbData = val->len;
3188 debug_print_value ( val->data, val );
3189 return ERROR_SUCCESS;
3193 /******************************************************************************
3194 * RegEnumValue32A [ADVAPI32.141]
3196 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3197 LPDWORD lpcchValue, LPDWORD lpdReserved,
3198 LPDWORD lpdwType, LPBYTE lpbData,
3199 LPDWORD lpcbData )
3201 LPWSTR lpszValueW;
3202 LPBYTE lpbDataW;
3203 DWORD ret,lpcbDataW;
3204 DWORD dwType;
3206 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3207 lpdReserved,lpdwType,lpbData,lpcbData);
3209 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3210 if (lpbData) {
3211 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3212 lpcbDataW = *lpcbData;
3213 } else
3214 lpbDataW = NULL;
3216 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3217 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3219 if (lpdwType)
3220 *lpdwType = dwType;
3222 if (ret==ERROR_SUCCESS) {
3223 lstrcpyWtoA(lpszValue,lpszValueW);
3224 if (lpbData) {
3225 if ((1<<dwType) & UNICONVMASK) {
3226 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3227 } else {
3228 if (lpcbDataW > *lpcbData)
3229 ret = ERROR_MORE_DATA;
3230 else
3231 memcpy(lpbData,lpbDataW,lpcbDataW);
3233 *lpcbData = lpcbDataW;
3236 if (lpbDataW) free(lpbDataW);
3237 if (lpszValueW) free(lpszValueW);
3238 return ret;
3242 /******************************************************************************
3243 * RegEnumValue16 [KERNEL.223]
3245 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3246 LPDWORD lpcchValue, LPDWORD lpdReserved,
3247 LPDWORD lpdwType, LPBYTE lpbData,
3248 LPDWORD lpcbData )
3250 TRACE(reg,"(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3251 lpdReserved,lpdwType,lpbData,lpcbData);
3252 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3253 lpdwType, lpbData, lpcbData );
3257 /******************************************************************************
3258 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3259 * Releases the handle of the specified key
3261 * PARAMS
3262 * hkey [I] Handle of key to close
3264 * RETURNS
3265 * Success: ERROR_SUCCESS
3266 * Failure: Error code
3268 DWORD WINAPI RegCloseKey( HKEY hkey )
3270 TRACE(reg,"(%x)\n",hkey);
3272 /* The standard handles are allowed to succeed, even though they are not
3273 closed */
3274 if (is_standard_hkey(hkey))
3275 return ERROR_SUCCESS;
3277 return remove_handle(hkey);
3282 * Delete registry key
3284 * Callpath:
3285 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3289 /******************************************************************************
3290 * RegDeleteKey32W [ADVAPI32.134]
3292 * PARAMS
3293 * hkey [I] Handle to open key
3294 * lpszSubKey [I] Name of subkey to delete
3296 * RETURNS
3297 * Success: ERROR_SUCCESS
3298 * Failure: Error code
3300 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPWSTR lpszSubKey )
3302 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3303 LPWSTR *wps;
3304 int wpc,i;
3306 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3308 lpNextKey = lookup_hkey(hkey);
3309 if (!lpNextKey)
3310 return ERROR_INVALID_HANDLE;
3312 /* Subkey param cannot be NULL */
3313 if (!lpszSubKey || !*lpszSubKey)
3314 return ERROR_BADKEY;
3316 /* We need to know the previous key in the hier. */
3317 split_keypath(lpszSubKey,&wps,&wpc);
3318 i = 0;
3319 lpxkey = lpNextKey;
3320 while (i<wpc-1) {
3321 lpxkey=lpNextKey->nextsub;
3322 while (lpxkey) {
3323 TRACE(reg, " Scanning [%s]\n",
3324 debugstr_w(lpxkey->keyname));
3325 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3326 break;
3327 lpxkey=lpxkey->next;
3329 if (!lpxkey) {
3330 FREE_KEY_PATH;
3331 TRACE(reg, " Not found.\n");
3332 /* not found is success */
3333 return ERROR_SUCCESS;
3335 i++;
3336 lpNextKey = lpxkey;
3338 lpxkey = lpNextKey->nextsub;
3339 lplpPrevKey = &(lpNextKey->nextsub);
3340 while (lpxkey) {
3341 TRACE(reg, " Scanning [%s]\n",
3342 debugstr_w(lpxkey->keyname));
3343 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3344 break;
3345 lplpPrevKey = &(lpxkey->next);
3346 lpxkey = lpxkey->next;
3349 if (!lpxkey) {
3350 FREE_KEY_PATH;
3351 WARN(reg , " Not found.\n");
3352 return ERROR_FILE_NOT_FOUND;
3355 if (lpxkey->nextsub) {
3356 FREE_KEY_PATH;
3357 WARN(reg , " Not empty.\n");
3358 return ERROR_CANTWRITE;
3360 *lplpPrevKey = lpxkey->next;
3361 free(lpxkey->keyname);
3362 if (lpxkey->class)
3363 free(lpxkey->class);
3364 if (lpxkey->values)
3365 free(lpxkey->values);
3366 free(lpxkey);
3367 FREE_KEY_PATH;
3368 TRACE(reg, " Done.\n");
3369 return ERROR_SUCCESS;
3373 /******************************************************************************
3374 * RegDeleteKey32A [ADVAPI32.133]
3376 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3378 LPWSTR lpszSubKeyW;
3379 DWORD ret;
3381 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3382 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3383 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3384 if(lpszSubKeyW) free(lpszSubKeyW);
3385 return ret;
3389 /******************************************************************************
3390 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3392 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3394 TRACE(reg,"(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3395 return RegDeleteKeyA( hkey, lpszSubKey );
3400 * Delete registry value
3402 * Callpath:
3403 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3407 /******************************************************************************
3408 * RegDeleteValue32W [ADVAPI32.136]
3410 * PARAMS
3411 * hkey [I]
3412 * lpszValue [I]
3414 * RETURNS
3416 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPWSTR lpszValue )
3418 DWORD i;
3419 LPKEYSTRUCT lpkey;
3420 LPKEYVALUE val;
3422 TRACE(reg,"(%x,%s)\n",hkey,debugstr_w(lpszValue));
3424 lpkey = lookup_hkey( hkey );
3425 if (!lpkey)
3426 return ERROR_INVALID_HANDLE;
3428 if (lpszValue) {
3429 for (i=0;i<lpkey->nrofvalues;i++)
3430 if ( lpkey->values[i].name &&
3431 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3433 break;
3434 } else {
3435 for (i=0;i<lpkey->nrofvalues;i++)
3436 if (lpkey->values[i].name==NULL)
3437 break;
3440 if (i == lpkey->nrofvalues)
3441 return ERROR_FILE_NOT_FOUND;
3443 val = lpkey->values+i;
3444 if (val->name) free(val->name);
3445 if (val->data) free(val->data);
3446 memcpy(
3447 lpkey->values+i,
3448 lpkey->values+i+1,
3449 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3451 lpkey->values = (LPKEYVALUE)xrealloc(
3452 lpkey->values,
3453 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3455 lpkey->nrofvalues--;
3456 return ERROR_SUCCESS;
3460 /******************************************************************************
3461 * RegDeleteValue32A [ADVAPI32.135]
3463 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPSTR lpszValue )
3465 LPWSTR lpszValueW;
3466 DWORD ret;
3468 TRACE(reg, "(%x,%s)\n",hkey,debugstr_a(lpszValue));
3469 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3470 ret = RegDeleteValueW( hkey, lpszValueW );
3471 if(lpszValueW) free(lpszValueW);
3472 return ret;
3476 /******************************************************************************
3477 * RegDeleteValue16 [KERNEL.222]
3479 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3481 TRACE(reg,"(%x,%s)\n", hkey,debugstr_a(lpszValue));
3482 return RegDeleteValueA( hkey, lpszValue );
3486 /******************************************************************************
3487 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3488 * Writes key to registry
3490 * PARAMS
3491 * hkey [I] Handle of key to write
3493 * RETURNS
3494 * Success: ERROR_SUCCESS
3495 * Failure: Error code
3497 DWORD WINAPI RegFlushKey( HKEY hkey )
3499 LPKEYSTRUCT lpkey;
3500 BOOL ret;
3502 TRACE(reg, "(%x)\n", hkey);
3504 lpkey = lookup_hkey( hkey );
3505 if (!lpkey)
3506 return ERROR_BADKEY;
3508 ERR(reg, "What is the correct filename?\n");
3510 ret = _savereg( lpkey, "foo.bar", TRUE);
3512 if( ret ) {
3513 return ERROR_SUCCESS;
3514 } else
3515 return ERROR_UNKNOWN; /* FIXME */
3519 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3522 /******************************************************************************
3523 * RegQueryInfoKey32W [ADVAPI32.153]
3525 * PARAMS
3526 * hkey [I] Handle to key to query
3527 * lpszClass [O] Buffer for class string
3528 * lpcchClass [O] Size of class string buffer
3529 * lpdwReserved [I] Reserved
3530 * lpcSubKeys [I] Buffer for number of subkeys
3531 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3532 * lpcchMaxClass [O] Buffer for longest class string length
3533 * lpcValues [O] Buffer for number of value entries
3534 * lpcchMaxValueName [O] Buffer for longest value name length
3535 * lpccbMaxValueData [O] Buffer for longest value data length
3536 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3537 * ft
3538 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3539 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3540 * lpcchClass is NULL
3541 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3542 * (it's hard to test validity, so test !NULL instead)
3544 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3545 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3546 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3547 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3548 LPDWORD lpcchMaxValueName,
3549 LPDWORD lpccbMaxValueData,
3550 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3552 LPKEYSTRUCT lpkey,lpxkey;
3553 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3554 int i;
3556 TRACE(reg,"(%x,%p,...)\n",hkey,lpszClass);
3557 lpkey = lookup_hkey(hkey);
3558 if (!lpkey)
3559 return ERROR_INVALID_HANDLE;
3560 if (lpszClass) {
3561 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3562 return ERROR_INVALID_PARAMETER;
3564 /* either lpcchClass is valid or this is win95 and lpcchClass
3565 could be invalid */
3566 if (lpkey->class) {
3567 DWORD classLen = lstrlenW(lpkey->class);
3569 if (lpcchClass && classLen+1>*lpcchClass) {
3570 *lpcchClass=classLen+1;
3571 return ERROR_MORE_DATA;
3573 if (lpcchClass)
3574 *lpcchClass=classLen;
3575 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3576 } else {
3577 *lpszClass = 0;
3578 if (lpcchClass)
3579 *lpcchClass = 0;
3581 } else {
3582 if (lpcchClass)
3583 *lpcchClass = lstrlenW(lpkey->class);
3585 lpxkey=lpkey->nextsub;
3586 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3587 while (lpxkey) {
3588 nrofkeys++;
3589 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3590 maxsubkey=lstrlenW(lpxkey->keyname);
3591 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3592 maxclass=lstrlenW(lpxkey->class);
3593 lpxkey=lpxkey->next;
3595 for (i=0;i<lpkey->nrofvalues;i++) {
3596 LPKEYVALUE val=lpkey->values+i;
3598 if (val->name && lstrlenW(val->name)>maxvname)
3599 maxvname=lstrlenW(val->name);
3600 if (val->len>maxvdata)
3601 maxvdata=val->len;
3603 if (!maxclass) maxclass = 1;
3604 if (!maxvname) maxvname = 1;
3605 if (lpcValues)
3606 *lpcValues = lpkey->nrofvalues;
3607 if (lpcSubKeys)
3608 *lpcSubKeys = nrofkeys;
3609 if (lpcchMaxSubkey)
3610 *lpcchMaxSubkey = maxsubkey;
3611 if (lpcchMaxClass)
3612 *lpcchMaxClass = maxclass;
3613 if (lpcchMaxValueName)
3614 *lpcchMaxValueName= maxvname;
3615 if (lpccbMaxValueData)
3616 *lpccbMaxValueData= maxvdata;
3617 return ERROR_SUCCESS;
3621 /******************************************************************************
3622 * RegQueryInfoKey32A [ADVAPI32.152]
3624 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3625 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3626 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3627 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3628 LPDWORD lpccbMaxValueData,
3629 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3631 LPWSTR lpszClassW = NULL;
3632 DWORD ret;
3634 TRACE(reg,"(%x,%p,%p......)\n",hkey, lpszClass, lpcchClass);
3635 if (lpszClass) {
3636 if (lpcchClass) {
3637 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3638 } else if (VERSION_GetVersion() == WIN95) {
3639 /* win95 allows lpcchClass to be null */
3640 /* we don't know how big lpszClass is, would
3641 MAX_PATHNAME_LEN be the correct default? */
3642 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3645 } else
3646 lpszClassW = NULL;
3647 ret=RegQueryInfoKeyW(
3648 hkey,
3649 lpszClassW,
3650 lpcchClass,
3651 lpdwReserved,
3652 lpcSubKeys,
3653 lpcchMaxSubkey,
3654 lpcchMaxClass,
3655 lpcValues,
3656 lpcchMaxValueName,
3657 lpccbMaxValueData,
3658 lpcbSecurityDescriptor,
3661 if (ret==ERROR_SUCCESS && lpszClass)
3662 lstrcpyWtoA(lpszClass,lpszClassW);
3663 if (lpszClassW)
3664 free(lpszClassW);
3665 return ret;
3669 /******************************************************************************
3670 * RegConnectRegistry32W [ADVAPI32.128]
3672 * PARAMS
3673 * lpMachineName [I] Address of name of remote computer
3674 * hHey [I] Predefined registry handle
3675 * phkResult [I] Address of buffer for remote registry handle
3677 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3678 LPHKEY phkResult )
3680 TRACE(reg,"(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3682 if (!lpMachineName || !*lpMachineName) {
3683 /* Use the local machine name */
3684 return RegOpenKey16( hKey, "", phkResult );
3687 FIXME(reg,"Cannot connect to %s\n",debugstr_w(lpMachineName));
3688 return ERROR_BAD_NETPATH;
3692 /******************************************************************************
3693 * RegConnectRegistry32A [ADVAPI32.127]
3695 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3697 DWORD ret;
3698 LPWSTR machineW = strdupA2W(machine);
3699 ret = RegConnectRegistryW( machineW, hkey, reskey );
3700 free(machineW);
3701 return ret;
3705 /******************************************************************************
3706 * RegGetKeySecurity [ADVAPI32.144]
3707 * Retrieves a copy of security descriptor protecting the registry key
3709 * PARAMS
3710 * hkey [I] Open handle of key to set
3711 * SecurityInformation [I] Descriptor contents
3712 * pSecurityDescriptor [O] Address of descriptor for key
3713 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3715 * RETURNS
3716 * Success: ERROR_SUCCESS
3717 * Failure: Error code
3719 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3720 SECURITY_INFORMATION SecurityInformation,
3721 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3722 LPDWORD lpcbSecurityDescriptor )
3724 LPKEYSTRUCT lpkey;
3726 TRACE(reg,"(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3727 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3729 lpkey = lookup_hkey( hkey );
3730 if (!lpkey)
3731 return ERROR_INVALID_HANDLE;
3733 /* FIXME: Check for valid SecurityInformation values */
3735 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3736 return ERROR_INSUFFICIENT_BUFFER;
3738 FIXME(reg, "(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3739 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3741 return ERROR_SUCCESS;
3745 /******************************************************************************
3746 * RegLoadKey32W [ADVAPI32.???]
3748 * PARAMS
3749 * hkey [I] Handle of open key
3750 * lpszSubKey [I] Address of name of subkey
3751 * lpszFile [I] Address of filename for registry information
3753 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3755 LPKEYSTRUCT lpkey;
3756 TRACE(reg,"(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3758 /* Do this check before the hkey check */
3759 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3760 return ERROR_INVALID_PARAMETER;
3762 lpkey = lookup_hkey( hkey );
3763 if (!lpkey)
3764 return ERROR_INVALID_HANDLE;
3766 FIXME(reg,"(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3767 debugstr_w(lpszFile));
3769 return ERROR_SUCCESS;
3773 /******************************************************************************
3774 * RegLoadKey32A [ADVAPI32.???]
3776 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3778 LONG ret;
3779 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3780 LPWSTR lpszFileW = strdupA2W(lpszFile);
3781 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3782 if(lpszFileW) free(lpszFileW);
3783 if(lpszSubKeyW) free(lpszSubKeyW);
3784 return ret;
3788 /******************************************************************************
3789 * RegNotifyChangeKeyValue [ADVAPI32.???]
3791 * PARAMS
3792 * hkey [I] Handle of key to watch
3793 * fWatchSubTree [I] Flag for subkey notification
3794 * fdwNotifyFilter [I] Changes to be reported
3795 * hEvent [I] Handle of signaled event
3796 * fAsync [I] Flag for asynchronous reporting
3798 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3799 DWORD fdwNotifyFilter, HANDLE hEvent,
3800 BOOL fAsync )
3802 LPKEYSTRUCT lpkey;
3803 TRACE(reg,"(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3804 hEvent,fAsync);
3806 lpkey = lookup_hkey( hkey );
3807 if (!lpkey)
3808 return ERROR_INVALID_HANDLE;
3810 FIXME(reg,"(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3811 hEvent,fAsync);
3813 return ERROR_SUCCESS;
3817 /******************************************************************************
3818 * RegUnLoadKey32W [ADVAPI32.173]
3820 * PARAMS
3821 * hkey [I] Handle of open key
3822 * lpSubKey [I] Address of name of subkey to unload
3824 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3826 FIXME(reg,"(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3827 return ERROR_SUCCESS;
3831 /******************************************************************************
3832 * RegUnLoadKey32A [ADVAPI32.172]
3834 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3836 LONG ret;
3837 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3838 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3839 if(lpSubKeyW) free(lpSubKeyW);
3840 return ret;
3844 /******************************************************************************
3845 * RegSetKeySecurity [ADVAPI32.167]
3847 * PARAMS
3848 * hkey [I] Open handle of key to set
3849 * SecurityInfo [I] Descriptor contents
3850 * pSecurityDesc [I] Address of descriptor for key
3852 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3853 PSECURITY_DESCRIPTOR pSecurityDesc )
3855 LPKEYSTRUCT lpkey;
3857 TRACE(reg,"(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3859 /* It seems to perform this check before the hkey check */
3860 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3861 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3862 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3863 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3864 /* Param OK */
3865 } else
3866 return ERROR_INVALID_PARAMETER;
3868 if (!pSecurityDesc)
3869 return ERROR_INVALID_PARAMETER;
3871 lpkey = lookup_hkey( hkey );
3872 if (!lpkey)
3873 return ERROR_INVALID_HANDLE;
3875 FIXME(reg,":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3877 return ERROR_SUCCESS;
3881 /******************************************************************************
3882 * RegSaveKey32W [ADVAPI32.166]
3884 * PARAMS
3885 * hkey [I] Handle of key where save begins
3886 * lpFile [I] Address of filename to save to
3887 * sa [I] Address of security structure
3889 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3890 LPSECURITY_ATTRIBUTES sa )
3892 LPKEYSTRUCT lpkey;
3894 TRACE(reg, "(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3896 /* It appears to do this check before the hkey check */
3897 if (!lpFile || !*lpFile)
3898 return ERROR_INVALID_PARAMETER;
3900 lpkey = lookup_hkey( hkey );
3901 if (!lpkey)
3902 return ERROR_INVALID_HANDLE;
3904 FIXME(reg, "(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3906 return ERROR_SUCCESS;
3910 /******************************************************************************
3911 * RegSaveKey32A [ADVAPI32.165]
3913 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3914 LPSECURITY_ATTRIBUTES sa )
3916 LONG ret;
3917 LPWSTR lpFileW = strdupA2W(lpFile);
3918 ret = RegSaveKeyW( hkey, lpFileW, sa );
3919 free(lpFileW);
3920 return ret;
3924 /******************************************************************************
3925 * RegRestoreKey32W [ADVAPI32.164]
3927 * PARAMS
3928 * hkey [I] Handle of key where restore begins
3929 * lpFile [I] Address of filename containing saved tree
3930 * dwFlags [I] Optional flags
3932 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3934 LPKEYSTRUCT lpkey;
3936 TRACE(reg, "(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3938 /* It seems to do this check before the hkey check */
3939 if (!lpFile || !*lpFile)
3940 return ERROR_INVALID_PARAMETER;
3942 lpkey = lookup_hkey( hkey );
3943 if (!lpkey)
3944 return ERROR_INVALID_HANDLE;
3946 FIXME(reg,"(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3948 /* Check for file existence */
3950 return ERROR_SUCCESS;
3954 /******************************************************************************
3955 * RegRestoreKey32A [ADVAPI32.163]
3957 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3959 LONG ret;
3960 LPWSTR lpFileW = strdupA2W(lpFile);
3961 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3962 if(lpFileW) free(lpFileW);
3963 return ret;
3967 /******************************************************************************
3968 * RegReplaceKey32W [ADVAPI32.162]
3970 * PARAMS
3971 * hkey [I] Handle of open key
3972 * lpSubKey [I] Address of name of subkey
3973 * lpNewFile [I] Address of filename for file with new data
3974 * lpOldFile [I] Address of filename for backup file
3976 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3977 LPCWSTR lpOldFile )
3979 LPKEYSTRUCT lpkey;
3981 TRACE(reg,"(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3982 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3984 lpkey = lookup_hkey( hkey );
3985 if (!lpkey)
3986 return ERROR_INVALID_HANDLE;
3988 FIXME(reg, "(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3989 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3991 return ERROR_SUCCESS;
3995 /******************************************************************************
3996 * RegReplaceKey32A [ADVAPI32.161]
3998 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3999 LPCSTR lpOldFile )
4001 LONG ret;
4002 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
4003 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
4004 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
4005 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
4006 free(lpOldFileW);
4007 free(lpNewFileW);
4008 free(lpSubKeyW);
4009 return ret;