WM_SYSCOMMAND message (for SC_CLOSE) should be posted not sent.
[wine/wine-kai.git] / misc / registry.c
blobbdfdcb64472f0bfcbb026be4aaf0e030822b6662
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 *lpcbData = lpkey->values[i].len;
2509 ret = ERROR_MORE_DATA;
2513 if (lpcbData) /* size required ?*/
2514 { *lpcbData = lpkey->values[i].len;
2517 debug_print_value ( lpbData, &lpkey->values[i]);
2519 TRACE_(reg)(" (ret=%lx, type=%lx, len=%ld)\n", ret, lpdwType?*lpdwType:0,lpcbData?*lpcbData:0);
2521 return ret;
2525 /******************************************************************************
2526 * RegQueryValue32W [ADVAPI32.159]
2528 DWORD WINAPI RegQueryValueW( HKEY hkey, LPCWSTR lpszSubKey, LPWSTR lpszData,
2529 LPLONG lpcbData )
2531 HKEY xhkey;
2532 DWORD ret,lpdwType;
2534 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_w(lpszSubKey),lpszData,
2535 lpcbData?*lpcbData:0);
2537 /* Only open subkey, if we really do descend */
2538 if (lpszSubKey && *lpszSubKey) {
2539 ret = RegOpenKeyW( hkey, lpszSubKey, &xhkey );
2540 if (ret != ERROR_SUCCESS) {
2541 WARN_(reg)("Could not open %s\n", debugstr_w(lpszSubKey));
2542 return ret;
2544 } else
2545 xhkey = hkey;
2547 lpdwType = REG_SZ;
2548 ret = RegQueryValueExW( xhkey, NULL, NULL, &lpdwType, (LPBYTE)lpszData,
2549 lpcbData );
2550 if (xhkey != hkey)
2551 RegCloseKey(xhkey);
2552 return ret;
2556 /******************************************************************************
2557 * RegQueryValueEx32A [ADVAPI32.157]
2559 * NOTES:
2560 * the documantation is wrong: if the buffer is to small it remains untouched
2562 * FIXME: check returnvalue (len) for an empty key
2564 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR lpszValueName,
2565 LPDWORD lpdwReserved, LPDWORD lpdwType,
2566 LPBYTE lpbData, LPDWORD lpcbData )
2568 LPWSTR lpszValueNameW;
2569 LPBYTE mybuf = NULL;
2570 DWORD ret, mytype, mylen = 0;
2572 TRACE_(reg)("(%x,%s,%p,%p,%p,%p=%ld)\n", hkey,debugstr_a(lpszValueName),
2573 lpdwReserved,lpdwType,lpbData,lpcbData,lpcbData?*lpcbData:0);
2575 if (!lpcbData && lpbData) /* buffer without size is illegal */
2576 { return ERROR_INVALID_PARAMETER;
2579 lpszValueNameW = lpszValueName ? strdupA2W(lpszValueName) : NULL;
2581 /* get just the type first */
2582 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, &mytype, NULL, NULL );
2584 if ( ret != ERROR_SUCCESS ) /* failed ?? */
2585 { if(lpszValueNameW) free(lpszValueNameW);
2586 return ret;
2589 if (lpcbData) /* at least length requested? */
2590 { if (UNICONVMASK & (1<<(mytype))) /* string requested? */
2591 { if (lpbData ) /* value requested? */
2592 { mylen = 2*( *lpcbData );
2593 mybuf = (LPBYTE)xmalloc( mylen );
2596 ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, mybuf, &mylen );
2598 if (ret == ERROR_SUCCESS )
2599 { if ( lpbData )
2600 { lmemcpynWtoA(lpbData, (LPWSTR)mybuf, mylen/2);
2604 *lpcbData = mylen/2; /* size is in byte! */
2606 else /* no strings, call it straight */
2607 { ret = RegQueryValueExW( hkey, lpszValueNameW, lpdwReserved, lpdwType, lpbData, lpcbData );
2611 if (lpdwType) /* type when requested */
2612 { *lpdwType = mytype;
2615 TRACE_(reg)(" (ret=%lx,type=%lx, len=%ld)\n", ret,mytype,lpcbData?*lpcbData:0);
2617 if(mybuf) free(mybuf);
2618 if(lpszValueNameW) free(lpszValueNameW);
2619 return ret;
2623 /******************************************************************************
2624 * RegQueryValueEx16 [KERNEL.225]
2626 DWORD WINAPI RegQueryValueEx16( HKEY hkey, LPSTR lpszValueName,
2627 LPDWORD lpdwReserved, LPDWORD lpdwType,
2628 LPBYTE lpbData, LPDWORD lpcbData )
2630 TRACE_(reg)("(%x,%s,%p,%p,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2631 lpdwReserved,lpdwType,lpbData,lpcbData?*lpcbData:0);
2632 return RegQueryValueExA( hkey, lpszValueName, lpdwReserved, lpdwType,
2633 lpbData, lpcbData );
2637 /******************************************************************************
2638 * RegQueryValue32A [ADVAPI32.156]
2640 DWORD WINAPI RegQueryValueA( HKEY hkey, LPCSTR lpszSubKey, LPSTR lpszData,
2641 LPLONG lpcbData )
2643 HKEY xhkey;
2644 DWORD ret, dwType;
2646 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2647 lpcbData?*lpcbData:0);
2649 if (lpszSubKey && *lpszSubKey) {
2650 ret = RegOpenKey16( hkey, lpszSubKey, &xhkey );
2651 if( ret != ERROR_SUCCESS )
2652 return ret;
2653 } else
2654 xhkey = hkey;
2656 dwType = REG_SZ;
2657 ret = RegQueryValueExA( xhkey, NULL,NULL, &dwType, (LPBYTE)lpszData,
2658 lpcbData );
2659 if( xhkey != hkey )
2660 RegCloseKey( xhkey );
2661 return ret;
2665 /******************************************************************************
2666 * RegQueryValue16 [SHELL.6] [KERNEL.224]
2668 * NOTES
2669 * Is this HACK still applicable?
2671 * HACK
2672 * The 16bit RegQueryValue doesn't handle selectorblocks anyway, so we just
2673 * mask out the high 16 bit. This (not so much incidently) hopefully fixes
2674 * Aldus FH4)
2676 DWORD WINAPI RegQueryValue16( HKEY hkey, LPSTR lpszSubKey, LPSTR lpszData,
2677 LPDWORD lpcbData )
2679 TRACE_(reg)("(%x,%s,%p,%ld)\n",hkey,debugstr_a(lpszSubKey),lpszData,
2680 lpcbData?*lpcbData:0);
2682 if (lpcbData)
2683 *lpcbData &= 0xFFFF;
2684 return RegQueryValueA(hkey,lpszSubKey,lpszData,lpcbData);
2689 * Setting values of Registry keys
2691 * Callpath:
2692 * RegSetValue16 -> RegSetValue32A -> RegSetValueEx32A \
2693 * RegSetValue32W -> RegSetValueEx32W
2697 /******************************************************************************
2698 * RegSetValueEx32W [ADVAPI32.170]
2699 * Sets the data and type of a value under a register key
2701 * PARAMS
2702 * hkey [I] Handle of key to set value for
2703 * lpszValueName [I] Name of value to set
2704 * dwReserved [I] Reserved - must be zero
2705 * dwType [I] Flag for value type
2706 * lpbData [I] Address of value data
2707 * cbData [I] Size of value data
2709 * RETURNS
2710 * Success: ERROR_SUCCESS
2711 * Failure: Error code
2713 * NOTES
2714 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2716 DWORD WINAPI RegSetValueExW( HKEY hkey, LPCWSTR lpszValueName,
2717 DWORD dwReserved, DWORD dwType,
2718 CONST BYTE *lpbData, DWORD cbData)
2720 LPKEYSTRUCT lpkey;
2721 int i;
2723 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(lpszValueName),
2724 dwReserved, dwType, lpbData, cbData);
2726 lpkey = lookup_hkey( hkey );
2728 if (!lpkey)
2729 return ERROR_INVALID_HANDLE;
2731 lpkey->flags |= REG_OPTION_TAINTED;
2733 if (lpszValueName==NULL) {
2734 /* Sets type and name for key's unnamed or default value */
2735 for (i=0;i<lpkey->nrofvalues;i++)
2736 if (lpkey->values[i].name==NULL)
2737 break;
2738 } else {
2739 for (i=0;i<lpkey->nrofvalues;i++)
2740 if ( lpkey->values[i].name &&
2741 !lstrcmpiW(lpszValueName,lpkey->values[i].name)
2743 break;
2745 if (i==lpkey->nrofvalues) {
2746 lpkey->values = (LPKEYVALUE)xrealloc(
2747 lpkey->values,
2748 (lpkey->nrofvalues+1)*sizeof(KEYVALUE)
2750 lpkey->nrofvalues++;
2751 memset(lpkey->values+i,'\0',sizeof(KEYVALUE));
2753 if (lpkey->values[i].name==NULL) {
2754 if (lpszValueName)
2755 lpkey->values[i].name = strdupW(lpszValueName);
2756 else
2757 lpkey->values[i].name = NULL;
2760 if (dwType == REG_SZ)
2761 cbData = 2 * (lstrlenW ((LPCWSTR)lpbData) + 1);
2763 lpkey->values[i].len = cbData;
2764 lpkey->values[i].type = dwType;
2765 if (lpkey->values[i].data !=NULL)
2766 free(lpkey->values[i].data);
2767 lpkey->values[i].data = (LPBYTE)xmalloc(cbData);
2768 lpkey->values[i].lastmodified = time(NULL);
2769 memcpy(lpkey->values[i].data,lpbData,cbData);
2770 return ERROR_SUCCESS;
2774 /******************************************************************************
2775 * RegSetValueEx32A [ADVAPI32.169]
2777 * NOTES
2778 * win95 does not care about cbData for REG_SZ and finds out the len by itself (js)
2780 DWORD WINAPI RegSetValueExA( HKEY hkey, LPCSTR lpszValueName,
2781 DWORD dwReserved, DWORD dwType,
2782 CONST BYTE *lpbData, DWORD cbData )
2784 LPBYTE buf;
2785 LPWSTR lpszValueNameW;
2786 DWORD ret;
2788 if (!lpbData)
2789 return (ERROR_INVALID_PARAMETER);
2791 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2792 dwReserved,dwType,lpbData,cbData);
2794 if ((1<<dwType) & UNICONVMASK)
2795 { if (dwType == REG_SZ)
2796 cbData = strlen ((LPCSTR)lpbData)+1;
2798 buf = (LPBYTE)xmalloc( cbData *2 );
2799 lmemcpynAtoW ((LPVOID)buf, lpbData, cbData );
2800 cbData=2*cbData;
2802 else
2803 buf=(LPBYTE)lpbData;
2805 if (lpszValueName)
2806 lpszValueNameW = strdupA2W(lpszValueName);
2807 else
2808 lpszValueNameW = NULL;
2810 ret=RegSetValueExW(hkey,lpszValueNameW,dwReserved,dwType,buf,cbData);
2812 if (lpszValueNameW)
2813 free(lpszValueNameW);
2815 if (buf!=lpbData)
2816 free(buf);
2818 return ret;
2822 /******************************************************************************
2823 * RegSetValueEx16 [KERNEL.226]
2825 DWORD WINAPI RegSetValueEx16( HKEY hkey, LPSTR lpszValueName, DWORD dwReserved,
2826 DWORD dwType, LPBYTE lpbData, DWORD cbData )
2828 TRACE_(reg)("(%x,%s,%ld,%ld,%p,%ld)\n",hkey,debugstr_a(lpszValueName),
2829 dwReserved,dwType,lpbData,cbData);
2830 return RegSetValueExA( hkey, lpszValueName, dwReserved, dwType, lpbData,
2831 cbData );
2835 /******************************************************************************
2836 * RegSetValue32W [ADVAPI32.171]
2838 DWORD WINAPI RegSetValueW( HKEY hkey, LPCWSTR lpszSubKey, DWORD dwType,
2839 LPCWSTR lpszData, DWORD cbData )
2841 HKEY xhkey;
2842 DWORD ret;
2844 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",
2845 hkey,debugstr_w(lpszSubKey),dwType,debugstr_w(lpszData),cbData
2847 if (lpszSubKey && *lpszSubKey) {
2848 ret=RegCreateKeyW(hkey,lpszSubKey,&xhkey);
2849 if (ret!=ERROR_SUCCESS)
2850 return ret;
2851 } else
2852 xhkey=hkey;
2853 if (dwType!=REG_SZ) {
2854 TRACE_(reg)("dwType=%ld - Changing to REG_SZ\n",dwType);
2855 dwType=REG_SZ;
2857 if (cbData!=2*lstrlenW(lpszData)+2) {
2858 TRACE_(reg)("Len=%ld != strlen(%s)+1=%d!\n",
2859 cbData,debugstr_w(lpszData),2*lstrlenW(lpszData)+2
2861 cbData=2*lstrlenW(lpszData)+2;
2863 ret=RegSetValueExW(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2864 if (hkey!=xhkey)
2865 RegCloseKey(xhkey);
2866 return ret;
2870 /******************************************************************************
2871 * RegSetValue32A [ADVAPI32.168]
2874 DWORD WINAPI RegSetValueA( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2875 LPCSTR lpszData, DWORD cbData )
2877 DWORD ret;
2878 HKEY xhkey;
2880 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,lpszSubKey,dwType,lpszData,cbData);
2881 if (lpszSubKey && *lpszSubKey) {
2882 ret=RegCreateKey16(hkey,lpszSubKey,&xhkey);
2883 if (ret!=ERROR_SUCCESS)
2884 return ret;
2885 } else
2886 xhkey=hkey;
2888 if (dwType!=REG_SZ) {
2889 TRACE_(reg)("dwType=%ld!\n",dwType);
2890 dwType=REG_SZ;
2892 if (cbData!=strlen(lpszData)+1)
2893 cbData=strlen(lpszData)+1;
2894 ret=RegSetValueExA(xhkey,NULL,0,dwType,(LPBYTE)lpszData,cbData);
2895 if (xhkey!=hkey)
2896 RegCloseKey(xhkey);
2897 return ret;
2901 /******************************************************************************
2902 * RegSetValue16 [KERNEL.221] [SHELL.5]
2904 DWORD WINAPI RegSetValue16( HKEY hkey, LPCSTR lpszSubKey, DWORD dwType,
2905 LPCSTR lpszData, DWORD cbData )
2907 TRACE_(reg)("(%x,%s,%ld,%s,%ld)\n",hkey,debugstr_a(lpszSubKey),dwType,
2908 debugstr_a(lpszData),cbData);
2909 return RegSetValueA(hkey,lpszSubKey,dwType,lpszData,cbData);
2914 * Key Enumeration
2916 * Callpath:
2917 * RegEnumKey16 -> RegEnumKey32A -> RegEnumKeyEx32A \
2918 * RegEnumKey32W -> RegEnumKeyEx32W
2922 /******************************************************************************
2923 * RegEnumKeyEx32W [ADVAPI32.139]
2925 * PARAMS
2926 * hkey [I] Handle to key to enumerate
2927 * iSubKey [I] Index of subkey to enumerate
2928 * lpszName [O] Buffer for subkey name
2929 * lpcchName [O] Size of subkey buffer
2930 * lpdwReserved [I] Reserved
2931 * lpszClass [O] Buffer for class string
2932 * lpcchClass [O] Size of class buffer
2933 * ft [O] Time key last written to
2935 DWORD WINAPI RegEnumKeyExW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2936 LPDWORD lpcchName, LPDWORD lpdwReserved,
2937 LPWSTR lpszClass, LPDWORD lpcchClass,
2938 FILETIME *ft )
2940 LPKEYSTRUCT lpkey,lpxkey;
2942 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",hkey,iSubkey,lpszName,
2943 *lpcchName,lpdwReserved,lpszClass,lpcchClass,ft);
2945 lpkey = lookup_hkey( hkey );
2946 if (!lpkey)
2947 return ERROR_INVALID_HANDLE;
2949 if (!lpkey->nextsub)
2950 return ERROR_NO_MORE_ITEMS;
2951 lpxkey=lpkey->nextsub;
2953 /* Traverse the subkeys */
2954 while (iSubkey && lpxkey) {
2955 iSubkey--;
2956 lpxkey=lpxkey->next;
2959 if (iSubkey || !lpxkey)
2960 return ERROR_NO_MORE_ITEMS;
2961 if (lstrlenW(lpxkey->keyname)+1>*lpcchName) {
2962 *lpcchName = lstrlenW(lpxkey->keyname)+1;
2963 return ERROR_MORE_DATA;
2965 memcpy(lpszName,lpxkey->keyname,lstrlenW(lpxkey->keyname)*2+2);
2967 if (*lpcchName)
2968 *lpcchName = lstrlenW(lpszName);
2970 if (lpszClass) {
2971 /* FIXME: what should we write into it? */
2972 *lpszClass = 0;
2973 *lpcchClass = 2;
2975 return ERROR_SUCCESS;
2979 /******************************************************************************
2980 * RegEnumKey32W [ADVAPI32.140]
2982 DWORD WINAPI RegEnumKeyW( HKEY hkey, DWORD iSubkey, LPWSTR lpszName,
2983 DWORD lpcchName )
2985 FILETIME ft;
2987 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
2988 return RegEnumKeyExW(hkey,iSubkey,lpszName,&lpcchName,NULL,NULL,NULL,&ft);
2992 /******************************************************************************
2993 * RegEnumKeyEx32A [ADVAPI32.138]
2995 DWORD WINAPI RegEnumKeyExA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
2996 LPDWORD lpcchName, LPDWORD lpdwReserved,
2997 LPSTR lpszClass, LPDWORD lpcchClass,
2998 FILETIME *ft )
3000 DWORD ret,lpcchNameW,lpcchClassW;
3001 LPWSTR lpszNameW,lpszClassW;
3004 TRACE_(reg)("(%x,%ld,%p,%ld,%p,%p,%p,%p)\n",
3005 hkey,iSubkey,lpszName,*lpcchName,lpdwReserved,lpszClass,lpcchClass,ft
3007 if (lpszName) {
3008 lpszNameW = (LPWSTR)xmalloc(*lpcchName*2);
3009 lpcchNameW = *lpcchName;
3010 } else {
3011 lpszNameW = NULL;
3012 lpcchNameW = 0;
3014 if (lpszClass) {
3015 lpszClassW = (LPWSTR)xmalloc(*lpcchClass*2);
3016 lpcchClassW = *lpcchClass;
3017 } else {
3018 lpszClassW =0;
3019 lpcchClassW=0;
3021 ret=RegEnumKeyExW(
3022 hkey,
3023 iSubkey,
3024 lpszNameW,
3025 &lpcchNameW,
3026 lpdwReserved,
3027 lpszClassW,
3028 &lpcchClassW,
3031 if (ret==ERROR_SUCCESS) {
3032 lstrcpyWtoA(lpszName,lpszNameW);
3033 *lpcchName=strlen(lpszName);
3034 if (lpszClassW) {
3035 lstrcpyWtoA(lpszClass,lpszClassW);
3036 *lpcchClass=strlen(lpszClass);
3039 if (lpszNameW)
3040 free(lpszNameW);
3041 if (lpszClassW)
3042 free(lpszClassW);
3043 return ret;
3047 /******************************************************************************
3048 * RegEnumKey32A [ADVAPI32.137]
3050 DWORD WINAPI RegEnumKeyA( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3051 DWORD lpcchName )
3053 FILETIME ft;
3055 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3056 return RegEnumKeyExA( hkey, iSubkey, lpszName, &lpcchName, NULL, NULL,
3057 NULL, &ft );
3061 /******************************************************************************
3062 * RegEnumKey16 [SHELL.7] [KERNEL.216]
3064 DWORD WINAPI RegEnumKey16( HKEY hkey, DWORD iSubkey, LPSTR lpszName,
3065 DWORD lpcchName )
3067 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,iSubkey,lpszName,lpcchName);
3068 return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName);
3073 * Enumerate Registry Values
3075 * Callpath:
3076 * RegEnumValue16 -> RegEnumValue32A -> RegEnumValue32W
3080 /******************************************************************************
3081 * RegEnumValue32W [ADVAPI32.142]
3083 * PARAMS
3084 * hkey [I] Handle to key to query
3085 * iValue [I] Index of value to query
3086 * lpszValue [O] Value string
3087 * lpcchValue [I/O] Size of value buffer (in wchars)
3088 * lpdReserved [I] Reserved
3089 * lpdwType [O] Type code
3090 * lpbData [O] Value data
3091 * lpcbData [I/O] Size of data buffer (in bytes)
3093 * Note: wide character functions that take and/or return "character counts"
3094 * use TCHAR (that is unsigned short or char) not byte counts.
3096 DWORD WINAPI RegEnumValueW( HKEY hkey, DWORD iValue, LPWSTR lpszValue,
3097 LPDWORD lpcchValue, LPDWORD lpdReserved,
3098 LPDWORD lpdwType, LPBYTE lpbData,
3099 LPDWORD lpcbData )
3101 LPKEYSTRUCT lpkey;
3102 LPKEYVALUE val;
3104 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,debugstr_w(lpszValue),
3105 lpcchValue,lpdReserved,lpdwType,lpbData,lpcbData);
3107 lpkey = lookup_hkey( hkey );
3109 if (!lpcbData && lpbData)
3110 return ERROR_INVALID_PARAMETER;
3112 if (!lpkey)
3113 return ERROR_INVALID_HANDLE;
3115 if (lpkey->nrofvalues <= iValue)
3116 return ERROR_NO_MORE_ITEMS;
3118 val = &(lpkey->values[iValue]);
3120 if (val->name) {
3121 if (lstrlenW(val->name)+1>*lpcchValue) {
3122 *lpcchValue = lstrlenW(val->name)+1;
3123 return ERROR_MORE_DATA;
3125 memcpy(lpszValue,val->name,2 * (lstrlenW(val->name)+1) );
3126 *lpcchValue=lstrlenW(val->name);
3127 } else {
3128 *lpszValue = 0;
3129 *lpcchValue = 0;
3132 /* Can be NULL if the type code is not required */
3133 if (lpdwType)
3134 *lpdwType = val->type;
3136 if (lpbData) {
3137 if (val->len>*lpcbData) {
3138 *lpcbData = val->len;
3139 return ERROR_MORE_DATA;
3141 memcpy(lpbData,val->data,val->len);
3142 *lpcbData = val->len;
3145 debug_print_value ( val->data, val );
3146 return ERROR_SUCCESS;
3150 /******************************************************************************
3151 * RegEnumValue32A [ADVAPI32.141]
3153 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3154 LPDWORD lpcchValue, LPDWORD lpdReserved,
3155 LPDWORD lpdwType, LPBYTE lpbData,
3156 LPDWORD lpcbData )
3158 LPWSTR lpszValueW;
3159 LPBYTE lpbDataW;
3160 DWORD ret,lpcbDataW;
3161 DWORD dwType;
3163 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3164 lpdReserved,lpdwType,lpbData,lpcbData);
3166 lpszValueW = (LPWSTR)xmalloc(*lpcchValue*2);
3167 if (lpbData) {
3168 lpbDataW = (LPBYTE)xmalloc(*lpcbData*2);
3169 lpcbDataW = *lpcbData;
3170 } else
3171 lpbDataW = NULL;
3173 ret = RegEnumValueW( hkey, iValue, lpszValueW, lpcchValue,
3174 lpdReserved, &dwType, lpbDataW, &lpcbDataW );
3176 if (lpdwType)
3177 *lpdwType = dwType;
3179 if (ret==ERROR_SUCCESS) {
3180 lstrcpyWtoA(lpszValue,lpszValueW);
3181 if (lpbData) {
3182 if ((1<<dwType) & UNICONVMASK) {
3183 lstrcpyWtoA(lpbData,(LPWSTR)lpbDataW);
3184 } else {
3185 if (lpcbDataW > *lpcbData) {
3186 *lpcbData = lpcbDataW;
3187 ret = ERROR_MORE_DATA;
3188 } else
3189 memcpy(lpbData,lpbDataW,lpcbDataW);
3191 *lpcbData = lpcbDataW;
3194 if (lpbDataW) free(lpbDataW);
3195 if (lpszValueW) free(lpszValueW);
3196 return ret;
3200 /******************************************************************************
3201 * RegEnumValue16 [KERNEL.223]
3203 DWORD WINAPI RegEnumValue16( HKEY hkey, DWORD iValue, LPSTR lpszValue,
3204 LPDWORD lpcchValue, LPDWORD lpdReserved,
3205 LPDWORD lpdwType, LPBYTE lpbData,
3206 LPDWORD lpcbData )
3208 TRACE_(reg)("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",hkey,iValue,lpszValue,lpcchValue,
3209 lpdReserved,lpdwType,lpbData,lpcbData);
3210 return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, lpdReserved,
3211 lpdwType, lpbData, lpcbData );
3215 /******************************************************************************
3216 * RegCloseKey [SHELL.3] [KERNEL.220] [ADVAPI32.126]
3217 * Releases the handle of the specified key
3219 * PARAMS
3220 * hkey [I] Handle of key to close
3222 * RETURNS
3223 * Success: ERROR_SUCCESS
3224 * Failure: Error code
3226 DWORD WINAPI RegCloseKey( HKEY hkey )
3228 TRACE_(reg)("(%x)\n",hkey);
3230 /* The standard handles are allowed to succeed, even though they are not
3231 closed */
3232 if (is_standard_hkey(hkey))
3233 return ERROR_SUCCESS;
3235 return remove_handle(hkey);
3240 * Delete registry key
3242 * Callpath:
3243 * RegDeleteKey16 -> RegDeleteKey32A -> RegDeleteKey32W
3247 /******************************************************************************
3248 * RegDeleteKey32W [ADVAPI32.134]
3250 * PARAMS
3251 * hkey [I] Handle to open key
3252 * lpszSubKey [I] Name of subkey to delete
3254 * RETURNS
3255 * Success: ERROR_SUCCESS
3256 * Failure: Error code
3258 DWORD WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR lpszSubKey )
3260 LPKEYSTRUCT *lplpPrevKey,lpNextKey,lpxkey;
3261 LPWSTR *wps;
3262 int wpc,i;
3264 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszSubKey));
3266 lpNextKey = lookup_hkey(hkey);
3267 if (!lpNextKey)
3268 return ERROR_INVALID_HANDLE;
3270 /* Subkey param cannot be NULL */
3271 if (!lpszSubKey || !*lpszSubKey)
3272 return ERROR_BADKEY;
3274 /* We need to know the previous key in the hier. */
3275 split_keypath(lpszSubKey,&wps,&wpc);
3276 i = 0;
3277 lpxkey = lpNextKey;
3278 while (i<wpc-1) {
3279 lpxkey=lpNextKey->nextsub;
3280 while (lpxkey) {
3281 TRACE_(reg)(" Scanning [%s]\n",
3282 debugstr_w(lpxkey->keyname));
3283 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3284 break;
3285 lpxkey=lpxkey->next;
3287 if (!lpxkey) {
3288 FREE_KEY_PATH;
3289 TRACE_(reg)(" Not found.\n");
3290 /* not found is success */
3291 return ERROR_SUCCESS;
3293 i++;
3294 lpNextKey = lpxkey;
3296 lpxkey = lpNextKey->nextsub;
3297 lplpPrevKey = &(lpNextKey->nextsub);
3298 while (lpxkey) {
3299 TRACE_(reg)(" Scanning [%s]\n",
3300 debugstr_w(lpxkey->keyname));
3301 if (!lstrcmpiW(wps[i],lpxkey->keyname))
3302 break;
3303 lplpPrevKey = &(lpxkey->next);
3304 lpxkey = lpxkey->next;
3307 if (!lpxkey) {
3308 FREE_KEY_PATH;
3309 WARN_(reg)(" Not found.\n");
3310 return ERROR_FILE_NOT_FOUND;
3313 if (lpxkey->nextsub) {
3314 FREE_KEY_PATH;
3315 WARN_(reg)(" Not empty.\n");
3316 return ERROR_CANTWRITE;
3318 *lplpPrevKey = lpxkey->next;
3319 free(lpxkey->keyname);
3320 if (lpxkey->class)
3321 free(lpxkey->class);
3322 if (lpxkey->values)
3323 free(lpxkey->values);
3324 free(lpxkey);
3325 FREE_KEY_PATH;
3326 TRACE_(reg)(" Done.\n");
3327 return ERROR_SUCCESS;
3331 /******************************************************************************
3332 * RegDeleteKey32A [ADVAPI32.133]
3334 DWORD WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR lpszSubKey )
3336 LPWSTR lpszSubKeyW;
3337 DWORD ret;
3339 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3340 lpszSubKeyW = lpszSubKey?strdupA2W(lpszSubKey):NULL;
3341 ret = RegDeleteKeyW( hkey, lpszSubKeyW );
3342 if(lpszSubKeyW) free(lpszSubKeyW);
3343 return ret;
3347 /******************************************************************************
3348 * RegDeleteKey16 [SHELL.4] [KERNEL.219]
3350 DWORD WINAPI RegDeleteKey16( HKEY hkey, LPCSTR lpszSubKey )
3352 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszSubKey));
3353 return RegDeleteKeyA( hkey, lpszSubKey );
3358 * Delete registry value
3360 * Callpath:
3361 * RegDeleteValue16 -> RegDeleteValue32A -> RegDeleteValue32W
3365 /******************************************************************************
3366 * RegDeleteValue32W [ADVAPI32.136]
3368 * PARAMS
3369 * hkey [I]
3370 * lpszValue [I]
3372 * RETURNS
3374 DWORD WINAPI RegDeleteValueW( HKEY hkey, LPCWSTR lpszValue )
3376 DWORD i;
3377 LPKEYSTRUCT lpkey;
3378 LPKEYVALUE val;
3380 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_w(lpszValue));
3382 lpkey = lookup_hkey( hkey );
3383 if (!lpkey)
3384 return ERROR_INVALID_HANDLE;
3386 if (lpszValue) {
3387 for (i=0;i<lpkey->nrofvalues;i++)
3388 if ( lpkey->values[i].name &&
3389 !lstrcmpiW(lpkey->values[i].name,lpszValue)
3391 break;
3392 } else {
3393 for (i=0;i<lpkey->nrofvalues;i++)
3394 if (lpkey->values[i].name==NULL)
3395 break;
3398 if (i == lpkey->nrofvalues)
3399 return ERROR_FILE_NOT_FOUND;
3401 val = lpkey->values+i;
3402 if (val->name) free(val->name);
3403 if (val->data) free(val->data);
3404 memcpy(
3405 lpkey->values+i,
3406 lpkey->values+i+1,
3407 sizeof(KEYVALUE)*(lpkey->nrofvalues-i-1)
3409 lpkey->values = (LPKEYVALUE)xrealloc(
3410 lpkey->values,
3411 (lpkey->nrofvalues-1)*sizeof(KEYVALUE)
3413 lpkey->nrofvalues--;
3414 return ERROR_SUCCESS;
3418 /******************************************************************************
3419 * RegDeleteValue32A [ADVAPI32.135]
3421 DWORD WINAPI RegDeleteValueA( HKEY hkey, LPCSTR lpszValue )
3423 LPWSTR lpszValueW;
3424 DWORD ret;
3426 TRACE_(reg)("(%x,%s)\n",hkey,debugstr_a(lpszValue));
3427 lpszValueW = lpszValue?strdupA2W(lpszValue):NULL;
3428 ret = RegDeleteValueW( hkey, lpszValueW );
3429 if(lpszValueW) free(lpszValueW);
3430 return ret;
3434 /******************************************************************************
3435 * RegDeleteValue16 [KERNEL.222]
3437 DWORD WINAPI RegDeleteValue16( HKEY hkey, LPSTR lpszValue )
3439 TRACE_(reg)("(%x,%s)\n", hkey,debugstr_a(lpszValue));
3440 return RegDeleteValueA( hkey, lpszValue );
3444 /******************************************************************************
3445 * RegFlushKey [KERNEL.227] [ADVAPI32.143]
3446 * Writes key to registry
3448 * PARAMS
3449 * hkey [I] Handle of key to write
3451 * RETURNS
3452 * Success: ERROR_SUCCESS
3453 * Failure: Error code
3455 DWORD WINAPI RegFlushKey( HKEY hkey )
3457 LPKEYSTRUCT lpkey;
3458 BOOL ret;
3460 TRACE_(reg)("(%x)\n", hkey);
3462 lpkey = lookup_hkey( hkey );
3463 if (!lpkey)
3464 return ERROR_BADKEY;
3466 ERR_(reg)("What is the correct filename?\n");
3468 ret = _savereg( lpkey, "foo.bar", TRUE);
3470 if( ret ) {
3471 return ERROR_SUCCESS;
3472 } else
3473 return ERROR_UNKNOWN; /* FIXME */
3477 /* FIXME: lpcchXXXX ... is this counting in WCHARS or in BYTEs ?? */
3480 /******************************************************************************
3481 * RegQueryInfoKey32W [ADVAPI32.153]
3483 * PARAMS
3484 * hkey [I] Handle to key to query
3485 * lpszClass [O] Buffer for class string
3486 * lpcchClass [O] Size of class string buffer
3487 * lpdwReserved [I] Reserved
3488 * lpcSubKeys [I] Buffer for number of subkeys
3489 * lpcchMaxSubKey [O] Buffer for longest subkey name length
3490 * lpcchMaxClass [O] Buffer for longest class string length
3491 * lpcValues [O] Buffer for number of value entries
3492 * lpcchMaxValueName [O] Buffer for longest value name length
3493 * lpccbMaxValueData [O] Buffer for longest value data length
3494 * lpcbSecurityDescriptor [O] Buffer for security descriptor length
3495 * ft
3496 * - win95 allows lpszClass to be valid and lpcchClass to be NULL
3497 * - winnt returns ERROR_INVALID_PARAMETER if lpszClass is valid and
3498 * lpcchClass is NULL
3499 * - both allow lpszClass to be NULL and lpcchClass to be NULL
3500 * (it's hard to test validity, so test !NULL instead)
3502 DWORD WINAPI RegQueryInfoKeyW( HKEY hkey, LPWSTR lpszClass,
3503 LPDWORD lpcchClass, LPDWORD lpdwReserved,
3504 LPDWORD lpcSubKeys, LPDWORD lpcchMaxSubkey,
3505 LPDWORD lpcchMaxClass, LPDWORD lpcValues,
3506 LPDWORD lpcchMaxValueName,
3507 LPDWORD lpccbMaxValueData,
3508 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3510 LPKEYSTRUCT lpkey,lpxkey;
3511 int nrofkeys,maxsubkey,maxclass,maxvname,maxvdata;
3512 int i;
3514 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3515 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3516 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3517 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3519 lpkey = lookup_hkey(hkey);
3520 if (!lpkey)
3521 return ERROR_INVALID_HANDLE;
3522 if (lpszClass) {
3523 if (VERSION_GetVersion() == NT40 && lpcchClass == NULL) {
3524 return ERROR_INVALID_PARAMETER;
3526 /* either lpcchClass is valid or this is win95 and lpcchClass
3527 could be invalid */
3528 if (lpkey->class) {
3529 DWORD classLen = lstrlenW(lpkey->class);
3531 if (lpcchClass && classLen+1>*lpcchClass) {
3532 *lpcchClass=classLen+1;
3533 return ERROR_MORE_DATA;
3535 if (lpcchClass)
3536 *lpcchClass=classLen;
3537 memcpy(lpszClass,lpkey->class, classLen*2 + 2);
3538 } else {
3539 *lpszClass = 0;
3540 if (lpcchClass)
3541 *lpcchClass = 0;
3543 } else {
3544 if (lpcchClass)
3545 *lpcchClass = lstrlenW(lpkey->class);
3547 lpxkey=lpkey->nextsub;
3548 nrofkeys=maxsubkey=maxclass=maxvname=maxvdata=0;
3549 while (lpxkey) {
3550 nrofkeys++;
3551 if (lstrlenW(lpxkey->keyname)>maxsubkey)
3552 maxsubkey=lstrlenW(lpxkey->keyname);
3553 if (lpxkey->class && lstrlenW(lpxkey->class)>maxclass)
3554 maxclass=lstrlenW(lpxkey->class);
3555 lpxkey=lpxkey->next;
3557 for (i=0;i<lpkey->nrofvalues;i++) {
3558 LPKEYVALUE val=lpkey->values+i;
3560 if (val->name && lstrlenW(val->name)>maxvname)
3561 maxvname=lstrlenW(val->name);
3562 if (val->len>maxvdata)
3563 maxvdata=val->len;
3565 if (!maxclass) maxclass = 1;
3566 if (!maxvname) maxvname = 1;
3567 if (lpcValues)
3568 *lpcValues = lpkey->nrofvalues;
3569 if (lpcSubKeys)
3570 *lpcSubKeys = nrofkeys;
3571 if (lpcchMaxSubkey)
3572 *lpcchMaxSubkey = maxsubkey;
3573 if (lpcchMaxClass)
3574 *lpcchMaxClass = maxclass;
3575 if (lpcchMaxValueName)
3576 *lpcchMaxValueName= maxvname;
3577 if (lpccbMaxValueData)
3578 *lpccbMaxValueData= maxvdata;
3579 return ERROR_SUCCESS;
3583 /******************************************************************************
3584 * RegQueryInfoKey32A [ADVAPI32.152]
3586 DWORD WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR lpszClass, LPDWORD lpcchClass,
3587 LPDWORD lpdwReserved, LPDWORD lpcSubKeys,
3588 LPDWORD lpcchMaxSubkey, LPDWORD lpcchMaxClass,
3589 LPDWORD lpcValues, LPDWORD lpcchMaxValueName,
3590 LPDWORD lpccbMaxValueData,
3591 LPDWORD lpcbSecurityDescriptor, FILETIME *ft )
3593 LPWSTR lpszClassW = NULL;
3594 DWORD ret;
3596 TRACE_(reg)("(%x,%p,%ld,%p,%p,%p,%p,%p,%p,%p,%p)\n",
3597 hkey, lpszClass, lpcchClass?*lpcchClass:0,lpdwReserved,
3598 lpcSubKeys,lpcchMaxSubkey,lpcValues,lpcchMaxValueName,
3599 lpccbMaxValueData,lpcbSecurityDescriptor,ft
3601 if (lpszClass) {
3602 if (lpcchClass) {
3603 lpszClassW = (LPWSTR)xmalloc((*lpcchClass) * 2);
3604 } else if (VERSION_GetVersion() == WIN95) {
3605 /* win95 allows lpcchClass to be null */
3606 /* we don't know how big lpszClass is, would
3607 MAX_PATHNAME_LEN be the correct default? */
3608 lpszClassW = (LPWSTR)xmalloc(MAX_PATHNAME_LEN*2);
3611 } else
3612 lpszClassW = NULL;
3613 ret=RegQueryInfoKeyW(
3614 hkey,
3615 lpszClassW,
3616 lpcchClass,
3617 lpdwReserved,
3618 lpcSubKeys,
3619 lpcchMaxSubkey,
3620 lpcchMaxClass,
3621 lpcValues,
3622 lpcchMaxValueName,
3623 lpccbMaxValueData,
3624 lpcbSecurityDescriptor,
3627 if (ret==ERROR_SUCCESS && lpszClass)
3628 lstrcpyWtoA(lpszClass,lpszClassW);
3629 if (lpszClassW)
3630 free(lpszClassW);
3631 return ret;
3635 /******************************************************************************
3636 * RegConnectRegistry32W [ADVAPI32.128]
3638 * PARAMS
3639 * lpMachineName [I] Address of name of remote computer
3640 * hHey [I] Predefined registry handle
3641 * phkResult [I] Address of buffer for remote registry handle
3643 LONG WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey,
3644 LPHKEY phkResult )
3646 TRACE_(reg)("(%s,%x,%p): stub\n",debugstr_w(lpMachineName),hKey,phkResult);
3648 if (!lpMachineName || !*lpMachineName) {
3649 /* Use the local machine name */
3650 return RegOpenKey16( hKey, "", phkResult );
3653 FIXME_(reg)("Cannot connect to %s\n",debugstr_w(lpMachineName));
3654 return ERROR_BAD_NETPATH;
3658 /******************************************************************************
3659 * RegConnectRegistry32A [ADVAPI32.127]
3661 LONG WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, LPHKEY reskey )
3663 DWORD ret;
3664 LPWSTR machineW = strdupA2W(machine);
3665 ret = RegConnectRegistryW( machineW, hkey, reskey );
3666 free(machineW);
3667 return ret;
3671 /******************************************************************************
3672 * RegGetKeySecurity [ADVAPI32.144]
3673 * Retrieves a copy of security descriptor protecting the registry key
3675 * PARAMS
3676 * hkey [I] Open handle of key to set
3677 * SecurityInformation [I] Descriptor contents
3678 * pSecurityDescriptor [O] Address of descriptor for key
3679 * lpcbSecurityDescriptor [I/O] Address of size of buffer and description
3681 * RETURNS
3682 * Success: ERROR_SUCCESS
3683 * Failure: Error code
3685 LONG WINAPI RegGetKeySecurity( HKEY hkey,
3686 SECURITY_INFORMATION SecurityInformation,
3687 PSECURITY_DESCRIPTOR pSecurityDescriptor,
3688 LPDWORD lpcbSecurityDescriptor )
3690 LPKEYSTRUCT lpkey;
3692 TRACE_(reg)("(%x,%ld,%p,%ld)\n",hkey,SecurityInformation,pSecurityDescriptor,
3693 lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3695 lpkey = lookup_hkey( hkey );
3696 if (!lpkey)
3697 return ERROR_INVALID_HANDLE;
3699 /* FIXME: Check for valid SecurityInformation values */
3701 if (*lpcbSecurityDescriptor < sizeof(SECURITY_DESCRIPTOR))
3702 return ERROR_INSUFFICIENT_BUFFER;
3704 FIXME_(reg)("(%x,%ld,%p,%ld): stub\n",hkey,SecurityInformation,
3705 pSecurityDescriptor,lpcbSecurityDescriptor?*lpcbSecurityDescriptor:0);
3707 return ERROR_SUCCESS;
3711 /******************************************************************************
3712 * RegLoadKey32W [ADVAPI32.???]
3714 * PARAMS
3715 * hkey [I] Handle of open key
3716 * lpszSubKey [I] Address of name of subkey
3717 * lpszFile [I] Address of filename for registry information
3719 LONG WINAPI RegLoadKeyW( HKEY hkey, LPCWSTR lpszSubKey, LPCWSTR lpszFile )
3721 LPKEYSTRUCT lpkey;
3722 TRACE_(reg)("(%x,%s,%s)\n",hkey,debugstr_w(lpszSubKey),debugstr_w(lpszFile));
3724 /* Do this check before the hkey check */
3725 if (!lpszSubKey || !*lpszSubKey || !lpszFile || !*lpszFile)
3726 return ERROR_INVALID_PARAMETER;
3728 lpkey = lookup_hkey( hkey );
3729 if (!lpkey)
3730 return ERROR_INVALID_HANDLE;
3732 FIXME_(reg)("(%x,%s,%s): stub\n",hkey,debugstr_w(lpszSubKey),
3733 debugstr_w(lpszFile));
3735 return ERROR_SUCCESS;
3739 /******************************************************************************
3740 * RegLoadKey32A [ADVAPI32.???]
3742 LONG WINAPI RegLoadKeyA( HKEY hkey, LPCSTR lpszSubKey, LPCSTR lpszFile )
3744 LONG ret;
3745 LPWSTR lpszSubKeyW = strdupA2W(lpszSubKey);
3746 LPWSTR lpszFileW = strdupA2W(lpszFile);
3747 ret = RegLoadKeyW( hkey, lpszSubKeyW, lpszFileW );
3748 if(lpszFileW) free(lpszFileW);
3749 if(lpszSubKeyW) free(lpszSubKeyW);
3750 return ret;
3754 /******************************************************************************
3755 * RegNotifyChangeKeyValue [ADVAPI32.???]
3757 * PARAMS
3758 * hkey [I] Handle of key to watch
3759 * fWatchSubTree [I] Flag for subkey notification
3760 * fdwNotifyFilter [I] Changes to be reported
3761 * hEvent [I] Handle of signaled event
3762 * fAsync [I] Flag for asynchronous reporting
3764 LONG WINAPI RegNotifyChangeKeyValue( HKEY hkey, BOOL fWatchSubTree,
3765 DWORD fdwNotifyFilter, HANDLE hEvent,
3766 BOOL fAsync )
3768 LPKEYSTRUCT lpkey;
3769 TRACE_(reg)("(%x,%i,%ld,%x,%i)\n",hkey,fWatchSubTree,fdwNotifyFilter,
3770 hEvent,fAsync);
3772 lpkey = lookup_hkey( hkey );
3773 if (!lpkey)
3774 return ERROR_INVALID_HANDLE;
3776 FIXME_(reg)("(%x,%i,%ld,%x,%i): stub\n",hkey,fWatchSubTree,fdwNotifyFilter,
3777 hEvent,fAsync);
3779 return ERROR_SUCCESS;
3783 /******************************************************************************
3784 * RegUnLoadKey32W [ADVAPI32.173]
3786 * PARAMS
3787 * hkey [I] Handle of open key
3788 * lpSubKey [I] Address of name of subkey to unload
3790 LONG WINAPI RegUnLoadKeyW( HKEY hkey, LPCWSTR lpSubKey )
3792 FIXME_(reg)("(%x,%s): stub\n",hkey, debugstr_w(lpSubKey));
3793 return ERROR_SUCCESS;
3797 /******************************************************************************
3798 * RegUnLoadKey32A [ADVAPI32.172]
3800 LONG WINAPI RegUnLoadKeyA( HKEY hkey, LPCSTR lpSubKey )
3802 LONG ret;
3803 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3804 ret = RegUnLoadKeyW( hkey, lpSubKeyW );
3805 if(lpSubKeyW) free(lpSubKeyW);
3806 return ret;
3810 /******************************************************************************
3811 * RegSetKeySecurity [ADVAPI32.167]
3813 * PARAMS
3814 * hkey [I] Open handle of key to set
3815 * SecurityInfo [I] Descriptor contents
3816 * pSecurityDesc [I] Address of descriptor for key
3818 LONG WINAPI RegSetKeySecurity( HKEY hkey, SECURITY_INFORMATION SecurityInfo,
3819 PSECURITY_DESCRIPTOR pSecurityDesc )
3821 LPKEYSTRUCT lpkey;
3823 TRACE_(reg)("(%x,%ld,%p)\n",hkey,SecurityInfo,pSecurityDesc);
3825 /* It seems to perform this check before the hkey check */
3826 if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
3827 (SecurityInfo & GROUP_SECURITY_INFORMATION) ||
3828 (SecurityInfo & DACL_SECURITY_INFORMATION) ||
3829 (SecurityInfo & SACL_SECURITY_INFORMATION)) {
3830 /* Param OK */
3831 } else
3832 return ERROR_INVALID_PARAMETER;
3834 if (!pSecurityDesc)
3835 return ERROR_INVALID_PARAMETER;
3837 lpkey = lookup_hkey( hkey );
3838 if (!lpkey)
3839 return ERROR_INVALID_HANDLE;
3841 FIXME_(reg)(":(%x,%ld,%p): stub\n",hkey,SecurityInfo,pSecurityDesc);
3843 return ERROR_SUCCESS;
3847 /******************************************************************************
3848 * RegSaveKey32W [ADVAPI32.166]
3850 * PARAMS
3851 * hkey [I] Handle of key where save begins
3852 * lpFile [I] Address of filename to save to
3853 * sa [I] Address of security structure
3855 LONG WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR lpFile,
3856 LPSECURITY_ATTRIBUTES sa )
3858 LPKEYSTRUCT lpkey;
3860 TRACE_(reg)("(%x,%s,%p)\n", hkey, debugstr_w(lpFile), sa);
3862 /* It appears to do this check before the hkey check */
3863 if (!lpFile || !*lpFile)
3864 return ERROR_INVALID_PARAMETER;
3866 lpkey = lookup_hkey( hkey );
3867 if (!lpkey)
3868 return ERROR_INVALID_HANDLE;
3870 FIXME_(reg)("(%x,%s,%p): stub\n", hkey, debugstr_w(lpFile), sa);
3872 return ERROR_SUCCESS;
3876 /******************************************************************************
3877 * RegSaveKey32A [ADVAPI32.165]
3879 LONG WINAPI RegSaveKeyA( HKEY hkey, LPCSTR lpFile,
3880 LPSECURITY_ATTRIBUTES sa )
3882 LONG ret;
3883 LPWSTR lpFileW = strdupA2W(lpFile);
3884 ret = RegSaveKeyW( hkey, lpFileW, sa );
3885 free(lpFileW);
3886 return ret;
3890 /******************************************************************************
3891 * RegRestoreKey32W [ADVAPI32.164]
3893 * PARAMS
3894 * hkey [I] Handle of key where restore begins
3895 * lpFile [I] Address of filename containing saved tree
3896 * dwFlags [I] Optional flags
3898 LONG WINAPI RegRestoreKeyW( HKEY hkey, LPCWSTR lpFile, DWORD dwFlags )
3900 LPKEYSTRUCT lpkey;
3902 TRACE_(reg)("(%x,%s,%ld)\n",hkey,debugstr_w(lpFile),dwFlags);
3904 /* It seems to do this check before the hkey check */
3905 if (!lpFile || !*lpFile)
3906 return ERROR_INVALID_PARAMETER;
3908 lpkey = lookup_hkey( hkey );
3909 if (!lpkey)
3910 return ERROR_INVALID_HANDLE;
3912 FIXME_(reg)("(%x,%s,%ld): stub\n",hkey,debugstr_w(lpFile),dwFlags);
3914 /* Check for file existence */
3916 return ERROR_SUCCESS;
3920 /******************************************************************************
3921 * RegRestoreKey32A [ADVAPI32.163]
3923 LONG WINAPI RegRestoreKeyA( HKEY hkey, LPCSTR lpFile, DWORD dwFlags )
3925 LONG ret;
3926 LPWSTR lpFileW = strdupA2W(lpFile);
3927 ret = RegRestoreKeyW( hkey, lpFileW, dwFlags );
3928 if(lpFileW) free(lpFileW);
3929 return ret;
3933 /******************************************************************************
3934 * RegReplaceKey32W [ADVAPI32.162]
3936 * PARAMS
3937 * hkey [I] Handle of open key
3938 * lpSubKey [I] Address of name of subkey
3939 * lpNewFile [I] Address of filename for file with new data
3940 * lpOldFile [I] Address of filename for backup file
3942 LONG WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile,
3943 LPCWSTR lpOldFile )
3945 LPKEYSTRUCT lpkey;
3947 TRACE_(reg)("(%x,%s,%s,%s)\n",hkey,debugstr_w(lpSubKey),
3948 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3950 lpkey = lookup_hkey( hkey );
3951 if (!lpkey)
3952 return ERROR_INVALID_HANDLE;
3954 FIXME_(reg)("(%x,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey),
3955 debugstr_w(lpNewFile),debugstr_w(lpOldFile));
3957 return ERROR_SUCCESS;
3961 /******************************************************************************
3962 * RegReplaceKey32A [ADVAPI32.161]
3964 LONG WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile,
3965 LPCSTR lpOldFile )
3967 LONG ret;
3968 LPWSTR lpSubKeyW = strdupA2W(lpSubKey);
3969 LPWSTR lpNewFileW = strdupA2W(lpNewFile);
3970 LPWSTR lpOldFileW = strdupA2W(lpOldFile);
3971 ret = RegReplaceKeyW( hkey, lpSubKeyW, lpNewFileW, lpOldFileW );
3972 free(lpOldFileW);
3973 free(lpNewFileW);
3974 free(lpSubKeyW);
3975 return ret;