Added support for 32-bit NE code segments.
[wine/testsucceed.git] / misc / registry.c
blobb58d15758882197505b2d95603acd345a98b4c81
1 /*
2 * Registry Functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 1998 Matthew Becker
6 * Copyright 1999 Sylvain St-Germain
8 * December 21, 1997 - Kevin Cozens
9 * Fixed bugs in the _w95_loadreg() function. Added extra information
10 * regarding the format of the Windows '95 registry files.
12 * NOTES
13 * When changing this file, please re-run the regtest program to ensure
14 * the conditions are handled properly.
16 * TODO
17 * Security access
18 * Option handling
19 * Time for RegEnumKey*, RegQueryInfoKey*
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_ERRNO_H
28 #include <sys/errno.h>
29 #endif
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
32 #include <sys/stat.h>
33 #include <assert.h>
34 #include <time.h>
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/winbase16.h"
38 #include "wine/winestring.h"
39 #include "winerror.h"
40 #include "file.h"
41 #include "heap.h"
42 #include "debugtools.h"
43 #include "xmalloc.h"
44 #include "options.h"
45 #include "winreg.h"
46 #include "winversion.h"
48 DECLARE_DEBUG_CHANNEL(reg)
49 DECLARE_DEBUG_CHANNEL(string)
51 static void REGISTRY_Init(void);
52 /* FIXME: following defines should be configured global ... */
54 /* NOTE: do not append a /. linux' mkdir() WILL FAIL if you do that */
55 #define WINE_PREFIX "/.wine"
56 #define SAVE_USERS_DEFAULT ETCDIR"/wine.userreg"
57 #define SAVE_LOCAL_MACHINE_DEFAULT ETCDIR"/wine.systemreg"
59 /* relative in ~user/.wine/ : */
60 #define SAVE_CURRENT_USER "user.reg"
61 #define SAVE_LOCAL_USERS_DEFAULT "wine.userreg"
62 #define SAVE_LOCAL_MACHINE "system.reg"
64 #define KEY_REGISTRY "Software\\The WINE team\\WINE\\Registry"
65 #define VAL_SAVEUPDATED "SaveOnlyUpdatedKeys"
67 /* one value of a key */
68 typedef struct tagKEYVALUE
70 LPWSTR name; /* name of value (UNICODE) or NULL for win31 */
71 DWORD type; /* type of value */
72 DWORD len; /* length of data in BYTEs */
73 DWORD lastmodified; /* time of seconds since 1.1.1970 */
74 LPBYTE data; /* content, may be strings, binaries, etc. */
75 } KEYVALUE,*LPKEYVALUE;
77 /* a registry key */
78 typedef struct tagKEYSTRUCT
80 LPWSTR keyname; /* name of THIS key (UNICODE) */
81 DWORD flags; /* flags. */
82 LPWSTR class;
83 /* values */
84 DWORD nrofvalues; /* nr of values in THIS key */
85 LPKEYVALUE values; /* values in THIS key */
86 /* key management pointers */
87 struct tagKEYSTRUCT *next; /* next key on same hierarchy */
88 struct tagKEYSTRUCT *nextsub; /* keys that hang below THIS key */
89 } KEYSTRUCT, *LPKEYSTRUCT;
92 static KEYSTRUCT *key_classes_root=NULL; /* windows 3.1 global values */
93 static KEYSTRUCT *key_current_user=NULL; /* user specific values */
94 static KEYSTRUCT *key_local_machine=NULL;/* machine specific values */
95 static KEYSTRUCT *key_users=NULL; /* all users? */
97 /* dynamic, not saved */
98 static KEYSTRUCT *key_performance_data=NULL;
99 static KEYSTRUCT *key_current_config=NULL;
100 static KEYSTRUCT *key_dyn_data=NULL;
102 /* what valuetypes do we need to convert? */
103 #define UNICONVMASK ((1<<REG_SZ)|(1<<REG_MULTI_SZ)|(1<<REG_EXPAND_SZ))
106 static struct openhandle {
107 LPKEYSTRUCT lpkey;
108 HKEY hkey;
109 REGSAM accessmask;
110 } *openhandles=NULL;
111 static int nrofopenhandles=0;
112 /* Starts after 1 because 0,1 are reserved for Win16 */
113 /* Note: Should always be even, as Win95 ADVAPI32.DLL reserves odd
114 HKEYs for remote registry access */
115 static int currenthandle=2;
119 * QUESTION
120 * Are these doing the same as HEAP_strdupAtoW and HEAP_strdupWtoA?
121 * If so, can we remove them?
122 * ANSWER
123 * No, the memory handling functions are called very often in here,
124 * just replacing them by HeapAlloc(SystemHeap,...) makes registry
125 * loading 100 times slower. -MM
127 static LPWSTR strdupA2W(LPCSTR src)
129 if(src) {
130 LPWSTR dest=xmalloc(2*strlen(src)+2);
131 lstrcpyAtoW(dest,src);
132 return dest;
134 return NULL;
137 static LPWSTR strdupW(LPCWSTR a) {
138 LPWSTR b;
139 int len;
141 if(a) {
142 len=sizeof(WCHAR)*(lstrlenW(a)+1);
143 b=(LPWSTR)xmalloc(len);
144 memcpy(b,a,len);
145 return b;
147 return NULL;
150 LPWSTR strcvtA2W(LPCSTR src, int nchars)
153 LPWSTR dest = xmalloc (2 * nchars + 2);
155 lstrcpynAtoW(dest,src,nchars+1);
156 dest[nchars] = 0;
157 return dest;
160 * we need to convert A to W with '\0' in strings (MULTI_SZ)
163 static LPWSTR lmemcpynAtoW( LPWSTR dst, LPCSTR src, INT n )
164 { LPWSTR p = dst;
166 TRACE_(reg)("\"%s\" %i\n",src, n);
168 while (n-- > 0) *p++ = (WCHAR)(unsigned char)*src++;
170 return dst;
172 static LPSTR lmemcpynWtoA( LPSTR dst, LPCWSTR src, INT n )
173 { LPSTR p = dst;
175 TRACE_(string)("L\"%s\" %i\n",debugstr_w(src), n);
177 while (n-- > 0) *p++ = (CHAR)*src++;
179 return dst;
182 static void debug_print_value (LPBYTE lpbData, LPKEYVALUE key)
184 if (TRACE_ON(reg) && lpbData)
186 switch(key->type)
188 case REG_EXPAND_SZ:
189 case REG_SZ:
190 TRACE_(reg)(" Value %s, Data(sz)=%s\n",
191 debugstr_w(key->name),
192 debugstr_w((LPCWSTR)lpbData));
193 break;
195 case REG_DWORD:
196 TRACE_(reg)(" Value %s, Data(dword)=0x%08lx\n",
197 debugstr_w(key->name),
198 (DWORD)*lpbData);
199 break;
201 case REG_MULTI_SZ:
203 int i;
204 LPCWSTR ptr = (LPCWSTR)lpbData;
205 for (i=0;ptr[0];i++)
207 TRACE_(reg)(" Value %s, MULTI_SZ(%i=%s)\n",
208 debugstr_w(key->name),
210 debugstr_w(ptr));
212 ptr += lstrlenW(ptr)+1;
215 break;
217 default:
219 char szTemp[100]; /* 3*32 + 3 + 1 */
220 int i;
221 for ( i = 0; i < key->len ; i++)
223 sprintf (&(szTemp[i*3]),"%02x ", lpbData[i]);
224 if (i>=31)
226 sprintf (&(szTemp[i*3+3]),"...");
227 break;
230 TRACE_(reg)(" Value %s, Data(raw)=(%s)\n",
231 debugstr_w(key->name),
232 szTemp);
234 } /* switch */
235 } /* if */
239 /******************************************************************************
240 * is_standard_hkey [Internal]
241 * Determines if a hkey is a standard key
243 static BOOL is_standard_hkey( HKEY hkey )
245 switch(hkey) {
246 case 0x00000000:
247 case 0x00000001:
248 case HKEY_CLASSES_ROOT:
249 case HKEY_CURRENT_CONFIG:
250 case HKEY_CURRENT_USER:
251 case HKEY_LOCAL_MACHINE:
252 case HKEY_USERS:
253 case HKEY_PERFORMANCE_DATA:
254 case HKEY_DYN_DATA:
255 return TRUE;
256 default:
257 return FALSE;
261 /******************************************************************************
262 * add_handle [Internal]
264 static void add_handle( HKEY hkey, LPKEYSTRUCT lpkey, REGSAM accessmask )
266 int i;
268 TRACE_(reg)("(0x%x,%p,0x%lx)\n",hkey,lpkey,accessmask);
269 /* Check for duplicates */
270 for (i=0;i<nrofopenhandles;i++) {
271 if (openhandles[i].lpkey==lpkey) {
272 /* This is not really an error - the user is allowed to create
273 two (or more) handles to the same key */
274 /*WARN(reg, "Adding key %p twice\n",lpkey);*/
276 if (openhandles[i].hkey==hkey) {
277 WARN_(reg)("Adding handle %x twice\n",hkey);
280 openhandles=xrealloc( openhandles,
281 sizeof(struct openhandle)*(nrofopenhandles+1));
283 openhandles[i].lpkey = lpkey;
284 openhandles[i].hkey = hkey;
285 openhandles[i].accessmask = accessmask;
286 nrofopenhandles++;
290 /******************************************************************************
291 * get_handle [Internal]
293 * RETURNS
294 * Success: Pointer to key
295 * Failure: NULL
297 static LPKEYSTRUCT get_handle( HKEY hkey )
299 int i;
301 for (i=0; i<nrofopenhandles; i++)
302 if (openhandles[i].hkey == hkey)
303 return openhandles[i].lpkey;
304 WARN_(reg)("Could not find handle 0x%x\n",hkey);
305 return NULL;
309 /******************************************************************************
310 * remove_handle [Internal]
312 * PARAMS
313 * hkey [I] Handle of key to remove
315 * RETURNS
316 * Success: ERROR_SUCCESS
317 * Failure: ERROR_INVALID_HANDLE
319 static DWORD remove_handle( HKEY hkey )
321 int i;
323 for (i=0;i<nrofopenhandles;i++)
324 if (openhandles[i].hkey==hkey)
325 break;
327 if (i == nrofopenhandles) {
328 WARN_(reg)("Could not find handle 0x%x\n",hkey);
329 return ERROR_INVALID_HANDLE;
332 memcpy( openhandles+i,
333 openhandles+i+1,
334 sizeof(struct openhandle)*(nrofopenhandles-i-1)
336 openhandles=xrealloc(openhandles,sizeof(struct openhandle)*(nrofopenhandles-1));
337 nrofopenhandles--;
338 return ERROR_SUCCESS;
341 /******************************************************************************
342 * lookup_hkey [Internal]
344 * Just as the name says. Creates the root keys on demand, so we can call the
345 * Reg* functions at any time.
347 * RETURNS
348 * Success: Pointer to key structure
349 * Failure: NULL
351 #define ADD_ROOT_KEY(xx) \
352 xx = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));\
353 memset(xx,'\0',sizeof(KEYSTRUCT));\
354 xx->keyname= strdupA2W("<should_not_appear_anywhere>");
356 static LPKEYSTRUCT lookup_hkey( HKEY hkey )
358 switch (hkey) {
359 /* 0 and 1 are valid rootkeys in win16 shell.dll and are used by
360 * some programs. Do not remove those cases. -MM
362 case 0x00000000:
363 case 0x00000001:
364 case HKEY_CLASSES_ROOT:
366 if (!key_classes_root)
368 HKEY cl_r_hkey;
370 /* calls lookup_hkey recursively, TWICE */
371 if ( RegCreateKey16(
372 HKEY_LOCAL_MACHINE,
373 "SOFTWARE\\Classes",
374 &cl_r_hkey) != ERROR_SUCCESS)
376 ERR_(reg)("Could not create HKLM\\SOFTWARE\\Classes. This is impossible.\n");
377 exit(1);
380 key_classes_root = lookup_hkey(cl_r_hkey);
382 return key_classes_root;
385 case HKEY_CURRENT_USER:
386 if (!key_current_user) {
387 ADD_ROOT_KEY(key_current_user);
389 return key_current_user;
391 case HKEY_LOCAL_MACHINE:
392 if (!key_local_machine) {
393 ADD_ROOT_KEY(key_local_machine);
394 REGISTRY_Init();
396 return key_local_machine;
398 case HKEY_USERS:
399 if (!key_users) {
400 ADD_ROOT_KEY(key_users);
402 return key_users;
404 case HKEY_PERFORMANCE_DATA:
405 if (!key_performance_data) {
406 ADD_ROOT_KEY(key_performance_data);
408 return key_performance_data;
410 case HKEY_DYN_DATA:
411 if (!key_dyn_data) {
412 ADD_ROOT_KEY(key_dyn_data);
414 return key_dyn_data;
416 case HKEY_CURRENT_CONFIG:
417 if (!key_current_config) {
418 ADD_ROOT_KEY(key_current_config);
420 return key_current_config;
422 default:
423 return get_handle(hkey);
426 /*NOTREACHED*/
428 #undef ADD_ROOT_KEY
429 /* so we don't accidently access them ... */
430 #define key_current_config NULL NULL
431 #define key_current_user NULL NULL
432 #define key_users NULL NULL
433 #define key_local_machine NULL NULL
434 #define key_classes_root NULL NULL
435 #define key_dyn_data NULL NULL
436 #define key_performance_data NULL NULL
438 /******************************************************************************
439 * split_keypath [Internal]
440 * splits the unicode string 'wp' into an array of strings.
441 * the array is allocated by this function.
442 * Free the array using FREE_KEY_PATH
444 * PARAMS
445 * wp [I] String to split up
446 * wpv [O] Array of pointers to strings
447 * wpc [O] Number of components
449 static void split_keypath( LPCWSTR wp, LPWSTR **wpv, int *wpc)
451 int i,j,len;
452 LPWSTR ws;
454 TRACE_(reg)("(%s,%p,%p)\n",debugstr_w(wp),wpv,wpc);
456 ws = HEAP_strdupW( SystemHeap, 0, wp );
458 /* We know we have at least one substring */
459 *wpc = 1;
461 /* Replace each backslash with NULL, and increment the count */
462 for (i=0;ws[i];i++) {
463 if (ws[i]=='\\') {
464 ws[i]=0;
465 (*wpc)++;
469 len = i;
471 /* Allocate the space for the array of pointers, leaving room for the
472 NULL at the end */
473 *wpv = (LPWSTR*)HeapAlloc( SystemHeap, 0, sizeof(LPWSTR)*(*wpc+2));
474 (*wpv)[0]= ws;
476 /* Assign each pointer to the appropriate character in the string */
477 j = 1;
478 for (i=1;i<len;i++)
479 if (ws[i-1]==0) {
480 (*wpv)[j++]=ws+i;
481 /* TRACE(reg, " Subitem %d = %s\n",j-1,debugstr_w((*wpv)[j-1])); */
484 (*wpv)[j]=NULL;
486 #define FREE_KEY_PATH HeapFree(SystemHeap,0,wps[0]);HeapFree(SystemHeap,0,wps);
491 /******************************************************************************
492 * REGISTRY_Init [Internal]
493 * Registry initialisation, allocates some default keys.
495 static void REGISTRY_Init(void) {
496 HKEY hkey;
497 char buf[200];
499 TRACE_(reg)("(void)\n");
501 RegCreateKey16(HKEY_DYN_DATA,"PerfStats\\StatData",&hkey);
502 RegCloseKey(hkey);
504 /* This was an Open, but since it is called before the real registries
505 are loaded, it was changed to a Create - MTB 980507*/
506 RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System",&hkey);
507 RegSetValueExA(hkey,"Identifier",0,REG_SZ,"SystemType WINE",strlen("SystemType WINE"));
508 RegCloseKey(hkey);
510 /* \\SOFTWARE\\Microsoft\\Window NT\\CurrentVersion
511 * CurrentVersion
512 * CurrentBuildNumber
513 * CurrentType
514 * string RegisteredOwner
515 * string RegisteredOrganization
518 /* System\\CurrentControlSet\\Services\\SNMP\\Parameters\\RFC1156Agent
519 * string SysContact
520 * string SysLocation
521 * SysServices
523 if (-1!=gethostname(buf,200)) {
524 RegCreateKey16(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",&hkey);
525 RegSetValueEx16(hkey,"ComputerName",0,REG_SZ,buf,strlen(buf)+1);
526 RegCloseKey(hkey);
531 /************************ SAVE Registry Function ****************************/
533 #define REGISTRY_SAVE_VERSION 0x00000001
535 /* Registry saveformat:
536 * If you change it, increase above number by 1, which will flush
537 * old registry database files.
539 * Global:
540 * "WINE REGISTRY Version %d"
541 * subkeys....
542 * Subkeys:
543 * keyname
544 * valuename=lastmodified,type,data
545 * ...
546 * subkeys
547 * ...
548 * keyname,valuename,stringdata:
549 * the usual ascii characters from 0x00-0xff (well, not 0x00)
550 * and \uXXXX as UNICODE value XXXX with XXXX>0xff
551 * ( "=\\\t" escaped in \uXXXX form.)
552 * type,lastmodified:
553 * int
555 * FIXME: doesn't save 'class' (what does it mean anyway?), nor flags.
557 * [HKEY_CURRENT_USER\\Software\\The WINE team\\WINE\\Registry]
558 * SaveOnlyUpdatedKeys=yes
561 /******************************************************************************
562 * _save_check_tainted [Internal]
564 static int _save_check_tainted( LPKEYSTRUCT lpkey )
566 int tainted;
568 if (!lpkey)
569 return 0;
570 if (lpkey->flags & REG_OPTION_TAINTED)
571 tainted = 1;
572 else
573 tainted = 0;
574 while (lpkey) {
575 if (_save_check_tainted(lpkey->nextsub)) {
576 lpkey->flags |= REG_OPTION_TAINTED;
577 tainted = 1;
579 lpkey = lpkey->next;
581 return tainted;
584 /******************************************************************************
585 * _save_USTRING [Internal]
587 static void _save_USTRING( FILE *F, LPWSTR wstr, int escapeeq )
589 LPWSTR s;
590 int doescape;
592 if (wstr==NULL)
593 return;
594 s=wstr;
595 while (*s) {
596 doescape=0;
597 if (*s>0xff)
598 doescape = 1;
599 if (*s=='\n')
600 doescape = 1;
601 if (escapeeq && *s=='=')
602 doescape = 1;
603 if (*s=='\\')
604 fputc(*s,F); /* if \\ then put it twice. */
605 if (doescape)
606 fprintf(F,"\\u%04x",*((unsigned short*)s));
607 else
608 fputc(*s,F);
609 s++;
613 /******************************************************************************
614 * _savesubkey [Internal]
616 * NOTES
617 * REG_MULTI_SZ is handled as binary (like in win95) (js)
619 static int _savesubkey( FILE *F, LPKEYSTRUCT lpkey, int level, int all )
621 LPKEYSTRUCT lpxkey;
622 int i,tabs,j;
624 lpxkey = lpkey;
625 while (lpxkey) {
626 if ( !(lpxkey->flags & REG_OPTION_VOLATILE) &&
627 (all || (lpxkey->flags & REG_OPTION_TAINTED))
629 for (tabs=level;tabs--;)
630 fputc('\t',F);
631 _save_USTRING(F,lpxkey->keyname,1);
632 fputs("\n",F);
633 for (i=0;i<lpxkey->nrofvalues;i++) {
634 LPKEYVALUE val=lpxkey->values+i;
636 for (tabs=level+1;tabs--;)
637 fputc('\t',F);
638 _save_USTRING(F,val->name,0);
639 fputc('=',F);
640 fprintf(F,"%ld,%ld,",val->type,val->lastmodified);
641 if ( val->type == REG_SZ || val->type == REG_EXPAND_SZ )
642 _save_USTRING(F,(LPWSTR)val->data,0);
643 else
644 for (j=0;j<val->len;j++)
645 fprintf(F,"%02x",*((unsigned char*)val->data+j));
646 fputs("\n",F);
648 /* descend recursively */
649 if (!_savesubkey(F,lpxkey->nextsub,level+1,all))
650 return 0;
652 lpxkey=lpxkey->next;
654 return 1;
658 /******************************************************************************
659 * _savesubreg [Internal]
661 static int _savesubreg( FILE *F, LPKEYSTRUCT lpkey, int all )
663 fprintf(F,"WINE REGISTRY Version %d\n",REGISTRY_SAVE_VERSION);
664 _save_check_tainted(lpkey->nextsub);
665 return _savesubkey(F,lpkey->nextsub,0,all);
669 /******************************************************************************
670 * _savereg [Internal]
672 static BOOL _savereg( LPKEYSTRUCT lpkey, char *fn, int all )
674 FILE *F;
676 F=fopen(fn,"w");
677 if (F==NULL) {
678 WARN_(reg)("Couldn't open %s for writing: %s\n",
679 fn,strerror(errno)
681 return FALSE;
683 if (!_savesubreg(F,lpkey,all)) {
684 fclose(F);
685 unlink(fn);
686 WARN_(reg)("Failed to save keys, perhaps no more diskspace for %s?\n",fn);
687 return FALSE;
689 fclose(F);
690 return TRUE;
694 /******************************************************************************
695 * SHELL_SaveRegistry [Internal]
697 void SHELL_SaveRegistry( void )
699 char *fn, *home, *tmp;
700 char buf[4];
701 HKEY hkey;
702 int all;
703 int usedCfgUser = 0;
704 int usedCfgLM = 0;
706 TRACE_(reg)("(void)\n");
708 all=0;
709 if (RegOpenKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey)!=ERROR_SUCCESS)
711 strcpy(buf,"yes");
713 else
715 DWORD len,junk,type;
717 len=4;
718 if ((ERROR_SUCCESS!=RegQueryValueExA( hkey,
719 VAL_SAVEUPDATED,
720 &junk,
721 &type,
722 buf,
723 &len)) || (type!=REG_SZ))
725 strcpy(buf,"yes");
727 RegCloseKey(hkey);
730 if (lstrcmpiA(buf,"yes")) all=1;
732 if (!(home = getenv( "HOME" )))
734 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
735 return;
738 * Save HKEY_CURRENT_USER
739 * Try first saving according to the defined location in .winerc
741 fn = xmalloc( MAX_PATHNAME_LEN );
742 if (PROFILE_GetWineIniString ( "Registry", "UserFileName", "", fn, MAX_PATHNAME_LEN - 1))
744 _savereg(lookup_hkey(HKEY_CURRENT_USER),fn,all);
745 usedCfgUser = 1;
747 free (fn);
749 if (usedCfgUser != 1)
751 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX) +
752 strlen(SAVE_CURRENT_USER) + 2 );
753 strcpy(fn,home);
754 strcat(fn,WINE_PREFIX);
756 /* create the directory. don't care about errorcodes. */
757 mkdir(fn,0755); /* drwxr-xr-x */
758 strcat(fn,"/"SAVE_CURRENT_USER);
760 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
761 strcpy(tmp,fn);
762 strcat(tmp,".tmp");
764 if (_savereg(lookup_hkey(HKEY_CURRENT_USER),tmp,all)) {
765 if (-1==rename(tmp,fn)) {
766 perror("rename tmp registry");
767 unlink(tmp);
770 free(tmp);
771 free(fn);
775 * Save HKEY_LOCAL_MACHINE
776 * Try first saving according to the defined location in .winerc
778 fn = xmalloc ( MAX_PATHNAME_LEN);
779 if (PROFILE_GetWineIniString ( "Registry", "LocalMachineFileName", "", fn,
780 MAX_PATHNAME_LEN - 1))
782 _savereg(lookup_hkey(HKEY_LOCAL_MACHINE), fn, all);
783 usedCfgLM = 1;
785 free (fn);
787 if ( usedCfgLM != 1)
789 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_MACHINE)+2);
790 strcpy(fn,home);
791 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
793 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
794 strcpy(tmp,fn);
795 strcat(tmp,".tmp");
797 if (_savereg(lookup_hkey(HKEY_LOCAL_MACHINE),tmp,all)) {
798 if (-1==rename(tmp,fn)) {
799 perror("rename tmp registry");
800 unlink(tmp);
803 free(tmp);
804 free(fn);
808 * Save HKEY_USERS
810 fn=(char*)xmalloc( strlen(home)+ strlen(WINE_PREFIX)+ strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
812 strcpy(fn,home);
813 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
815 tmp = (char*)xmalloc(strlen(fn)+strlen(".tmp")+1);
816 strcpy(tmp,fn);strcat(tmp,".tmp");
817 if ( _savereg(lookup_hkey(HKEY_USERS),tmp,FALSE)) {
818 if (-1==rename(tmp,fn)) {
819 perror("rename tmp registry");
820 unlink(tmp);
823 free(tmp);
824 free(fn);
828 /************************ LOAD Registry Function ****************************/
832 /******************************************************************************
833 * _find_or_add_key [Internal]
835 static LPKEYSTRUCT _find_or_add_key( LPKEYSTRUCT lpkey, LPWSTR keyname )
837 LPKEYSTRUCT lpxkey,*lplpkey;
839 if ((!keyname) || (keyname[0]==0)) {
840 free(keyname);
841 return lpkey;
843 lplpkey= &(lpkey->nextsub);
844 lpxkey = *lplpkey;
845 while (lpxkey) {
846 if ( tolower(lpxkey->keyname[0])==tolower(keyname[0]) &&
847 !lstrcmpiW(lpxkey->keyname,keyname)
849 break;
850 lplpkey = &(lpxkey->next);
851 lpxkey = *lplpkey;
853 if (lpxkey==NULL) {
854 *lplpkey = (LPKEYSTRUCT)xmalloc(sizeof(KEYSTRUCT));
855 lpxkey = *lplpkey;
856 memset(lpxkey,'\0',sizeof(KEYSTRUCT));
857 lpxkey->keyname = keyname;
858 } else
859 free(keyname);
860 return lpxkey;
863 /******************************************************************************
864 * _find_or_add_value [Internal]
866 static void _find_or_add_value( LPKEYSTRUCT lpkey, LPWSTR name, DWORD type,
867 LPBYTE data, DWORD len, DWORD lastmodified )
869 LPKEYVALUE val=NULL;
870 int i;
872 if (name && !*name) {/* empty string equals default (NULL) value */
873 free(name);
874 name = NULL;
877 for (i=0;i<lpkey->nrofvalues;i++) {
878 val=lpkey->values+i;
879 if (name==NULL) {
880 if (val->name==NULL)
881 break;
882 } else {
883 if ( val->name!=NULL &&
884 tolower(val->name[0])==tolower(name[0]) &&
885 !lstrcmpiW(val->name,name)
887 break;
890 if (i==lpkey->nrofvalues) {
891 lpkey->values = xrealloc(
892 lpkey->values,
893 (++lpkey->nrofvalues)*sizeof(KEYVALUE)
895 val=lpkey->values+i;
896 memset(val,'\0',sizeof(KEYVALUE));
897 val->name = name;
898 } else {
899 if (name)
900 free(name);
902 if (val->lastmodified<lastmodified) {
903 val->lastmodified=lastmodified;
904 val->type = type;
906 if ((type == REG_SZ || type == REG_EXPAND_SZ) && !data){
908 data=xmalloc(sizeof(WCHAR));
909 memset(data,0,sizeof(WCHAR));
910 len =sizeof(WCHAR);
913 val->len = len;
914 if (val->data)
915 free(val->data);
916 val->data = data;
917 } else
918 free(data);
922 /******************************************************************************
923 * _wine_read_line [Internal]
925 * reads a line including dynamically enlarging the readbuffer and throwing
926 * away comments
928 static int _wine_read_line( FILE *F, char **buf, int *len )
930 char *s,*curread;
931 int mylen,curoff;
933 curread = *buf;
934 mylen = *len;
935 **buf = '\0';
936 while (1) {
937 while (1) {
938 s=fgets(curread,mylen,F);
939 if (s==NULL)
940 return 0; /* EOF */
941 if (NULL==(s=strchr(curread,'\n'))) {
942 /* buffer wasn't large enough */
943 curoff = strlen(*buf);
944 *buf = xrealloc(*buf,*len*2);
945 curread = *buf + curoff;
946 mylen = *len; /* we filled up the buffer and
947 * got new '*len' bytes to fill
949 *len = *len * 2;
950 } else {
951 *s='\0';
952 break;
955 /* throw away comments */
956 if (**buf=='#' || **buf==';') {
957 curread = *buf;
958 mylen = *len;
959 continue;
961 if (s) /* got end of line */
962 break;
964 return 1;
968 /******************************************************************************
969 * _wine_read_USTRING [Internal]
971 * converts a char* into a UNICODE string (up to a special char)
972 * and returns the position exactly after that string
974 static char* _wine_read_USTRING( char *buf, LPWSTR *str )
976 char *s;
977 LPWSTR ws;
979 /* read up to "=" or "\0" or "\n" */
980 s = buf;
981 if (*s == '=') {
982 /* empty string is the win3.1 default value(NULL)*/
983 *str = NULL;
984 return s;
986 *str = (LPWSTR)xmalloc(2*strlen(buf)+2);
987 ws = *str;
988 while (*s && (*s!='\n') && (*s!='=')) {
989 if (*s!='\\')
990 *ws++=*((unsigned char*)s++);
991 else {
992 s++;
993 if (!*s) {
994 /* Dangling \ ... may only happen if a registry
995 * write was short. FIXME: What do to?
997 break;
999 if (*s=='\\') {
1000 *ws++='\\';
1001 s++;
1002 continue;
1004 if (*s!='u') {
1005 WARN_(reg)("Non unicode escape sequence \\%c found in |%s|\n",*s,buf);
1006 *ws++='\\';
1007 *ws++=*s++;
1008 } else {
1009 char xbuf[5];
1010 int wc;
1012 s++;
1013 memcpy(xbuf,s,4);xbuf[4]='\0';
1014 if (!sscanf(xbuf,"%x",&wc))
1015 WARN_(reg)("Strange escape sequence %s found in |%s|\n",xbuf,buf);
1016 s+=4;
1017 *ws++ =(unsigned short)wc;
1021 *ws = 0;
1022 ws = *str;
1023 if (*ws)
1024 *str = strdupW(*str);
1025 else
1026 *str = NULL;
1027 free(ws);
1028 return s;
1032 /******************************************************************************
1033 * _wine_loadsubkey [Internal]
1035 * NOTES
1036 * It seems like this is returning a boolean. Should it?
1038 * RETURNS
1039 * Success: 1
1040 * Failure: 0
1042 static int _wine_loadsubkey( FILE *F, LPKEYSTRUCT lpkey, int level, char **buf,
1043 int *buflen, DWORD optflag )
1045 LPKEYSTRUCT lpxkey;
1046 int i;
1047 char *s;
1048 LPWSTR name;
1050 TRACE_(reg)("(%p,%p,%d,%s,%d,%lx)\n", F, lpkey, level, debugstr_a(*buf),
1051 *buflen, optflag);
1053 lpkey->flags |= optflag;
1055 /* Good. We already got a line here ... so parse it */
1056 lpxkey = NULL;
1057 while (1) {
1058 i=0;s=*buf;
1059 while (*s=='\t') {
1060 s++;
1061 i++;
1063 if (i>level) {
1064 if (lpxkey==NULL) {
1065 WARN_(reg)("Got a subhierarchy without resp. key?\n");
1066 return 0;
1068 _wine_loadsubkey(F,lpxkey,level+1,buf,buflen,optflag);
1069 continue;
1072 /* let the caller handle this line */
1073 if (i<level || **buf=='\0')
1074 return 1;
1076 /* it can be: a value or a keyname. Parse the name first */
1077 s=_wine_read_USTRING(s,&name);
1079 /* switch() default: hack to avoid gotos */
1080 switch (0) {
1081 default:
1082 if (*s=='\0') {
1083 lpxkey=_find_or_add_key(lpkey,name);
1084 } else {
1085 LPBYTE data;
1086 int len,lastmodified,type;
1088 if (*s!='=') {
1089 WARN_(reg)("Unexpected character: %c\n",*s);
1090 break;
1092 s++;
1093 if (2!=sscanf(s,"%d,%d,",&type,&lastmodified)) {
1094 WARN_(reg)("Haven't understood possible value in |%s|, skipping.\n",*buf);
1095 break;
1097 /* skip the 2 , */
1098 s=strchr(s,',');s++;
1099 s=strchr(s,',');s++;
1100 if (type == REG_SZ || type == REG_EXPAND_SZ) {
1101 s=_wine_read_USTRING(s,(LPWSTR*)&data);
1102 if (data)
1103 len = lstrlenW((LPWSTR)data)*2+2;
1104 else
1105 len = 0;
1106 } else {
1107 len=strlen(s)/2;
1108 data = (LPBYTE)xmalloc(len+1);
1109 for (i=0;i<len;i++) {
1110 data[i]=0;
1111 if (*s>='0' && *s<='9')
1112 data[i]=(*s-'0')<<4;
1113 if (*s>='a' && *s<='f')
1114 data[i]=(*s-'a'+'\xa')<<4;
1115 if (*s>='A' && *s<='F')
1116 data[i]=(*s-'A'+'\xa')<<4;
1117 s++;
1118 if (*s>='0' && *s<='9')
1119 data[i]|=*s-'0';
1120 if (*s>='a' && *s<='f')
1121 data[i]|=*s-'a'+'\xa';
1122 if (*s>='A' && *s<='F')
1123 data[i]|=*s-'A'+'\xa';
1124 s++;
1127 _find_or_add_value(lpkey,name,type,data,len,lastmodified);
1130 /* read the next line */
1131 if (!_wine_read_line(F,buf,buflen))
1132 return 1;
1134 return 1;
1138 /******************************************************************************
1139 * _wine_loadsubreg [Internal]
1141 static int _wine_loadsubreg( FILE *F, LPKEYSTRUCT lpkey, DWORD optflag )
1143 int ver;
1144 char *buf;
1145 int buflen;
1147 buf=xmalloc(10);buflen=10;
1148 if (!_wine_read_line(F,&buf,&buflen)) {
1149 free(buf);
1150 return 0;
1152 if (!sscanf(buf,"WINE REGISTRY Version %d",&ver)) {
1153 free(buf);
1154 return 0;
1156 if (ver!=REGISTRY_SAVE_VERSION) {
1157 TRACE_(reg)("Old format (%d) registry found, ignoring it. (buf was %s).\n",ver,buf);
1158 free(buf);
1159 return 0;
1161 if (!_wine_read_line(F,&buf,&buflen)) {
1162 free(buf);
1163 return 0;
1165 if (!_wine_loadsubkey(F,lpkey,0,&buf,&buflen,optflag)) {
1166 free(buf);
1167 return 0;
1169 free(buf);
1170 return 1;
1174 /******************************************************************************
1175 * _wine_loadreg [Internal]
1177 static void _wine_loadreg( LPKEYSTRUCT lpkey, char *fn, DWORD optflag )
1179 FILE *F;
1181 TRACE_(reg)("(%p,%s,%lx)\n",lpkey,debugstr_a(fn),optflag);
1183 F = fopen(fn,"rb");
1184 if (F==NULL) {
1185 WARN_(reg)("Couldn't open %s for reading: %s\n",fn,strerror(errno) );
1186 return;
1188 if (!_wine_loadsubreg(F,lpkey,optflag)) {
1189 fclose(F);
1190 unlink(fn);
1191 return;
1193 fclose(F);
1196 /******************************************************************************
1197 * _flush_registry [Internal]
1199 * This function allow to flush section of the internal registry. It is mainly
1200 * implements to fix a problem with the global HKU and the local HKU.
1201 * Those two files are read to build the HKU\.Default branch to finaly copy
1202 * this branch onto HKCU hive, once this is done, if we keep the HKU hive as is,
1203 * all the global HKU are saved onto the user's personal version of HKU hive.
1204 * which is bad...
1207 /* Forward declaration of recusive agent */
1208 static void _flush_reg(LPKEYSTRUCT from);
1210 static void _flush_registry( LPKEYSTRUCT from )
1212 /* make sure we have something... */
1213 if (from == NULL)
1214 return;
1216 /* Launch the recusive agent on sub branches */
1217 _flush_reg( from->nextsub );
1218 _flush_reg( from->next );
1220 /* Initialize pointers */
1221 from->nextsub = NULL;
1222 from->next = NULL;
1224 static void _flush_reg( LPKEYSTRUCT from )
1226 int j;
1228 /* make sure we have something... */
1229 if (from == NULL)
1230 return;
1233 * do the same for the child keys
1235 if (from->nextsub != NULL)
1236 _flush_reg(from->nextsub);
1239 * do the same for the sibling keys
1241 if (from->next != NULL)
1242 _flush_reg(from->next);
1245 * iterate through this key's values and delete them
1247 for (j=0;j<from->nrofvalues;j++)
1249 free( (from->values+j)->name);
1250 free( (from->values+j)->data);
1254 * free the structure
1256 if ( from != NULL )
1257 free(from);
1261 /******************************************************************************
1262 * _copy_registry [Internal]
1264 static void _copy_registry( LPKEYSTRUCT from, LPKEYSTRUCT to )
1266 LPKEYSTRUCT lpxkey;
1267 int j;
1268 LPKEYVALUE valfrom;
1270 from=from->nextsub;
1271 while (from) {
1272 lpxkey = _find_or_add_key(to,strdupW(from->keyname));
1274 for (j=0;j<from->nrofvalues;j++) {
1275 LPWSTR name;
1276 LPBYTE data;
1278 valfrom = from->values+j;
1279 name=valfrom->name;
1280 if (name) name=strdupW(name);
1281 data=(LPBYTE)xmalloc(valfrom->len);
1282 memcpy(data,valfrom->data,valfrom->len);
1284 _find_or_add_value(
1285 lpxkey,
1286 name,
1287 valfrom->type,
1288 data,
1289 valfrom->len,
1290 valfrom->lastmodified
1293 _copy_registry(from,lpxkey);
1294 from = from->next;
1299 /* WINDOWS 95 REGISTRY LOADER */
1301 * Structure of a win95 registry database.
1302 * main header:
1303 * 0 : "CREG" - magic
1304 * 4 : DWORD version
1305 * 8 : DWORD offset_of_RGDB_part
1306 * 0C..0F: ? (someone fill in please)
1307 * 10: WORD number of RGDB blocks
1308 * 12: WORD ?
1309 * 14: WORD always 0000?
1310 * 16: WORD always 0001?
1311 * 18..1F: ? (someone fill in please)
1313 * 20: RGKN_section:
1314 * header:
1315 * 0 : "RGKN" - magic
1316 * 4 : DWORD offset to first RGDB section
1317 * 8 : DWORD offset to the root record
1318 * C..0x1B: ? (fill in)
1319 * 0x20 ... offset_of_RGDB_part: Disk Key Entry structures
1321 * Disk Key Entry Structure:
1322 * 00: DWORD - Free entry indicator(?)
1323 * 04: DWORD - Hash = sum of bytes of keyname
1324 * 08: DWORD - Root key indicator? unknown, but usually 0xFFFFFFFF on win95 systems
1325 * 0C: DWORD - disk address of PreviousLevel Key.
1326 * 10: DWORD - disk address of Next Sublevel Key.
1327 * 14: DWORD - disk address of Next Key (on same level).
1328 * DKEP>18: WORD - Nr, Low Significant part.
1329 * 1A: WORD - Nr, High Significant part.
1331 * The disk address always points to the nr part of the previous key entry
1332 * of the referenced key. Don't ask me why, or even if I got this correct
1333 * from staring at 1kg of hexdumps. (DKEP)
1335 * The High significant part of the structure seems to equal the number
1336 * of the RGDB section. The low significant part is a unique ID within
1337 * that RGDB section
1339 * There are two minor corrections to the position of that structure.
1340 * 1. If the address is xxx014 or xxx018 it will be aligned to xxx01c AND
1341 * the DKE reread from there.
1342 * 2. If the address is xxxFFx it will be aligned to (xxx+1)000.
1343 * CPS - I have not experienced the above phenomenon in my registry files
1345 * RGDB_section:
1346 * 00: "RGDB" - magic
1347 * 04: DWORD offset to next RGDB section
1348 * 08: DWORD ?
1349 * 0C: WORD always 000d?
1350 * 0E: WORD RGDB block number
1351 * 10: DWORD ? (equals value at offset 4 - value at offset 8)
1352 * 14..1F: ?
1353 * 20.....: disk keys
1355 * disk key:
1356 * 00: DWORD nextkeyoffset - offset to the next disk key structure
1357 * 08: WORD nrLS - low significant part of NR
1358 * 0A: WORD nrHS - high significant part of NR
1359 * 0C: DWORD bytesused - bytes used in this structure.
1360 * 10: WORD name_len - length of name in bytes. without \0
1361 * 12: WORD nr_of_values - number of values.
1362 * 14: char name[name_len] - name string. No \0.
1363 * 14+name_len: disk values
1364 * nextkeyoffset: ... next disk key
1366 * disk value:
1367 * 00: DWORD type - value type (hmm, could be WORD too)
1368 * 04: DWORD - unknown, usually 0
1369 * 08: WORD namelen - length of Name. 0 means name=NULL
1370 * 0C: WORD datalen - length of Data.
1371 * 10: char name[namelen] - name, no \0
1372 * 10+namelen: BYTE data[datalen] - data, without \0 if string
1373 * 10+namelen+datalen: next values or disk key
1375 * Disk keys are layed out flat ... But, sometimes, nrLS and nrHS are both
1376 * 0xFFFF, which means skipping over nextkeyoffset bytes (including this
1377 * structure) and reading another RGDB_section.
1378 * repeat until end of file.
1380 * An interesting relationship exists in RGDB_section. The value at offset
1381 * 10 equals the value at offset 4 minus the value at offset 8. I have no
1382 * idea at the moment what this means. (Kevin Cozens)
1384 * FIXME: this description needs some serious help, yes.
1387 struct _w95keyvalue {
1388 unsigned long type;
1389 unsigned short datalen;
1390 char *name;
1391 unsigned char *data;
1392 unsigned long x1;
1393 int lastmodified;
1396 struct _w95key {
1397 char *name;
1398 int nrofvals;
1399 struct _w95keyvalue *values;
1400 struct _w95key *prevlvl;
1401 struct _w95key *nextsub;
1402 struct _w95key *next;
1406 struct _w95_info {
1407 char *rgknbuffer;
1408 int rgknsize;
1409 char *rgdbbuffer;
1410 int rgdbsize;
1411 int depth;
1412 int lastmodified;
1416 /******************************************************************************
1417 * _w95_processKey [Internal]
1419 static LPKEYSTRUCT _w95_processKey ( LPKEYSTRUCT lpkey,
1420 int nrLS, int nrMS, struct _w95_info *info )
1423 /* Disk Key Header structure (RGDB part) */
1424 struct dkh {
1425 unsigned long nextkeyoff;
1426 unsigned short nrLS;
1427 unsigned short nrMS;
1428 unsigned long bytesused;
1429 unsigned short keynamelen;
1430 unsigned short values;
1431 unsigned long xx1;
1432 /* keyname */
1433 /* disk key values or nothing */
1435 /* Disk Key Value structure */
1436 struct dkv {
1437 unsigned long type;
1438 unsigned long x1;
1439 unsigned short valnamelen;
1440 unsigned short valdatalen;
1441 /* valname, valdata */
1445 struct dkh dkh;
1446 int bytesread = 0;
1447 char *rgdbdata = info->rgdbbuffer;
1448 int nbytes = info->rgdbsize;
1449 char *curdata = rgdbdata;
1450 char *end = rgdbdata + nbytes;
1451 int off_next_rgdb;
1452 char *next = rgdbdata;
1453 int nrgdb, i;
1454 LPKEYSTRUCT lpxkey;
1456 do {
1457 curdata = next;
1458 if (strncmp(curdata, "RGDB", 4)) return (NULL);
1460 memcpy(&off_next_rgdb,curdata+4,4);
1461 next = curdata + off_next_rgdb;
1462 nrgdb = (int) *((short *)curdata + 7);
1464 } while (nrgdb != nrMS && (next < end));
1466 /* curdata now points to the start of the right RGDB section */
1467 curdata += 0x20;
1469 #define XREAD(whereto,len) \
1470 if ((curdata + len) <= end) {\
1471 memcpy(whereto,curdata,len);\
1472 curdata+=len;\
1473 bytesread+=len;\
1476 while (curdata < next) {
1477 struct dkh *xdkh = (struct dkh*)curdata;
1479 bytesread += sizeof(dkh); /* FIXME... nextkeyoff? */
1480 if (xdkh->nrLS == nrLS) {
1481 memcpy(&dkh,xdkh,sizeof(dkh));
1482 curdata += sizeof(dkh);
1483 break;
1485 curdata += xdkh->nextkeyoff;
1488 if (dkh.nrLS != nrLS) return (NULL);
1490 if (nrgdb != dkh.nrMS)
1491 return (NULL);
1493 assert((dkh.keynamelen<2) || curdata[0]);
1494 lpxkey=_find_or_add_key(lpkey,strcvtA2W(curdata, dkh.keynamelen));
1495 curdata += dkh.keynamelen;
1497 for (i=0;i< dkh.values; i++) {
1498 struct dkv dkv;
1499 LPBYTE data;
1500 int len;
1501 LPWSTR name;
1503 XREAD(&dkv,sizeof(dkv));
1505 name = strcvtA2W(curdata, dkv.valnamelen);
1506 curdata += dkv.valnamelen;
1508 if ((1 << dkv.type) & UNICONVMASK) {
1509 data = (LPBYTE) strcvtA2W(curdata, dkv.valdatalen);
1510 len = 2*(dkv.valdatalen + 1);
1511 } else {
1512 /* I don't think we want to NULL terminate all data */
1513 data = xmalloc(dkv.valdatalen);
1514 memcpy (data, curdata, dkv.valdatalen);
1515 len = dkv.valdatalen;
1518 curdata += dkv.valdatalen;
1520 _find_or_add_value(
1521 lpxkey,
1522 name,
1523 dkv.type,
1524 data,
1525 len,
1526 info->lastmodified
1529 return (lpxkey);
1532 /******************************************************************************
1533 * _w95_walkrgkn [Internal]
1535 static void _w95_walkrgkn( LPKEYSTRUCT prevkey, char *off,
1536 struct _w95_info *info )
1539 /* Disk Key Entry structure (RGKN part) */
1540 struct dke {
1541 unsigned long x1;
1542 unsigned long x2;
1543 unsigned long x3;/*usually 0xFFFFFFFF */
1544 unsigned long prevlvl;
1545 unsigned long nextsub;
1546 unsigned long next;
1547 unsigned short nrLS;
1548 unsigned short nrMS;
1549 } *dke = (struct dke *)off;
1550 LPKEYSTRUCT lpxkey;
1552 if (dke == NULL) {
1553 dke = (struct dke *) ((char *)info->rgknbuffer);
1556 lpxkey = _w95_processKey(prevkey, dke->nrLS, dke->nrMS, info);
1557 /* XXX <-- This is a hack*/
1558 if (!lpxkey) {
1559 lpxkey = prevkey;
1562 if (dke->nextsub != -1 &&
1563 ((dke->nextsub - 0x20) < info->rgknsize)
1564 && (dke->nextsub > 0x20)) {
1566 _w95_walkrgkn(lpxkey,
1567 info->rgknbuffer + dke->nextsub - 0x20,
1568 info);
1571 if (dke->next != -1 &&
1572 ((dke->next - 0x20) < info->rgknsize) &&
1573 (dke->next > 0x20)) {
1574 _w95_walkrgkn(prevkey,
1575 info->rgknbuffer + dke->next - 0x20,
1576 info);
1579 return;
1583 /******************************************************************************
1584 * _w95_loadreg [Internal]
1586 static void _w95_loadreg( char* fn, LPKEYSTRUCT lpkey )
1588 HFILE hfd;
1589 char magic[5];
1590 unsigned long where,version,rgdbsection,end;
1591 struct _w95_info info;
1592 OFSTRUCT ofs;
1593 BY_HANDLE_FILE_INFORMATION hfdinfo;
1595 TRACE_(reg)("Loading Win95 registry database '%s'\n",fn);
1596 hfd=OpenFile(fn,&ofs,OF_READ);
1597 if (hfd==HFILE_ERROR)
1598 return;
1599 magic[4]=0;
1600 if (4!=_lread(hfd,magic,4))
1601 return;
1602 if (strcmp(magic,"CREG")) {
1603 WARN_(reg)("%s is not a w95 registry.\n",fn);
1604 return;
1606 if (4!=_lread(hfd,&version,4))
1607 return;
1608 if (4!=_lread(hfd,&rgdbsection,4))
1609 return;
1610 if (-1==_llseek(hfd,0x20,SEEK_SET))
1611 return;
1612 if (4!=_lread(hfd,magic,4))
1613 return;
1614 if (strcmp(magic,"RGKN")) {
1615 WARN_(reg)("second IFF header not RGKN, but %s\n", magic);
1616 return;
1619 /* STEP 1: Keylink structures */
1620 if (-1==_llseek(hfd,0x40,SEEK_SET))
1621 return;
1622 where = 0x40;
1623 end = rgdbsection;
1625 info.rgknsize = end - where;
1626 info.rgknbuffer = (char*)xmalloc(info.rgknsize);
1627 if (info.rgknsize != _lread(hfd,info.rgknbuffer,info.rgknsize))
1628 return;
1630 if (!GetFileInformationByHandle(hfd,&hfdinfo))
1631 return;
1633 end = hfdinfo.nFileSizeLow;
1634 info.lastmodified = DOSFS_FileTimeToUnixTime(&hfdinfo.ftLastWriteTime,NULL);
1636 if (-1==_llseek(hfd,rgdbsection,SEEK_SET))
1637 return;
1639 info.rgdbbuffer = (char*)xmalloc(end-rgdbsection);
1640 info.rgdbsize = end - rgdbsection;
1642 if (info.rgdbsize !=_lread(hfd,info.rgdbbuffer,info.rgdbsize))
1643 return;
1644 _lclose(hfd);
1646 _w95_walkrgkn(lpkey, NULL, &info);
1648 free (info.rgdbbuffer);
1649 free (info.rgknbuffer);
1653 /* WINDOWS 31 REGISTRY LOADER, supplied by Tor Sjøwall, tor@sn.no */
1656 reghack - windows 3.11 registry data format demo program.
1658 The reg.dat file has 3 parts, a header, a table of 8-byte entries that is
1659 a combined hash table and tree description, and finally a text table.
1661 The header is obvious from the struct header. The taboff1 and taboff2
1662 fields are always 0x20, and their usage is unknown.
1664 The 8-byte entry table has various entry types.
1666 tabent[0] is a root index. The second word has the index of the root of
1667 the directory.
1668 tabent[1..hashsize] is a hash table. The first word in the hash entry is
1669 the index of the key/value that has that hash. Data with the same
1670 hash value are on a circular list. The other three words in the
1671 hash entry are always zero.
1672 tabent[hashsize..tabcnt] is the tree structure. There are two kinds of
1673 entry: dirent and keyent/valent. They are identified by context.
1674 tabent[freeidx] is the first free entry. The first word in a free entry
1675 is the index of the next free entry. The last has 0 as a link.
1676 The other three words in the free list are probably irrelevant.
1678 Entries in text table are preceeded by a word at offset-2. This word
1679 has the value (2*index)+1, where index is the referring keyent/valent
1680 entry in the table. I have no suggestion for the 2* and the +1.
1681 Following the word, there are N bytes of data, as per the keyent/valent
1682 entry length. The offset of the keyent/valent entry is from the start
1683 of the text table to the first data byte.
1685 This information is not available from Microsoft. The data format is
1686 deduced from the reg.dat file by me. Mistakes may
1687 have been made. I claim no rights and give no guarantees for this program.
1689 Tor Sjøwall, tor@sn.no
1692 /* reg.dat header format */
1693 struct _w31_header {
1694 char cookie[8]; /* 'SHCC3.10' */
1695 unsigned long taboff1; /* offset of hash table (??) = 0x20 */
1696 unsigned long taboff2; /* offset of index table (??) = 0x20 */
1697 unsigned long tabcnt; /* number of entries in index table */
1698 unsigned long textoff; /* offset of text part */
1699 unsigned long textsize; /* byte size of text part */
1700 unsigned short hashsize; /* hash size */
1701 unsigned short freeidx; /* free index */
1704 /* generic format of table entries */
1705 struct _w31_tabent {
1706 unsigned short w0, w1, w2, w3;
1709 /* directory tabent: */
1710 struct _w31_dirent {
1711 unsigned short sibling_idx; /* table index of sibling dirent */
1712 unsigned short child_idx; /* table index of child dirent */
1713 unsigned short key_idx; /* table index of key keyent */
1714 unsigned short value_idx; /* table index of value valent */
1717 /* key tabent: */
1718 struct _w31_keyent {
1719 unsigned short hash_idx; /* hash chain index for string */
1720 unsigned short refcnt; /* reference count */
1721 unsigned short length; /* length of string */
1722 unsigned short string_off; /* offset of string in text table */
1725 /* value tabent: */
1726 struct _w31_valent {
1727 unsigned short hash_idx; /* hash chain index for string */
1728 unsigned short refcnt; /* reference count */
1729 unsigned short length; /* length of string */
1730 unsigned short string_off; /* offset of string in text table */
1733 /* recursive helper function to display a directory tree */
1734 void
1735 __w31_dumptree( unsigned short idx,
1736 unsigned char *txt,
1737 struct _w31_tabent *tab,
1738 struct _w31_header *head,
1739 LPKEYSTRUCT lpkey,
1740 time_t lastmodified,
1741 int level
1743 struct _w31_dirent *dir;
1744 struct _w31_keyent *key;
1745 struct _w31_valent *val;
1746 LPKEYSTRUCT xlpkey = NULL;
1747 LPWSTR name,value;
1748 static char tail[400];
1750 while (idx!=0) {
1751 dir=(struct _w31_dirent*)&tab[idx];
1753 if (dir->key_idx) {
1754 key = (struct _w31_keyent*)&tab[dir->key_idx];
1756 memcpy(tail,&txt[key->string_off],key->length);
1757 tail[key->length]='\0';
1758 /* all toplevel entries AND the entries in the
1759 * toplevel subdirectory belong to \SOFTWARE\Classes
1761 if (!level && !lstrcmpA(tail,".classes")) {
1762 __w31_dumptree(dir->child_idx,txt,tab,head,lpkey,lastmodified,level+1);
1763 idx=dir->sibling_idx;
1764 continue;
1766 name=strdupA2W(tail);
1768 xlpkey=_find_or_add_key(lpkey,name);
1770 /* only add if leaf node or valued node */
1771 if (dir->value_idx!=0||dir->child_idx==0) {
1772 if (dir->value_idx) {
1773 val=(struct _w31_valent*)&tab[dir->value_idx];
1774 memcpy(tail,&txt[val->string_off],val->length);
1775 tail[val->length]='\0';
1776 value=strdupA2W(tail);
1777 _find_or_add_value(xlpkey,NULL,REG_SZ,(LPBYTE)value,lstrlenW(value)*2+2,lastmodified);
1780 } else {
1781 TRACE_(reg)("strange: no directory key name, idx=%04x\n", idx);
1783 __w31_dumptree(dir->child_idx,txt,tab,head,xlpkey,lastmodified,level+1);
1784 idx=dir->sibling_idx;
1789 /******************************************************************************
1790 * _w31_loadreg [Internal]
1792 void _w31_loadreg(void) {
1793 HFILE hf;
1794 struct _w31_header head;
1795 struct _w31_tabent *tab;
1796 unsigned char *txt;
1797 int len;
1798 OFSTRUCT ofs;
1799 BY_HANDLE_FILE_INFORMATION hfinfo;
1800 time_t lastmodified;
1801 LPKEYSTRUCT lpkey;
1803 TRACE_(reg)("(void)\n");
1805 hf = OpenFile("reg.dat",&ofs,OF_READ);
1806 if (hf==HFILE_ERROR)
1807 return;
1809 /* read & dump header */
1810 if (sizeof(head)!=_lread(hf,&head,sizeof(head))) {
1811 ERR_(reg)("reg.dat is too short.\n");
1812 _lclose(hf);
1813 return;
1815 if (memcmp(head.cookie, "SHCC3.10", sizeof(head.cookie))!=0) {
1816 ERR_(reg)("reg.dat has bad signature.\n");
1817 _lclose(hf);
1818 return;
1821 len = head.tabcnt * sizeof(struct _w31_tabent);
1822 /* read and dump index table */
1823 tab = xmalloc(len);
1824 if (len!=_lread(hf,tab,len)) {
1825 ERR_(reg)("couldn't read %d bytes.\n",len);
1826 free(tab);
1827 _lclose(hf);
1828 return;
1831 /* read text */
1832 txt = xmalloc(head.textsize);
1833 if (-1==_llseek(hf,head.textoff,SEEK_SET)) {
1834 ERR_(reg)("couldn't seek to textblock.\n");
1835 free(tab);
1836 free(txt);
1837 _lclose(hf);
1838 return;
1840 if (head.textsize!=_lread(hf,txt,head.textsize)) {
1841 ERR_(reg)("textblock too short (%d instead of %ld).\n",len,head.textsize);
1842 free(tab);
1843 free(txt);
1844 _lclose(hf);
1845 return;
1848 if (!GetFileInformationByHandle(hf,&hfinfo)) {
1849 ERR_(reg)("GetFileInformationByHandle failed?.\n");
1850 free(tab);
1851 free(txt);
1852 _lclose(hf);
1853 return;
1855 lastmodified = DOSFS_FileTimeToUnixTime(&hfinfo.ftLastWriteTime,NULL);
1856 lpkey = lookup_hkey(HKEY_CLASSES_ROOT);
1857 __w31_dumptree(tab[0].w1,txt,tab,&head,lpkey,lastmodified,0);
1858 free(tab);
1859 free(txt);
1860 _lclose(hf);
1861 return;
1865 /**********************************************************************************
1866 * SHELL_LoadRegistry [Internal]
1868 void SHELL_LoadRegistry( void )
1870 char *fn, *home;
1871 LPKEYSTRUCT lpkey, HKCU, HKU, HKLM;
1872 HKEY hkey;
1874 TRACE_(reg)("(void)\n");
1876 HKCU = lookup_hkey(HKEY_CURRENT_USER);
1877 HKU = lookup_hkey(HKEY_USERS);
1878 HKLM = lookup_hkey(HKEY_LOCAL_MACHINE);
1880 /* Load windows 3.1 entries */
1881 _w31_loadreg();
1882 /* Load windows 95 entries */
1883 _w95_loadreg("C:\\system.1st", HKLM);
1884 _w95_loadreg("system.dat", HKLM);
1885 _w95_loadreg("user.dat", HKU);
1888 * Load the global HKU hive directly from sysconfdir
1890 _wine_loadreg( HKU, SAVE_USERS_DEFAULT, 0);
1893 * Load the global machine defaults directly form sysconfdir
1895 _wine_loadreg( HKLM, SAVE_LOCAL_MACHINE_DEFAULT, 0);
1898 * Load the user saved registries
1900 if ((home = getenv( "HOME" )))
1903 * Load user's personal versions of global HKU/.Default keys
1905 fn=(char*)xmalloc(
1906 strlen(home)+
1907 strlen(WINE_PREFIX)+
1908 strlen(SAVE_LOCAL_USERS_DEFAULT)+2);
1910 strcpy(fn, home);
1911 strcat(fn, WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
1912 _wine_loadreg(HKU, fn, REG_OPTION_TAINTED);
1913 free(fn);
1916 * Load HKCU, attempt to get the registry location from the config
1917 * file first, if exist, load and keep going.
1919 fn = xmalloc( MAX_PATHNAME_LEN );
1920 if ( PROFILE_GetWineIniString(
1921 "Registry",
1922 "UserFileName",
1923 "",
1924 fn,
1925 MAX_PATHNAME_LEN - 1))
1927 _wine_loadreg(HKCU,fn,0);
1929 free (fn);
1931 fn=(char*)xmalloc(
1932 strlen(home)+
1933 strlen(WINE_PREFIX)+
1934 strlen(SAVE_CURRENT_USER)+2);
1936 strcpy(fn, home);
1937 strcat(fn, WINE_PREFIX"/"SAVE_CURRENT_USER);
1938 _wine_loadreg(HKCU, fn, REG_OPTION_TAINTED);
1939 free(fn);
1942 * Load HKLM, attempt to get the registry location from the config
1943 * file first, if exist, load and keep going.
1945 fn = xmalloc ( MAX_PATHNAME_LEN);
1946 if ( PROFILE_GetWineIniString(
1947 "Registry",
1948 "LocalMachineFileName",
1949 "",
1950 fn,
1951 MAX_PATHNAME_LEN - 1))
1953 _wine_loadreg(HKLM, fn, 0);
1955 free(fn);
1957 fn=(char*)xmalloc(
1958 strlen(home)+
1959 strlen(WINE_PREFIX)+
1960 strlen(SAVE_LOCAL_MACHINE)+2);
1962 strcpy(fn,home);
1963 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
1964 _wine_loadreg(HKLM, fn, REG_OPTION_TAINTED);
1965 free(fn);
1967 else
1969 WARN_(reg)("Failed to get homedirectory of UID %ld.\n",(long) getuid());
1973 * Obtain the handle of the HKU\.Default key.
1974 * in order to copy HKU\.Default\* onto HKEY_CURRENT_USER
1976 RegCreateKey16(HKEY_USERS,".Default",&hkey);
1977 lpkey = lookup_hkey(hkey);
1978 if(!lpkey)
1979 WARN_(reg)("Could not create global user default key\n");
1980 else
1981 _copy_registry(lpkey, HKCU );
1983 RegCloseKey(hkey);
1986 * Since HKU is built from the global HKU and the local user HKU file we must
1987 * flush the HKU tree we have built at this point otherwise the part brought
1988 * in from the global HKU is saved into the local HKU. To avoid this
1989 * useless dupplication of HKU keys we reread the local HKU key.
1992 /* Allways flush the HKU hive and reload it only with user's personal HKU */
1993 _flush_registry(HKU);
1995 /* Reload user's local HKU hive */
1996 if (home)
1998 fn=(char*)xmalloc( strlen(home) + strlen(WINE_PREFIX)
1999 + strlen(SAVE_LOCAL_USERS_DEFAULT) + 2);
2001 strcpy(fn,home);
2002 strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_USERS_DEFAULT);
2004 _wine_loadreg( HKU, fn, REG_OPTION_TAINTED);
2006 free(fn);
2010 * Make sure the update mode is there
2012 if (ERROR_SUCCESS==RegCreateKey16(HKEY_CURRENT_USER,KEY_REGISTRY,&hkey))
2014 DWORD junk,type,len;
2015 char data[5];
2017 len=4;
2018 if (( RegQueryValueExA(
2019 hkey,
2020 VAL_SAVEUPDATED,
2021 &junk,
2022 &type,
2023 data,
2024 &len) != ERROR_SUCCESS) || (type != REG_SZ))
2026 RegSetValueExA(hkey,VAL_SAVEUPDATED,0,REG_SZ,"yes",4);
2029 RegCloseKey(hkey);
2034 /********************* API FUNCTIONS ***************************************/
2036 * Open Keys.
2038 * All functions are stubs to RegOpenKeyEx32W where all the
2039 * magic happens.
2041 * Callpath:
2042 * RegOpenKey16 -> RegOpenKey32A -> RegOpenKeyEx32A \
2043 * RegOpenKey32W -> RegOpenKeyEx32W
2047 /******************************************************************************
2048 * RegOpenKeyEx32W [ADVAPI32.150]
2049 * Opens the specified key
2051 * Unlike RegCreateKeyEx, this does not create the key if it does not exist.
2053 * PARAMS
2054 * hkey [I] Handle of open key
2055 * lpszSubKey [I] Name of subkey to open
2056 * dwReserved [I] Reserved - must be zero
2057 * samDesired [I] Security access mask
2058 * retkey [O] Address of handle of open key
2060 * RETURNS
2061 * Success: ERROR_SUCCESS
2062 * Failure: Error code
2064 DWORD WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwReserved,
2065 REGSAM samDesired, LPHKEY retkey )
2067 LPKEYSTRUCT lpNextKey,lpxkey;
2068 LPWSTR *wps;
2069 int wpc,i;
2071 TRACE_(reg)("(0x%x,%s,%ld,%lx,%p)\n", hkey,debugstr_w(lpszSubKey),dwReserved,
2072 samDesired,retkey);
2074 lpNextKey = lookup_hkey( hkey );
2075 if (!lpNextKey)
2076 return ERROR_INVALID_HANDLE;
2078 if (!lpszSubKey || !*lpszSubKey) {
2079 /* Either NULL or pointer to empty string, so return a new handle
2080 to the original hkey */
2081 currenthandle += 2;
2082 add_handle(currenthandle,lpNextKey,samDesired);
2083 *retkey=currenthandle;
2084 return ERROR_SUCCESS;
2087 if (lpszSubKey[0] == '\\') {
2088 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2089 return ERROR_BAD_PATHNAME;
2092 split_keypath(lpszSubKey,&wps,&wpc);
2093 i = 0;
2094 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2095 lpxkey = lpNextKey;
2097 while (wps[i]) {
2098 lpxkey=lpNextKey->nextsub;
2099 while (lpxkey) {
2100 if (!lstrcmpiW(wps[i],lpxkey->keyname)) {
2101 break;
2103 lpxkey=lpxkey->next;
2106 if (!lpxkey) {
2107 TRACE_(reg)("Could not find subkey %s\n",debugstr_w(wps[i]));
2108 FREE_KEY_PATH;
2109 return ERROR_FILE_NOT_FOUND;
2111 i++;
2112 lpNextKey = lpxkey;
2115 currenthandle += 2;
2116 add_handle(currenthandle,lpxkey,samDesired);
2117 *retkey = currenthandle;
2118 TRACE_(reg)(" Returning %x\n", currenthandle);
2119 FREE_KEY_PATH;
2120 return ERROR_SUCCESS;
2124 /******************************************************************************
2125 * RegOpenKeyEx32A [ADVAPI32.149]
2127 DWORD WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2128 REGSAM samDesired, LPHKEY retkey )
2130 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2131 DWORD ret;
2133 TRACE_(reg)("(%x,%s,%ld,%lx,%p)\n",hkey,debugstr_a(lpszSubKey),dwReserved,
2134 samDesired,retkey);
2135 ret = RegOpenKeyExW( hkey, lpszSubKeyW, dwReserved, samDesired, retkey );
2136 free(lpszSubKeyW);
2137 return ret;
2141 /******************************************************************************
2142 * RegOpenKey32W [ADVAPI32.151]
2144 * PARAMS
2145 * hkey [I] Handle of open key
2146 * lpszSubKey [I] Address of name of subkey to open
2147 * retkey [O] Address of handle of open key
2149 * RETURNS
2150 * Success: ERROR_SUCCESS
2151 * Failure: Error code
2153 DWORD WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2155 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_w(lpszSubKey),retkey);
2156 return RegOpenKeyExW( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
2160 /******************************************************************************
2161 * RegOpenKey32A [ADVAPI32.148]
2163 DWORD WINAPI RegOpenKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2165 DWORD ret;
2166 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
2167 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2168 ret = RegOpenKeyW( hkey, lpszSubKeyW, retkey );
2169 free(lpszSubKeyW);
2170 return ret;
2174 /******************************************************************************
2175 * RegOpenKey16 [SHELL.1] [KERNEL.217]
2177 DWORD WINAPI RegOpenKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2179 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2180 return RegOpenKeyA( hkey, lpszSubKey, retkey );
2185 * Create keys
2187 * All those functions convert their respective
2188 * arguments and call RegCreateKeyExW at the end.
2190 * We stay away from the Ex functions as long as possible because there are
2191 * differences in the return values
2193 * Callpath:
2194 * RegCreateKeyEx32A \
2195 * RegCreateKey16 -> RegCreateKey32A -> RegCreateKey32W -> RegCreateKeyEx32W
2199 /******************************************************************************
2200 * RegCreateKeyEx32W [ADVAPI32.131]
2202 * PARAMS
2203 * hkey [I] Handle of an open key
2204 * lpszSubKey [I] Address of subkey name
2205 * dwReserved [I] Reserved - must be 0
2206 * lpszClass [I] Address of class string
2207 * fdwOptions [I] Special options flag
2208 * samDesired [I] Desired security access
2209 * lpSecAttribs [I] Address of key security structure
2210 * retkey [O] Address of buffer for opened handle
2211 * lpDispos [O] Receives REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
2213 DWORD WINAPI RegCreateKeyExW( HKEY hkey, LPCWSTR lpszSubKey,
2214 DWORD dwReserved, LPWSTR lpszClass,
2215 DWORD fdwOptions, REGSAM samDesired,
2216 LPSECURITY_ATTRIBUTES lpSecAttribs,
2217 LPHKEY retkey, LPDWORD lpDispos )
2219 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
2220 LPWSTR *wps;
2221 int wpc,i;
2223 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n", hkey,
2224 debugstr_w(lpszSubKey), dwReserved, debugstr_w(lpszClass),
2225 fdwOptions, samDesired, lpSecAttribs, retkey, lpDispos);
2227 lpNextKey = lookup_hkey(hkey);
2228 if (!lpNextKey)
2229 return ERROR_INVALID_HANDLE;
2231 /* Check for valid options */
2232 switch(fdwOptions) {
2233 case REG_OPTION_NON_VOLATILE:
2234 case REG_OPTION_VOLATILE:
2235 case REG_OPTION_BACKUP_RESTORE:
2236 break;
2237 default:
2238 return ERROR_INVALID_PARAMETER;
2241 /* Sam has to be a combination of the following */
2242 if (!(samDesired &
2243 (KEY_ALL_ACCESS | KEY_CREATE_LINK | KEY_CREATE_SUB_KEY |
2244 KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_NOTIFY |
2245 KEY_QUERY_VALUE | KEY_READ | KEY_SET_VALUE | KEY_WRITE)))
2246 return ERROR_INVALID_PARAMETER;
2248 if (!lpszSubKey || !*lpszSubKey) {
2249 currenthandle += 2;
2250 add_handle(currenthandle,lpNextKey,samDesired);
2251 *retkey=currenthandle;
2252 TRACE_(reg)("Returning %x\n", currenthandle);
2253 lpNextKey->flags|=REG_OPTION_TAINTED;
2254 return ERROR_SUCCESS;
2257 if (lpszSubKey[0] == '\\') {
2258 WARN_(reg)("Subkey %s must not begin with backslash.\n",debugstr_w(lpszSubKey));
2259 return ERROR_BAD_PATHNAME;
2262 split_keypath(lpszSubKey,&wps,&wpc);
2263 i = 0;
2264 while ((i<wpc) && (wps[i][0]=='\0')) i++;
2265 lpxkey = lpNextKey;
2266 while (wps[i]) {
2267 lpxkey=lpNextKey->nextsub;
2268 while (lpxkey) {
2269 if (!lstrcmpiW(wps[i],lpxkey->keyname))
2270 break;
2271 lpxkey=lpxkey->next;
2273 if (!lpxkey)
2274 break;
2275 i++;
2276 lpNextKey = lpxkey;
2278 if (lpxkey) {
2279 currenthandle += 2;
2280 add_handle(currenthandle,lpxkey,samDesired);
2281 lpxkey->flags |= REG_OPTION_TAINTED;
2282 *retkey = currenthandle;
2283 TRACE_(reg)("Returning %x\n", currenthandle);
2284 if (lpDispos)
2285 *lpDispos = REG_OPENED_EXISTING_KEY;
2286 FREE_KEY_PATH;
2287 return ERROR_SUCCESS;
2290 /* Good. Now the hard part */
2291 while (wps[i]) {
2292 lplpPrevKey = &(lpNextKey->nextsub);
2293 lpxkey = *lplpPrevKey;
2294 while (lpxkey) {
2295 lplpPrevKey = &(lpxkey->next);
2296 lpxkey = *lplpPrevKey;
2298 *lplpPrevKey=malloc(sizeof(KEYSTRUCT));
2299 if (!*lplpPrevKey) {
2300 FREE_KEY_PATH;
2301 TRACE_(reg)("Returning OUTOFMEMORY\n");
2302 return ERROR_OUTOFMEMORY;
2304 memset(*lplpPrevKey,'\0',sizeof(KEYSTRUCT));
2305 TRACE_(reg)("Adding %s\n", debugstr_w(wps[i]));
2306 (*lplpPrevKey)->keyname = strdupW(wps[i]);
2307 (*lplpPrevKey)->next = NULL;
2308 (*lplpPrevKey)->nextsub = NULL;
2309 (*lplpPrevKey)->values = NULL;
2310 (*lplpPrevKey)->nrofvalues = 0;
2311 (*lplpPrevKey)->flags = REG_OPTION_TAINTED;
2312 if (lpszClass)
2313 (*lplpPrevKey)->class = strdupW(lpszClass);
2314 else
2315 (*lplpPrevKey)->class = NULL;
2316 lpNextKey = *lplpPrevKey;
2317 i++;
2319 currenthandle += 2;
2320 add_handle(currenthandle,lpNextKey,samDesired);
2322 /*FIXME: flag handling correct? */
2323 lpNextKey->flags= fdwOptions |REG_OPTION_TAINTED;
2324 if (lpszClass)
2325 lpNextKey->class = strdupW(lpszClass);
2326 else
2327 lpNextKey->class = NULL;
2328 *retkey = currenthandle;
2329 TRACE_(reg)("Returning %x\n", currenthandle);
2330 if (lpDispos)
2331 *lpDispos = REG_CREATED_NEW_KEY;
2332 FREE_KEY_PATH;
2333 return ERROR_SUCCESS;
2337 /******************************************************************************
2338 * RegCreateKeyEx32A [ADVAPI32.130]
2340 DWORD WINAPI RegCreateKeyExA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwReserved,
2341 LPSTR lpszClass, DWORD fdwOptions,
2342 REGSAM samDesired,
2343 LPSECURITY_ATTRIBUTES lpSecAttribs,
2344 LPHKEY retkey, LPDWORD lpDispos )
2346 LPWSTR lpszSubKeyW, lpszClassW;
2347 DWORD ret;
2349 TRACE_(reg)("(%x,%s,%ld,%s,%lx,%lx,%p,%p,%p)\n",hkey,debugstr_a(lpszSubKey),
2350 dwReserved,debugstr_a(lpszClass),fdwOptions,samDesired,lpSecAttribs,
2351 retkey,lpDispos);
2353 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2354 lpszClassW = lpszClass?strdupA2W(lpszClass):NULL;
2356 ret = RegCreateKeyExW( hkey, lpszSubKeyW, dwReserved, lpszClassW,
2357 fdwOptions, samDesired, lpSecAttribs, retkey,
2358 lpDispos );
2360 if(lpszSubKeyW) free(lpszSubKeyW);
2361 if(lpszClassW) free(lpszClassW);
2363 return ret;
2367 /******************************************************************************
2368 * RegCreateKey32W [ADVAPI32.132]
2370 DWORD WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPHKEY retkey )
2372 DWORD junk;
2373 LPKEYSTRUCT lpNextKey;
2375 TRACE_(reg)("(%x,%s,%p)\n", hkey,debugstr_w(lpszSubKey),retkey);
2377 /* This check is here because the return value is different than the
2378 one from the Ex functions */
2379 lpNextKey = lookup_hkey(hkey);
2380 if (!lpNextKey)
2381 return ERROR_BADKEY;
2383 return RegCreateKeyExW( hkey, lpszSubKey, 0, NULL,
2384 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2385 retkey, &junk);
2389 /******************************************************************************
2390 * RegCreateKey32A [ADVAPI32.129]
2392 DWORD WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2394 DWORD ret;
2395 LPWSTR lpszSubKeyW;
2397 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2398 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
2399 ret = RegCreateKeyW( hkey, lpszSubKeyW, retkey );
2400 if(lpszSubKeyW) free(lpszSubKeyW);
2401 return ret;
2405 /******************************************************************************
2406 * RegCreateKey16 [SHELL.2] [KERNEL.218]
2408 DWORD WINAPI RegCreateKey16( HKEY hkey, LPCSTR lpszSubKey, LPHKEY retkey )
2410 TRACE_(reg)("(%x,%s,%p)\n",hkey,debugstr_a(lpszSubKey),retkey);
2411 return RegCreateKeyA( hkey, lpszSubKey, retkey );
2416 * Query Value Functions
2417 * Win32 differs between keynames and valuenames.
2418 * multiple values may belong to one key, the special value
2419 * with name NULL is the default value used by the win31
2420 * compat functions.
2422 * Callpath:
2423 * RegQueryValue16 -> RegQueryValue32A -> RegQueryValueEx32A \
2424 * RegQueryValue32W -> RegQueryValueEx32W
2428 /******************************************************************************
2429 * RegQueryValueEx32W [ADVAPI32.158]
2430 * Retrieves type and data for a specified name associated with an open key
2432 * PARAMS
2433 * hkey [I] Handle of key to query
2434 * lpValueName [I] Name of value to query
2435 * lpdwReserved [I] Reserved - must be NULL
2436 * lpdwType [O] Address of buffer for value type. If NULL, the type
2437 * is not required.
2438 * lpbData [O] Address of data buffer. If NULL, the actual data is
2439 * not required.
2440 * lpcbData [I/O] Address of data buffer size
2442 * RETURNS
2443 * ERROR_SUCCESS: Success
2444 * ERROR_MORE_DATA: !!! if the specified buffer is not big enough to hold the data
2445 * buffer is left untouched. The MS-documentation is wrong (js) !!!
2447 DWORD WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR lpValueName,
2448 LPDWORD lpdwReserved, LPDWORD lpdwType,
2449 LPBYTE lpbData, LPDWORD lpcbData )
2451 LPKEYSTRUCT lpkey;
2452 int i;
2453 DWORD ret;
2455 TRACE_(reg)("(0x%x,%s,%p,%p,%p,%p=%ld)\n", hkey, debugstr_w(lpValueName),
2456 lpdwReserved, lpdwType, lpbData, lpcbData, lpcbData?*lpcbData:0);
2458 lpkey = lookup_hkey(hkey);
2460 if (!lpkey)
2461 return ERROR_INVALID_HANDLE;
2463 if ((lpbData && ! lpcbData) || lpdwReserved)
2464 return ERROR_INVALID_PARAMETER;
2466 /* An empty name string is equivalent to NULL */
2467 if (lpValueName && !*lpValueName)
2468 lpValueName = NULL;
2470 if (lpValueName==NULL)
2471 { /* Use key's unnamed or default value, if any */
2472 for (i=0;i<lpkey->nrofvalues;i++)
2473 if (lpkey->values[i].name==NULL)
2474 break;
2476 else
2477 { /* Search for the key name */
2478 for (i=0;i<lpkey->nrofvalues;i++)
2479 if ( lpkey->values[i].name && !lstrcmpiW(lpValueName,lpkey->values[i].name))
2480 break;
2483 if (i==lpkey->nrofvalues)
2484 { TRACE_(reg)(" Key not found\n");
2485 if (lpValueName==NULL)
2486 { /* Empty keyname not found */
2487 if (lpbData)
2488 { *(WCHAR*)lpbData = 0;
2489 *lpcbData = 2;
2491 if (lpdwType)
2492 *lpdwType = REG_SZ;
2493 TRACE_(reg)(" Returning an empty string\n");
2494 return ERROR_SUCCESS;
2496 return ERROR_FILE_NOT_FOUND;
2499 ret = ERROR_SUCCESS;
2501 if (lpdwType) /* type required ?*/
2502 *lpdwType = lpkey->values[i].type;
2504 if (lpbData) /* data required ?*/
2505 { if (*lpcbData >= lpkey->values[i].len) /* buffer large enought ?*/
2506 memcpy(lpbData,lpkey->values[i].data,lpkey->values[i].len);
2507 else
2508 ret = ERROR_MORE_DATA;
2511 if (lpcbData) /* size required ?*/
2512 { *lpcbData = lpkey->values[i].len;
2515 debug_print_value ( lpbData, &lpkey->values[i]);
2517 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2519 return ret;
2523 /******************************************************************************
2524 * RegQueryValue32W [ADVAPI32.159]
2526 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2527 LPLONG lpcbData )
2529 HKEY xhkey;
2530 DWORD ret,lpdwType;
2532 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2533 lpcbData?*lpcbData:0);
2535 /* Only open subkey, if we really do descend */
2536 if (lpszSubKey && *lpszSubKey) {
2537 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2538 if (ret != ERROR_SUCCESS) {
2539 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2540 return ret;
2542 } else
2543 xhkey = hkey;
2545 lpdwType = REG_SZ;
2546 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2547 lpcbData );
2548 if (xhkey != hkey)
2549 RegCloseKey(xhkey);
2550 return ret;
2554 /******************************************************************************
2555 * RegQueryValueEx32A [ADVAPI32.157]
2557 * NOTES:
2558 * the documantation is wrong: if the buffer is to small it remains untouched
2560 * FIXME: check returnvalue (len) for an empty key
2562 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2563 LPDWORD lpdwReserved, LPDWORD lpdwType,
2564 LPBYTE lpbData, LPDWORD lpcbData )
2566 LPWSTR lpszValueNameW;
2567 LPBYTE mybuf = NULL;
2568 DWORD ret, mytype, mylen = 0;
2570 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2571 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2573 if (!lpcbData && lpbData) /* buffer without size is illegal */
2574 { return ERROR_INVALID_PARAMETER;
2577 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2579 /* get just the type first */
2580 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2582 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2583 { if(lpszValueNameW) free(lpszValueNameW);
2584 return ret;
2587 if (lpcbData) /* at least length requested? */
2588 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2589 { if (lpbData ) /* value requested? */
2590 { mylen = 2*( *lpcbData );
2591 mybuf = (LPBYTE)xmalloc( mylen );
2594 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2596 if (ret == ERROR_SUCCESS )
2597 { if ( lpbData )
2598 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2602 *lpcbData = mylen/2; /* size is in byte! */
2604 else /* no strings, call it straight */
2605 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2609 if (lpdwType) /* type when requested */
2610 { *lpdwType = mytype;
2613 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2615 if(mybuf) free(mybuf);
2616 if(lpszValueNameW) free(lpszValueNameW);
2617 return ret;
2621 /******************************************************************************
2622 * RegQueryValueEx16 [KERNEL.225]
2624 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2625 LPDWORD lpdwReserved, LPDWORD lpdwType,
2626 LPBYTE lpbData, LPDWORD lpcbData )
2628 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2629 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2630 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2631 lpbData, lpcbData );
2635 /******************************************************************************
2636 * RegQueryValue32A [ADVAPI32.156]
2638 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2639 LPLONG lpcbData )
2641 HKEY xhkey;
2642 DWORD ret, dwType;
2644 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2645 lpcbData?*lpcbData:0);
2647 if (lpszSubKey && *lpszSubKey) {
2648 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2649 if( ret != ERROR_SUCCESS )
2650 return ret;
2651 } else
2652 xhkey = hkey;
2654 dwType = REG_SZ;
2655 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2656 lpcbData );
2657 if( xhkey != hkey )
2658 RegCloseKey( xhkey );
2659 return ret;
2663 /******************************************************************************
2664 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2666 * NOTES
2667 * Is this HACK still applicable?
2669 * HACK
2670 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2671 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2672 * Aldus FH4)
2674 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2675 LPDWORD lpcbData )
2677 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2678 lpcbData?*lpcbData:0);
2680 if (lpcbData)
2681 *lpcbData &= 0xFFFF;
2682 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2687 * Setting values of Registry keys
2689 * Callpath:
2690 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2691 * RegSetValue32W -> RegSetValueEx32W
2695 /******************************************************************************
2696 * RegSetValueEx32W [ADVAPI32.170]
2697 * Sets the data and type of a value under a register key
2699 * PARAMS
2700 * hkey [I] Handle of key to set value for
2701 * lpszValueName [I] Name of value to set
2702 * dwReserved [I] Reserved - must be zero
2703 * dwType [I] Flag for value type
2704 * lpbData [I] Address of value data
2705 * cbData [I] Size of value data
2707 * RETURNS
2708 * Success: ERROR_SUCCESS
2709 * Failure: Error code
2711 * NOTES
2712 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2714 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2715 DWORD dwReserved, DWORD dwType,
2716 CONST BYTE *lpbData, DWORD cbData)
2718 LPKEYSTRUCT lpkey;
2719 int i;
2721 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2722 dwReserved, dwType, lpbData, cbData);
2724 lpkey = lookup_hkey( hkey );
2726 if (!lpkey)
2727 return ERROR_INVALID_HANDLE;
2729 lpkey->flags |= REG_OPTION_TAINTED;
2731 if (lpszValueName==NULL) {
2732 /* Sets type and name for key's unnamed or default value */
2733 for (i=0;i<lpkey->nrofvalues;i++)
2734 if (lpkey->values[i].name==NULL)
2735 break;
2736 } else {
2737 for (i=0;i<lpkey->nrofvalues;i++)
2738 if ( lpkey->values[i].name &&
2739 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2741 break;
2743 if (i==lpkey->nrofvalues) {
2744 lpkey->values = (LPKEYVALUE)xrealloc(
2745 lpkey->values,
2746 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2748 lpkey->nrofvalues++;
2749 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2751 if (lpkey->values[i].name==NULL) {
2752 if (lpszValueName)
2753 lpkey->values[i].name = strdupW(lpszValueName);
2754 else
2755 lpkey->values[i].name = NULL;
2758 if (dwType == REG_SZ)
2759 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2761 lpkey->values[i].len = cbData;
2762 lpkey->values[i].type = dwType;
2763 if (lpkey->values[i].data !=NULL)
2764 free(lpkey->values[i].data);
2765 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2766 lpkey->values[i].lastmodified = time(NULL);
2767 memcpy(lpkey->values[i].data,lpbData,cbData);
2768 return ERROR_SUCCESS;
2772 /******************************************************************************
2773 * RegSetValueEx32A [ADVAPI32.169]
2775 * NOTES
2776 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2778 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2779 DWORD dwReserved, DWORD dwType,
2780 CONST BYTE *lpbData, DWORD cbData )
2782 LPBYTE buf;
2783 LPWSTR lpszValueNameW;
2784 DWORD ret;
2786 if (!lpbData)
2787 return (ERROR_INVALID_PARAMETER);
2789 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2790 dwReserved,dwType,lpbData,cbData);
2792 if ((1<<dwType) & UNICONVMASK)
2793 { if (dwType == REG_SZ)
2794 cbData = strlen ((LPCSTR)lpbData)+1;
2796 buf = (LPBYTE)xmalloc( cbData *2 );
2797 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2798 cbData=2*cbData;
2800 else
2801 buf=(LPBYTE)lpbData;
2803 if (lpszValueName)
2804 lpszValueNameW = strdupA2W(lpszValueName);
2805 else
2806 lpszValueNameW = NULL;
2808 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2810 if (lpszValueNameW)
2811 free(lpszValueNameW);
2813 if (buf!=lpbData)
2814 free(buf);
2816 return ret;
2820 /******************************************************************************
2821 * RegSetValueEx16 [KERNEL.226]
2823 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2824 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2826 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2827 dwReserved,dwType,lpbData,cbData);
2828 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2829 cbData );
2833 /******************************************************************************
2834 * RegSetValue32W [ADVAPI32.171]
2836 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2837 LPCWSTR lpszData, DWORD cbData )
2839 HKEY xhkey;
2840 DWORD ret;
2842 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2843 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2845 if (lpszSubKey && *lpszSubKey) {
2846 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2847 if (ret!=ERROR_SUCCESS)
2848 return ret;
2849 } else
2850 xhkey=hkey;
2851 if (dwType!=REG_SZ) {
2852 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2853 dwType=REG_SZ;
2855 if (cbData!=2*lstrlenW(lpszData)+2) {
2856 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2857 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2859 cbData=2*lstrlenW(lpszData)+2;
2861 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2862 if (hkey!=xhkey)
2863 RegCloseKey(xhkey);
2864 return ret;
2868 /******************************************************************************
2869 * RegSetValue32A [ADVAPI32.168]
2872 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2873 LPCSTR lpszData, DWORD cbData )
2875 DWORD ret;
2876 HKEY xhkey;
2878 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2879 if (lpszSubKey && *lpszSubKey) {
2880 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2881 if (ret!=ERROR_SUCCESS)
2882 return ret;
2883 } else
2884 xhkey=hkey;
2886 if (dwType!=REG_SZ) {
2887 TRACE_(reg)("dwType=%ld!\n",dwType);
2888 dwType=REG_SZ;
2890 if (cbData!=strlen(lpszData)+1)
2891 cbData=strlen(lpszData)+1;
2892 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2893 if (xhkey!=hkey)
2894 RegCloseKey(xhkey);
2895 return ret;
2899 /******************************************************************************
2900 * RegSetValue16 [KERNEL.221] [SHELL.5]
2902 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2903 LPCSTR lpszData, DWORD cbData )
2905 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2906 debugstr_a(lpszData),cbData);
2907 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2912 * Key Enumeration
2914 * Callpath:
2915 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2916 * RegEnumKey32W -> RegEnumKeyEx32W
2920 /******************************************************************************
2921 * RegEnumKeyEx32W [ADVAPI32.139]
2923 * PARAMS
2924 * hkey [I] Handle to key to enumerate
2925 * iSubKey [I] Index of subkey to enumerate
2926 * lpszName [O] Buffer for subkey name
2927 * lpcchName [O] Size of subkey buffer
2928 * lpdwReserved [I] Reserved
2929 * lpszClass [O] Buffer for class string
2930 * lpcchClass [O] Size of class buffer
2931 * ft [O] Time key last written to
2933 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2934 LPDWORD lpcchName, LPDWORD lpdwReserved,
2935 LPWSTR lpszClass, LPDWORD lpcchClass,
2936 FILETIME *ft )
2938 LPKEYSTRUCT lpkey,lpxkey;
2940 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2941 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2943 lpkey = lookup_hkey( hkey );
2944 if (!lpkey)
2945 return ERROR_INVALID_HANDLE;
2947 if (!lpkey->nextsub)
2948 return ERROR_NO_MORE_ITEMS;
2949 lpxkey=lpkey->nextsub;
2951 /* Traverse the subkeys */
2952 while (iSubkey && lpxkey) {
2953 iSubkey--;
2954 lpxkey=lpxkey->next;
2957 if (iSubkey || !lpxkey)
2958 return ERROR_NO_MORE_ITEMS;
2959 if (lstrlenW(lpxkey->keyname)+1>*lpcchName)
2960 return ERROR_MORE_DATA;
2961 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
2963 if (*lpcchName)
2964 *lpcchName = lstrlenW(lpszName);
2966 if (lpszClass) {
2967 /* FIXME: what should we write into it? */
2968 *lpszClass = 0;
2969 *lpcchClass = 2;
2971 return ERROR_SUCCESS;
2975 /******************************************************************************
2976 * RegEnumKey32W [ADVAPI32.140]
2978 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2979 DWORD lpcchName )
2981 FILETIME ft;
2983 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2984 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2988 /******************************************************************************
2989 * RegEnumKeyEx32A [ADVAPI32.138]
2991 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2992 LPDWORD lpcchName, LPDWORD lpdwReserved,
2993 LPSTR lpszClass, LPDWORD lpcchClass,
2994 FILETIME *ft )
2996 DWORD ret,lpcchNameW,lpcchClassW;
2997 LPWSTR lpszNameW,lpszClassW;
3000 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3001 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3003 if (lpszName) {
3004 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3005 lpcchNameW = *lpcchName;
3006 } else {
3007 lpszNameW = NULL;
3008 lpcchNameW = 0;
3010 if (lpszClass) {
3011 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3012 lpcchClassW = *lpcchClass;
3013 } else {
3014 lpszClassW =0;
3015 lpcchClassW=0;
3017 ret=RegEnumKeyExW(
3018 hkey,
3019 iSubkey,
3020 lpszNameW,
3021 &lpcchNameW,
3022 lpdwReserved,
3023 lpszClassW,
3024 &lpcchClassW,
3027 if (ret==ERROR_SUCCESS) {
3028 lstrcpyWtoA(lpszName,lpszNameW);
3029 *lpcchName=strlen(lpszName);
3030 if (lpszClassW) {
3031 lstrcpyWtoA(lpszClass,lpszClassW);
3032 *lpcchClass=strlen(lpszClass);
3035 if (lpszNameW)
3036 free(lpszNameW);
3037 if (lpszClassW)
3038 free(lpszClassW);
3039 return ret;
3043 /******************************************************************************
3044 * RegEnumKey32A [ADVAPI32.137]
3046 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3047 DWORD lpcchName )
3049 FILETIME ft;
3051 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3052 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3053 NULL, &ft );
3057 /******************************************************************************
3058 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3060 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3061 DWORD lpcchName )
3063 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3064 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3069 * Enumerate Registry Values
3071 * Callpath:
3072 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3076 /******************************************************************************
3077 * RegEnumValue32W [ADVAPI32.142]
3079 * PARAMS
3080 * hkey [I] Handle to key to query
3081 * iValue [I] Index of value to query
3082 * lpszValue [O] Value string
3083 * lpcchValue [I/O] Size of value buffer (in wchars)
3084 * lpdReserved [I] Reserved
3085 * lpdwType [O] Type code
3086 * lpbData [O] Value data
3087 * lpcbData [I/O] Size of data buffer (in bytes)
3089 * Note: wide character functions that take and/or return "character counts"
3090 * use TCHAR (that is unsigned short or char) not byte counts.
3092 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3093 LPDWORD lpcchValue, LPDWORD lpdReserved,
3094 LPDWORD lpdwType, LPBYTE lpbData,
3095 LPDWORD lpcbData )
3097 LPKEYSTRUCT lpkey;
3098 LPKEYVALUE val;
3100 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3101 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3103 lpkey = lookup_hkey( hkey );
3105 if (!lpcbData && lpbData)
3106 return ERROR_INVALID_PARAMETER;
3108 if (!lpkey)
3109 return ERROR_INVALID_HANDLE;
3111 if (lpkey->nrofvalues <= iValue)
3112 return ERROR_NO_MORE_ITEMS;
3114 val = &(lpkey->values[iValue]);
3116 if (val->name) {
3117 if (lstrlenW(val->name)+1>*lpcchValue) {
3118 *lpcchValue = lstrlenW(val->name)+1;
3119 return ERROR_MORE_DATA;
3121 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3122 *lpcchValue=lstrlenW(val->name);
3123 } else {
3124 *lpszValue = 0;
3125 *lpcchValue = 0;
3128 /* Can be NULL if the type code is not required */
3129 if (lpdwType)
3130 *lpdwType = val->type;
3132 if (lpbData) {
3133 if (val->len>*lpcbData)
3134 return ERROR_MORE_DATA;
3135 memcpy(lpbData,val->data,val->len);
3136 *lpcbData = val->len;
3139 debug_print_value ( val->data, val );
3140 return ERROR_SUCCESS;
3144 /******************************************************************************
3145 * RegEnumValue32A [ADVAPI32.141]
3147 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3148 LPDWORD lpcchValue, LPDWORD lpdReserved,
3149 LPDWORD lpdwType, LPBYTE lpbData,
3150 LPDWORD lpcbData )
3152 LPWSTR lpszValueW;
3153 LPBYTE lpbDataW;
3154 DWORD ret,lpcbDataW;
3155 DWORD dwType;
3157 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3158 lpdReserved,lpdwType,lpbData,lpcbData);
3160 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3161 if (lpbData) {
3162 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3163 lpcbDataW = *lpcbData;
3164 } else
3165 lpbDataW = NULL;
3167 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3168 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3170 if (lpdwType)
3171 *lpdwType = dwType;
3173 if (ret==ERROR_SUCCESS) {
3174 lstrcpyWtoA(lpszValue,lpszValueW);
3175 if (lpbData) {
3176 if ((1<<dwType) & UNICONVMASK) {
3177 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3178 } else {
3179 if (lpcbDataW > *lpcbData)
3180 ret = ERROR_MORE_DATA;
3181 else
3182 memcpy(lpbData,lpbDataW,lpcbDataW);
3184 *lpcbData = lpcbDataW;
3187 if (lpbDataW) free(lpbDataW);
3188 if (lpszValueW) free(lpszValueW);
3189 return ret;
3193 /******************************************************************************
3194 * RegEnumValue16 [KERNEL.223]
3196 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3197 LPDWORD lpcchValue, LPDWORD lpdReserved,
3198 LPDWORD lpdwType, LPBYTE lpbData,
3199 LPDWORD lpcbData )
3201 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3202 lpdReserved,lpdwType,lpbData,lpcbData);
3203 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3204 lpdwType, lpbData, lpcbData );
3208 /******************************************************************************
3209 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3210 * Releases the handle of the specified key
3212 * PARAMS
3213 * hkey [I] Handle of key to close
3215 * RETURNS
3216 * Success: ERROR_SUCCESS
3217 * Failure: Error code
3219 DWORD WINAPI RegCloseKey( HKEY hkey )
3221 TRACE_(reg)("(%x)\n",hkey);
3223 /* The standard handles are allowed to succeed, even though they are not
3224 closed */
3225 if (is_standard_hkey(hkey))
3226 return ERROR_SUCCESS;
3228 return remove_handle(hkey);
3233 * Delete registry key
3235 * Callpath:
3236 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3240 /******************************************************************************
3241 * RegDeleteKey32W [ADVAPI32.134]
3243 * PARAMS
3244 * hkey [I] Handle to open key
3245 * lpszSubKey [I] Name of subkey to delete
3247 * RETURNS
3248 * Success: ERROR_SUCCESS
3249 * Failure: Error code
3251 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3253 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3254 LPWSTR *wps;
3255 int wpc,i;
3257 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3259 lpNextKey = lookup_hkey(hkey);
3260 if (!lpNextKey)
3261 return ERROR_INVALID_HANDLE;
3263 /* Subkey param cannot be NULL */
3264 if (!lpszSubKey || !*lpszSubKey)
3265 return ERROR_BADKEY;
3267 /* We need to know the previous key in the hier. */
3268 split_keypath(lpszSubKey,&wps,&wpc);
3269 i = 0;
3270 lpxkey = lpNextKey;
3271 while (i<wpc-1) {
3272 lpxkey=lpNextKey->nextsub;
3273 while (lpxkey) {
3274 TRACE_(reg)(" Scanning [%s]\n",
3275 debugstr_w(lpxkey->keyname));
3276 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3277 break;
3278 lpxkey=lpxkey->next;
3280 if (!lpxkey) {
3281 FREE_KEY_PATH;
3282 TRACE_(reg)(" Not found.\n");
3283 /* not found is success */
3284 return ERROR_SUCCESS;
3286 i++;
3287 lpNextKey = lpxkey;
3289 lpxkey = lpNextKey->nextsub;
3290 lplpPrevKey = &(lpNextKey->nextsub);
3291 while (lpxkey) {
3292 TRACE_(reg)(" Scanning [%s]\n",
3293 debugstr_w(lpxkey->keyname));
3294 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3295 break;
3296 lplpPrevKey = &(lpxkey->next);
3297 lpxkey = lpxkey->next;
3300 if (!lpxkey) {
3301 FREE_KEY_PATH;
3302 WARN_(reg)(" Not found.\n");
3303 return ERROR_FILE_NOT_FOUND;
3306 if (lpxkey->nextsub) {
3307 FREE_KEY_PATH;
3308 WARN_(reg)(" Not empty.\n");
3309 return ERROR_CANTWRITE;
3311 *lplpPrevKey = lpxkey->next;
3312 free(lpxkey->keyname);
3313 if (lpxkey->class)
3314 free(lpxkey->class);
3315 if (lpxkey->values)
3316 free(lpxkey->values);
3317 free(lpxkey);
3318 FREE_KEY_PATH;
3319 TRACE_(reg)(" Done.\n");
3320 return ERROR_SUCCESS;
3324 /******************************************************************************
3325 * RegDeleteKey32A [ADVAPI32.133]
3327 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3329 LPWSTR lpszSubKeyW;
3330 DWORD ret;
3332 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3333 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3334 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3335 if(lpszSubKeyW) free(lpszSubKeyW);
3336 return ret;
3340 /******************************************************************************
3341 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3343 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3345 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3346 return RegDeleteKeyA( hkey, lpszSubKey );
3351 * Delete registry value
3353 * Callpath:
3354 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3358 /******************************************************************************
3359 * RegDeleteValue32W [ADVAPI32.136]
3361 * PARAMS
3362 * hkey [I]
3363 * lpszValue [I]
3365 * RETURNS
3367 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3369 DWORD i;
3370 LPKEYSTRUCT lpkey;
3371 LPKEYVALUE val;
3373 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3375 lpkey = lookup_hkey( hkey );
3376 if (!lpkey)
3377 return ERROR_INVALID_HANDLE;
3379 if (lpszValue) {
3380 for (i=0;i<lpkey->nrofvalues;i++)
3381 if ( lpkey->values[i].name &&
3382 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3384 break;
3385 } else {
3386 for (i=0;i<lpkey->nrofvalues;i++)
3387 if (lpkey->values[i].name==NULL)
3388 break;
3391 if (i == lpkey->nrofvalues)
3392 return ERROR_FILE_NOT_FOUND;
3394 val = lpkey->values+i;
3395 if (val->name) free(val->name);
3396 if (val->data) free(val->data);
3397 memcpy(
3398 lpkey->values+i,
3399 lpkey->values+i+1,
3400 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3402 lpkey->values = (LPKEYVALUE)xrealloc(
3403 lpkey->values,
3404 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3406 lpkey->nrofvalues--;
3407 return ERROR_SUCCESS;
3411 /******************************************************************************
3412 * RegDeleteValue32A [ADVAPI32.135]
3414 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3416 LPWSTR lpszValueW;
3417 DWORD ret;
3419 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3420 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3421 ret = RegDeleteValueW( hkey, lpszValueW );
3422 if(lpszValueW) free(lpszValueW);
3423 return ret;
3427 /******************************************************************************
3428 * RegDeleteValue16 [KERNEL.222]
3430 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3432 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3433 return RegDeleteValueA( hkey, lpszValue );
3437 /******************************************************************************
3438 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3439 * Writes key to registry
3441 * PARAMS
3442 * hkey [I] Handle of key to write
3444 * RETURNS
3445 * Success: ERROR_SUCCESS
3446 * Failure: Error code
3448 DWORD WINAPI RegFlushKey( HKEY hkey )
3450 LPKEYSTRUCT lpkey;
3451 BOOL ret;
3453 TRACE_(reg)("(%x)\n", hkey);
3455 lpkey = lookup_hkey( hkey );
3456 if (!lpkey)
3457 return ERROR_BADKEY;
3459 ERR_(reg)("What is the correct filename?\n");
3461 ret = _savereg( lpkey, "foo.bar", TRUE);
3463 if( ret ) {
3464 return ERROR_SUCCESS;
3465 } else
3466 return ERROR_UNKNOWN; /* FIXME */
3470 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3473 /******************************************************************************
3474 * RegQueryInfoKey32W [ADVAPI32.153]
3476 * PARAMS
3477 * hkey [I] Handle to key to query
3478 * lpszClass [O] Buffer for class string
3479 * lpcchClass [O] Size of class string buffer
3480 * lpdwReserved [I] Reserved
3481 * lpcSubKeys [I] Buffer for number of subkeys
3482 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3483 * lpcchMaxClass [O] Buffer for longest class string length
3484 * lpcValues [O] Buffer for number of value entries
3485 * lpcchMaxValueName [O] Buffer for longest value name length
3486 * lpccbMaxValueData [O] Buffer for longest value data length
3487 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3488 * ft
3489 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3490 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3491 * lpcchClass is NULL
3492 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3493 * (it's hard to test validity, so test !NULL instead)
3495 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3496 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3497 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3498 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3499 LPDWORD lpcchMaxValueName,
3500 LPDWORD lpccbMaxValueData,
3501 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3503 LPKEYSTRUCT lpkey,lpxkey;
3504 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3505 int i;
3507 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3508 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3509 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3510 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3512 lpkey = lookup_hkey(hkey);
3513 if (!lpkey)
3514 return ERROR_INVALID_HANDLE;
3515 if (lpszClass) {
3516 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3517 return ERROR_INVALID_PARAMETER;
3519 /* either lpcchClass is valid or this is win95 and lpcchClass
3520 could be invalid */
3521 if (lpkey->class) {
3522 DWORD classLen = lstrlenW(lpkey->class);
3524 if (lpcchClass && classLen+1>*lpcchClass) {
3525 *lpcchClass=classLen+1;
3526 return ERROR_MORE_DATA;
3528 if (lpcchClass)
3529 *lpcchClass=classLen;
3530 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3531 } else {
3532 *lpszClass = 0;
3533 if (lpcchClass)
3534 *lpcchClass = 0;
3536 } else {
3537 if (lpcchClass)
3538 *lpcchClass = lstrlenW(lpkey->class);
3540 lpxkey=lpkey->nextsub;
3541 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3542 while (lpxkey) {
3543 nrofkeys++;
3544 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3545 maxsubkey=lstrlenW(lpxkey->keyname);
3546 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3547 maxclass=lstrlenW(lpxkey->class);
3548 lpxkey=lpxkey->next;
3550 for (i=0;i<lpkey->nrofvalues;i++) {
3551 LPKEYVALUE val=lpkey->values+i;
3553 if (val->name && lstrlenW(val->name)>maxvname)
3554 maxvname=lstrlenW(val->name);
3555 if (val->len>maxvdata)
3556 maxvdata=val->len;
3558 if (!maxclass) maxclass = 1;
3559 if (!maxvname) maxvname = 1;
3560 if (lpcValues)
3561 *lpcValues = lpkey->nrofvalues;
3562 if (lpcSubKeys)
3563 *lpcSubKeys = nrofkeys;
3564 if (lpcchMaxSubkey)
3565 *lpcchMaxSubkey = maxsubkey;
3566 if (lpcchMaxClass)
3567 *lpcchMaxClass = maxclass;
3568 if (lpcchMaxValueName)
3569 *lpcchMaxValueName= maxvname;
3570 if (lpccbMaxValueData)
3571 *lpccbMaxValueData= maxvdata;
3572 return ERROR_SUCCESS;
3576 /******************************************************************************
3577 * RegQueryInfoKey32A [ADVAPI32.152]
3579 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3580 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3581 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3582 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3583 LPDWORD lpccbMaxValueData,
3584 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3586 LPWSTR lpszClassW = NULL;
3587 DWORD ret;
3589 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3590 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3591 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3592 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3594 if (lpszClass) {
3595 if (lpcchClass) {
3596 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3597 } else if (VERSION_GetVersion() == WIN95) {
3598 /* win95 allows lpcchClass to be null */
3599 /* we don't know how big lpszClass is, would
3600 MAX_PATHNAME_LEN be the correct default? */
3601 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3604 } else
3605 lpszClassW = NULL;
3606 ret=RegQueryInfoKeyW(
3607 hkey,
3608 lpszClassW,
3609 lpcchClass,
3610 lpdwReserved,
3611 lpcSubKeys,
3612 lpcchMaxSubkey,
3613 lpcchMaxClass,
3614 lpcValues,
3615 lpcchMaxValueName,
3616 lpccbMaxValueData,
3617 lpcbSecurityDescriptor,
3620 if (ret==ERROR_SUCCESS && lpszClass)
3621 lstrcpyWtoA(lpszClass,lpszClassW);
3622 if (lpszClassW)
3623 free(lpszClassW);
3624 return ret;
3628 /******************************************************************************
3629 * RegConnectRegistry32W [ADVAPI32.128]
3631 * PARAMS
3632 * lpMachineName [I] Address of name of remote computer
3633 * hHey [I] Predefined registry handle
3634 * phkResult [I] Address of buffer for remote registry handle
3636 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3637 LPHKEY phkResult )
3639 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3641 if (!lpMachineName || !*lpMachineName) {
3642 /* Use the local machine name */
3643 return RegOpenKey16( hKey, "", phkResult );
3646 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3647 return ERROR_BAD_NETPATH;
3651 /******************************************************************************
3652 * RegConnectRegistry32A [ADVAPI32.127]
3654 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3656 DWORD ret;
3657 LPWSTR machineW = strdupA2W(machine);
3658 ret = RegConnectRegistryW( machineW, hkey, reskey );
3659 free(machineW);
3660 return ret;
3664 /******************************************************************************
3665 * RegGetKeySecurity [ADVAPI32.144]
3666 * Retrieves a copy of security descriptor protecting the registry key
3668 * PARAMS
3669 * hkey [I] Open handle of key to set
3670 * SecurityInformation [I] Descriptor contents
3671 * pSecurityDescriptor [O] Address of descriptor for key
3672 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3674 * RETURNS
3675 * Success: ERROR_SUCCESS
3676 * Failure: Error code
3678 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3679 SECURITY_INFORMATION SecurityInformation,
3680 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3681 LPDWORD lpcbSecurityDescriptor )
3683 LPKEYSTRUCT lpkey;
3685 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3686 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3688 lpkey = lookup_hkey( hkey );
3689 if (!lpkey)
3690 return ERROR_INVALID_HANDLE;
3692 /* FIXME: Check for valid SecurityInformation values */
3694 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3695 return ERROR_INSUFFICIENT_BUFFER;
3697 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3698 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3700 return ERROR_SUCCESS;
3704 /******************************************************************************
3705 * RegLoadKey32W [ADVAPI32.???]
3707 * PARAMS
3708 * hkey [I] Handle of open key
3709 * lpszSubKey [I] Address of name of subkey
3710 * lpszFile [I] Address of filename for registry information
3712 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3714 LPKEYSTRUCT lpkey;
3715 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3717 /* Do this check before the hkey check */
3718 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3719 return ERROR_INVALID_PARAMETER;
3721 lpkey = lookup_hkey( hkey );
3722 if (!lpkey)
3723 return ERROR_INVALID_HANDLE;
3725 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3726 debugstr_w(lpszFile));
3728 return ERROR_SUCCESS;
3732 /******************************************************************************
3733 * RegLoadKey32A [ADVAPI32.???]
3735 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3737 LONG ret;
3738 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3739 LPWSTR lpszFileW = strdupA2W(lpszFile);
3740 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3741 if(lpszFileW) free(lpszFileW);
3742 if(lpszSubKeyW) free(lpszSubKeyW);
3743 return ret;
3747 /******************************************************************************
3748 * RegNotifyChangeKeyValue [ADVAPI32.???]
3750 * PARAMS
3751 * hkey [I] Handle of key to watch
3752 * fWatchSubTree [I] Flag for subkey notification
3753 * fdwNotifyFilter [I] Changes to be reported
3754 * hEvent [I] Handle of signaled event
3755 * fAsync [I] Flag for asynchronous reporting
3757 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3758 DWORD fdwNotifyFilter, HANDLE hEvent,
3759 BOOL fAsync )
3761 LPKEYSTRUCT lpkey;
3762 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3763 hEvent,fAsync);
3765 lpkey = lookup_hkey( hkey );
3766 if (!lpkey)
3767 return ERROR_INVALID_HANDLE;
3769 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3770 hEvent,fAsync);
3772 return ERROR_SUCCESS;
3776 /******************************************************************************
3777 * RegUnLoadKey32W [ADVAPI32.173]
3779 * PARAMS
3780 * hkey [I] Handle of open key
3781 * lpSubKey [I] Address of name of subkey to unload
3783 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3785 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3786 return ERROR_SUCCESS;
3790 /******************************************************************************
3791 * RegUnLoadKey32A [ADVAPI32.172]
3793 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3795 LONG ret;
3796 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3797 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3798 if(lpSubKeyW) free(lpSubKeyW);
3799 return ret;
3803 /******************************************************************************
3804 * RegSetKeySecurity [ADVAPI32.167]
3806 * PARAMS
3807 * hkey [I] Open handle of key to set
3808 * SecurityInfo [I] Descriptor contents
3809 * pSecurityDesc [I] Address of descriptor for key
3811 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3812 PSECURITY_DESCRIPTOR pSecurityDesc )
3814 LPKEYSTRUCT lpkey;
3816 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3818 /* It seems to perform this check before the hkey check */
3819 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3820 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3821 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3822 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3823 /* Param OK */
3824 } else
3825 return ERROR_INVALID_PARAMETER;
3827 if (!pSecurityDesc)
3828 return ERROR_INVALID_PARAMETER;
3830 lpkey = lookup_hkey( hkey );
3831 if (!lpkey)
3832 return ERROR_INVALID_HANDLE;
3834 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3836 return ERROR_SUCCESS;
3840 /******************************************************************************
3841 * RegSaveKey32W [ADVAPI32.166]
3843 * PARAMS
3844 * hkey [I] Handle of key where save begins
3845 * lpFile [I] Address of filename to save to
3846 * sa [I] Address of security structure
3848 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3849 LPSECURITY_ATTRIBUTES sa )
3851 LPKEYSTRUCT lpkey;
3853 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3855 /* It appears to do this check before the hkey check */
3856 if (!lpFile || !*lpFile)
3857 return ERROR_INVALID_PARAMETER;
3859 lpkey = lookup_hkey( hkey );
3860 if (!lpkey)
3861 return ERROR_INVALID_HANDLE;
3863 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3865 return ERROR_SUCCESS;
3869 /******************************************************************************
3870 * RegSaveKey32A [ADVAPI32.165]
3872 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3873 LPSECURITY_ATTRIBUTES sa )
3875 LONG ret;
3876 LPWSTR lpFileW = strdupA2W(lpFile);
3877 ret = RegSaveKeyW( hkey, lpFileW, sa );
3878 free(lpFileW);
3879 return ret;
3883 /******************************************************************************
3884 * RegRestoreKey32W [ADVAPI32.164]
3886 * PARAMS
3887 * hkey [I] Handle of key where restore begins
3888 * lpFile [I] Address of filename containing saved tree
3889 * dwFlags [I] Optional flags
3891 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3893 LPKEYSTRUCT lpkey;
3895 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3897 /* It seems to do this check before the hkey check */
3898 if (!lpFile || !*lpFile)
3899 return ERROR_INVALID_PARAMETER;
3901 lpkey = lookup_hkey( hkey );
3902 if (!lpkey)
3903 return ERROR_INVALID_HANDLE;
3905 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3907 /* Check for file existence */
3909 return ERROR_SUCCESS;
3913 /******************************************************************************
3914 * RegRestoreKey32A [ADVAPI32.163]
3916 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3918 LONG ret;
3919 LPWSTR lpFileW = strdupA2W(lpFile);
3920 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3921 if(lpFileW) free(lpFileW);
3922 return ret;
3926 /******************************************************************************
3927 * RegReplaceKey32W [ADVAPI32.162]
3929 * PARAMS
3930 * hkey [I] Handle of open key
3931 * lpSubKey [I] Address of name of subkey
3932 * lpNewFile [I] Address of filename for file with new data
3933 * lpOldFile [I] Address of filename for backup file
3935 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3936 LPCWSTR lpOldFile )
3938 LPKEYSTRUCT lpkey;
3940 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3941 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3943 lpkey = lookup_hkey( hkey );
3944 if (!lpkey)
3945 return ERROR_INVALID_HANDLE;
3947 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3948 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3950 return ERROR_SUCCESS;
3954 /******************************************************************************
3955 * RegReplaceKey32A [ADVAPI32.161]
3957 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3958 LPCSTR lpOldFile )
3960 LONG ret;
3961 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3962 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3963 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3964 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3965 free(lpOldFileW);
3966 free(lpNewFileW);
3967 free(lpSubKeyW);
3968 return ret;